Repository navigation
Agent-mode cargo with HOME unset finds no registry cache, reports the crate as lockfile-only and exits 0, while cargo builds the unpatched copy from the passwd home's ~/.cargo #1135
Description
[agent] Found by the scheduled Cargo bug-hunt routine (ledger #315).
Summary
When HOME is unset and CARGO_HOME is unset, cargo still finds its home: the home crate falls back to the passwd entry (getpwuid(getuid())->pw_dir), so it builds from /root/.cargo (or /home/<user>/.cargo). socket-patch's cargo crawler resolves CARGO_HOME, then utils::fs::home_dir(), which since #1038 reads only HOME / USERPROFILE and returns None otherwise, so it probes no registry at all. An agent scan --mode agent then sees the patched crate only in Cargo.lock (lockfileOnlyPackages: 1), patches nothing, and exits 0 with status: "success". The next cargo build compiles the unpatched registry copy.
Impact
- A CI job, systemd unit,
env -iscript or container entrypoint that runs withoutHOMEgets a green socket-patch step and an unpatched build. - No warning names the reason: the output reads like a lockfile-only checkout (the Cargo apply on a cold or pruned registry cache now exits 0 as "lockfile-only", then the next cargo build downloads and compiles the unpatched crate (regression from #555) #616 shape), although the crate is extracted and cargo will build it.
vexexits 2 in the same environment, so the gap shows up only if someone runs vex too.
Repro (Linux, cargo 1.93.1, root user, passwd home /root)
mkdir -p proj/src && cd proj
printf '[package]\nname = "consumer"\nversion = "0.1.0"\nedition = "2018"\n\n[dependencies]\ncfg-if = "1.0.4"\n' > Cargo.toml
echo 'fn main() {}' > src/main.rs
cargo generate-lockfile && cargo update -p cfg-if --precise 1.0.4 && cargo fetch
env -u HOME -u CARGO_HOME cargo metadata --format-version 1 | jq -r '.packages[] | select(.name=="cfg-if").manifest_path'
# /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cfg-if-1.0.4/Cargo.toml <- cargo still uses ~/.cargo
# patch API stand-in serving one free patch for pkg:cargo/cfg-if@1.0.4 (appends `pub fn socket_patched()` to src/lib.rs)
env -u HOME -u CARGO_HOME socket-patch scan --mode agent --json --yes --api-url $MOCK --org test-org --api-token fake
# status: success, scannedPackages: 1, lockfileOnlyPackages: 1, totalPatches: 1, events: [], exit 0
grep -c socket_patched /root/.cargo/registry/src/*/cfg-if-1.0.4/src/lib.rs # 0: not patched
# control, same project, HOME=/root:
socket-patch scan --mode agent --json --yes ... # scannedPackages: 233, lockfileOnlyPackages: 0, the copy is patchedIt reproduced on two consecutive runs (identical output), and the control with HOME set patches the copy every time.
Expected vs actual
- Expected: agent mode patches "the crate wherever the crawler finds it" (docs/ecosystems.md, Cargo row) in the registry cache cargo actually builds from. When
CARGO_HOMEis unset, that's the default cargo home,<home>/.cargo, with<home>resolved the way cargo resolves it (HOME, then the passwd entry on Unix).utils::fs::home_dir's own doc already lists readers that "deliberately follow another tool's own rule" (Gradle's passwd-vs-$HOMEcheck ingradle/home.rs), so cargo needs the same treatment. Failing that, the run should at least say that no cargo home was found, instead of passing as lockfile-only. - Actual: no home, so no registry probe, the crate is reported lockfile-only,
status: success, exit 0, and the build is unpatched.
Matrix
| OS | cargo | HOME | CARGO_HOME | Reproduces |
|---|---|---|---|---|
| Linux | 1.93.1 | unset | unset | yes (×2) |
| Linux | 1.93.1 | /root |
unset | no (control) |
| Linux | 1.93.1 | unset | set | no (the crawler uses CARGO_HOME) |
| macOS | any | unset | unset | untested (same code path; cargo's passwd fallback is the same) |
| Windows | any | USERPROFILE unset |
unset | untested (cargo's home crate uses the known-folder API there) |
Tested on main 9472be4 (CLI 4.0.0). Not a regression from #1038: before it, home_dir fell back to the CWD-relative path ~ (that commit's message), which also found no registry. #1038 just made "no home" explicit.
Suspect code
crates/socket-patch-core/src/crawlers/cargo_crawler.rs:355-360(CargoCrawler::cargo_home):CARGO_HOME, elseutils::fs::home_dir().map(|h| h.join(".cargo")), with no passwd fallback.crates/socket-patch-core/src/utils/fs.rs:387-398(home_dir/home_from_env):HOME/USERPROFILEonly.- The same
CARGO_HOME-or-home_dirrule is incrates/socket-patch-core/src/vendor/cargo_config.rs:156-158(read_config_chain). WithHOMEunset, the$CARGO_HOME/config.tomlthat cargo still reads (a user[patch]/[source]) is skipped by the vendored and hosted config-chain checks too. I didn't drive that path end to end.
Related: #616 (the same lockfile-only exit 0 when the cache is genuinely cold). A fix there that makes a lockfile-only cargo patch loud would surface this case, but it still wouldn't patch the copy cargo builds.
Activity
cargo: run 16 ledger (#1135 filed, #864 verified, #339 commented)
mikolalysenko commentedon Oct 8, 2026
[agent] Triage: priority:p2 (Cargo). Confirmed on main 3b4ac84:
CargoCrawler::cargo_home(crates/socket-patch-core/src/crawlers/cargo_crawler.rs:355) falls back only toutils::fs::home_dir(), which readsHOME/USERPROFILEand has no passwd fallback, so with bothHOMEandCARGO_HOMEunset no registry is probed. Related to #616 (lockfile-only exit 0 on a cold cache) but a different cause, so not a duplicate. No open PR covers it.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
[agent] Cargo bug-hunt run 17 (ledger #315), main
4aec9d7, Linux, cargo 1.93.1.success,lockfileOnlyPackages: 1, applied 0.env -u HOME -u CARGO_HOME socket-patch scan -g -e cargoprints "No global packages found." and exits 0 (--json:scannedPackages: 0, no warning). WithHOME=/rootthe same command crawls 223 crates from the passwd home's~/.cargo, the cache cargo itself uses. The root cause is the same:CargoCrawler::cargo_home()returnsNonewhenhome_dir()has noHOME/USERPROFILE, and nothing reports it. A global run should at least warn that no cargo home could be resolved.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
v5 triage: P3, not a release blocker. HOME and CARGO_HOME both unset is an unusual launch environment. P3 rather than a release gate for ordinary Cargo lockfiles.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.