Fix vendor -g rewiring the cwd project (#498) - #499
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Run inside a project, `vendor -g` vendored the manifest's records into that project and `vendor --revert -g` unwound the project's vendoring. These tests pin that every form of `vendor` under --global, --global-prefix, SOCKET_GLOBAL and SOCKET_GLOBAL_PREFIX leaves the project's lockfile, artifacts and ledger byte-identical. Assisted-by: Claude Code:claude-opus-5-5
A global run never targets the project it starts in, but the standalone `vendor` command ignored global scope: `vendor --revert -g` silently unpatched a vendored project on its next frozen install, and `vendor -g` rewired the project's lockfile. Every form of `vendor` is now the same exit-2 usage error `scan`/`get --mode vendored -g` give, raised before the project is read or locked. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0e617ff. Configure here.
|
Burn-down agent: ready for review at
Generated by Claude Code |
|
Reviewed No blocking findings. The global-scope guard precedes check, project discovery, manifest access, and locking, covers flags and environment-derived scope, and leaves normal project vendoring behavior intact. Validation: Ran |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #498
Summary
vendorunder--global/--global-prefix(orSOCKET_GLOBAL/SOCKET_GLOBAL_PREFIX) is now a usage error: exit 2, humanError: --global cannot be used with vendor[ --revert| --check]: global installs have no project lockfile to …, JSON{status: "error", error: {code: "global_scope_unsupported", message}}. This matchesscan/get --mode vendored -g. The check runs before the project is read or locked.Root cause
#446 made
get,scan,apply,rollbackandremoveleave the cwd project's hosted pins and vendor ledger alone under global scope, usingcommands::project_state_in_scope/global_mode_conflict. The standalonevendorcommand (commands/vendor.rs) never consulted either one. Only its manifest-less eject path checkedis_global(). As a result:vendor --revert -greverted the project's vendoring and exited 0, so the next frozen install was silently unpatched.vendor -gvendored the manifest's records into the project and rewired its lockfile, including a hosted→vendored takeover.The bug isn't specific to vlt. The reporter's npm control reproduces it too, because the code is package-manager independent.
Design choice
The issue allowed either "refuse" or "no-op on the project". I chose refuse, for three reasons:
vendorcould legitimately act on.--mode vendored -gusage error.vendor --check -gis refused for the same reason: it would report on the project, which isn't the global run's target. The now-unreachableis_global()guard on the eject path was removed.Changes
commands/vendor.rs:global_scope_conflictplus an early exit-2 refusal inrun.commands/mod.rs: the sharedglobal_scope_flaghelper, so both usage errors name the flag identically.CLI_CONTRACT.md("Global scope never touches the project's state") andCHANGELOG.md.Test evidence
New tests in
crates/socket-patch-cli/tests/global_scope_project_state.rs(section 5) cover--global,-g,--global-prefix,SOCKET_GLOBAL=1andSOCKET_GLOBAL_PREFIX, each in human and--jsonmode:global_vendor_revert_leaves_vendored_project_state: the lock, artifact, ledger and installed copy stay byte-identical. A control shows a project-scope revert still unwinds.global_vendor_does_not_vendor_into_the_project: the lock and manifest are unchanged and no.socket/vendoris created. A control shows project-scope vendoring still works.global_vendor_check_is_refusedRed → green:
left: 0, right: 2. The command exited 0 and touched the project.cargo test -p socket-patch-cli --all-features --test global_scope_project_statepassed 29/29.Local checks:
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test --workspace --all-features --no-fail-fast: all green. Twelve tests across four targets (covgap_commands_vendor,in_process_redirect,repair, core--lib) fail only because this sandbox runs as uid 0, where theirchmod 0o555write-failure injection can't block writes. Re-run as an unprivileged user, all four targets pass in full (core lib 4719/4719, repair 116/116, in_process_redirect 104/104, covgap_commands_vendor 3/3 of the affected tests). None of them touch this change.cargo fmt --all -- --checkis already red onmainacross ~127 unrelated files (CI doesn't run it). The hunks in this PR are rustfmt-formatted, and I left the rest of the tree alone so the diff stays reviewable.npm/,pypi/andgem/only dispatch to the binary.Per-issue checklist
vendor -gandvendor --revert -gstill rewire the current project: on vlt,--revert -gsilently unpatches a vendored project (the #446 fix skipped vendor.rs) #498vendor --revert -gkeeps the project's vendoring →global_vendor_revert_leaves_vendored_project_statevendor -gandvendor --revert -gstill rewire the current project: on vlt,--revert -gsilently unpatches a vendored project (the #446 fix skipped vendor.rs) #498vendor -gdoesn't vendor into the project →global_vendor_does_not_vendor_into_the_projectvendor -gandvendor --revert -gstill rewire the current project: on vlt,--revert -gsilently unpatches a vendored project (the #446 fix skipped vendor.rs) #498SOCKET_GLOBAL/SOCKET_GLOBAL_PREFIXbehave like the flags → covered by every test aboveFollow-ups
vendor -gandvendor --revert -gstill rewire the current project: on vlt,--revert -gsilently unpatches a vendored project (the #446 fix skipped vendor.rs) #498. Related but separate: Since #446,scan -g --mode agentthenrollback -gfrom a vendored NuGet project reverts the project's patched package in the shared global packages folder; the locked restore stays "up-to-date" and VEX keeps attesting #489 (a NuGet global packages folder shared with the project after Fix -g touching the cwd project's state (#436, #445) #446) has a different root cause.Note
Low Risk
CLI guard only; refuses a mis-scoped command before writes. No change to project-scoped vendoring behavior.
Overview
vendorwith global scope is now rejected before any project read or lock, matchingscan/get --mode vendored. Exit code 2, JSON codeglobal_scope_unsupported, with messages that name--globalvs--global-prefix(or env equivalents) and the subform (vendor,vendor --revert,vendor --check).Previously,
vendor -gcould wire vendoring into the cwd project andvendor --revert -gcould unwind the project’s vendoring while exiting 0—becausevendornever usedproject_state_in_scopelike the other commands after #446.A shared
global_scope_flaghelper formats usage errors consistently with scan/get. The oldis_global()skip on the hosted eject path is removed since global runs fail upfront. CLI contract, changelog, and integration tests (all global scope spellings, human + JSON) assert the project lock, manifest, and vendor tree stay untouched.Reviewed by Cursor Bugbot for commit 0e617ff. Configure here.
Generated by Claude Code