[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
On a pnpm 9.0-lock project, scan --mode hosted adds trustLockfile: true to pnpm-workspace.yaml, ledger kind redirect_pnpm_workspace_trust. When the project is then moved to vendored mode (vendor or scan --mode vendored), the takeover reverts the hosted lock entry and drops its redirect record, but leaves the trust line and its ledger edit in place. The redirect ledger ends up holding one redirect_pnpm_workspace_trust edit and no records. A later vendor --revert removes the vendored wiring and leaves the project with no Socket wiring at all, but trustLockfile: true is still in pnpm-workspace.yaml.
npm's equivalent setting is handled. revert_redirect_purl unwinds the .npmrc allow-remote=all auto-config "LAST ONE OUT" in the same transaction, and the code comment says it does so precisely so that "the vendored takeover then leave[s] no loosened install policy behind". The pnpm trust edit gets no such treatment.
Impact
trustLockfile: true disables pnpm ≥11's registry re-verification for the whole lockfile (docs/ecosystems.md: "This skips registry re-verification for the whole lock"). It's only justified while hosted URLs are in the lock. After takeover, and especially after vendor --revert, the project silently keeps a weakened supply-chain policy that no current Socket wiring needs, and no command warns about it. Only a later whole-ledger rollback removes it, and a user who has already reverted the vendored state has no reason to run one.
Repro (pnpm 11 or 12, root 9.0 lock; patch API mocked as in e2e_redirect_pnpm_build.rs, manifest and blobs staged for vendor)
echo '{"name":"proj","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
printf "packages:\n - '.'\n" > pnpm-workspace.yaml
pnpm install
socket-patch scan --mode hosted --yes --json --api-url $MOCK --org test-org --api-token fake
# pnpm-workspace.yaml gains `trustLockfile: true`
socket-patch vendor --yes --json --offline # hosted -> vendored takeover, exit 0, applied
cat pnpm-workspace.yaml # packages / trustLockfile: true / overrides: ...
grep -c 127.0.0.1:18731 pnpm-lock.yaml # 0: no hosted URL left
jq '.edits,.records' .socket/vendor/redirect-state.json
# [{"kind":"redirect_pnpm_workspace_trust","action":"added",...}] {}
socket-patch vendor --revert --yes --json --offline # exit 0
cat pnpm-workspace.yaml
# packages:
# - '.'
# trustLockfile: true <- still there, nothing needs it
scan --mode vendored as the takeover driver behaves the same.
Expected vs actual
- Expected: the takeover leaves the project "FULLY in vendored mode" (module doc,
crates/socket-patch-core/src/patch/redirect/takeover.rs:1-5), and superseded redirect edits don't "survive forever" as a stale ledger (same doc). The npm .npmrc setting already gets this last-one-out unwind. When the takeover drops the last pnpm hosted record, the redirect_pnpm_workspace_trust edit should be unwound in the same transaction (its inverse Inverse::PnpmTrust already exists in replay.rs). A user-set trustLockfile must stay untouched.
- Actual: the trust line and an orphan ledger edit survive the takeover and
vendor --revert.
OS × version (Linux, Node 22)
| pnpm |
hosted → vendor |
hosted → scan --mode vendored |
then vendor --revert |
control: scoped rollback <purl> after hosted only |
| 11.27.0 |
trust left (3 runs) |
trust left (2 runs) |
trust left |
restored byte-exact (2 runs) |
| 12.8.1 |
trust left |
not run |
trust left |
restored byte-exact (2 runs) |
Fresh frozen installs stay patched at every step, so nothing visibly breaks; the defect is the leftover policy loosening. Tested on main f6b7fb9, and released 4.0.0 behaves the same (pnpm 11.27.0). The logic is OS-independent string surgery, so macOS and Windows weren't probed.
Suspect code
crates/socket-patch-core/src/patch/redirect/takeover.rs:1069-1096: the "LAST ONE OUT" block handles only .npmrc (npmrc_unwind_due, crates/socket-patch-core/src/patch/redirect/npmrc.rs:748). There's no pnpm counterpart for redirect_pnpm_workspace_trust when the last pnpm-lock record is dropped.
crates/socket-patch-core/src/patch/redirect/replay.rs:131 already maps the kind to Inverse::PnpmTrust for whole-ledger replay, which is why bare rollback does clean it up.
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
On a pnpm 9.0-lock project,
scan --mode hostedaddstrustLockfile: truetopnpm-workspace.yaml, ledger kindredirect_pnpm_workspace_trust. When the project is then moved to vendored mode (vendororscan --mode vendored), the takeover reverts the hosted lock entry and drops its redirect record, but leaves the trust line and its ledger edit in place. The redirect ledger ends up holding oneredirect_pnpm_workspace_trustedit and no records. A latervendor --revertremoves the vendored wiring and leaves the project with no Socket wiring at all, buttrustLockfile: trueis still inpnpm-workspace.yaml.npm's equivalent setting is handled.
revert_redirect_purlunwinds the.npmrcallow-remote=allauto-config "LAST ONE OUT" in the same transaction, and the code comment says it does so precisely so that "the vendored takeover then leave[s] no loosened install policy behind". The pnpm trust edit gets no such treatment.Impact
trustLockfile: truedisables pnpm ≥11's registry re-verification for the whole lockfile (docs/ecosystems.md: "This skips registry re-verification for the whole lock"). It's only justified while hosted URLs are in the lock. After takeover, and especially aftervendor --revert, the project silently keeps a weakened supply-chain policy that no current Socket wiring needs, and no command warns about it. Only a later whole-ledgerrollbackremoves it, and a user who has already reverted the vendored state has no reason to run one.Repro (pnpm 11 or 12, root 9.0 lock; patch API mocked as in
e2e_redirect_pnpm_build.rs, manifest and blobs staged for vendor)scan --mode vendoredas the takeover driver behaves the same.Expected vs actual
crates/socket-patch-core/src/patch/redirect/takeover.rs:1-5), and superseded redirect edits don't "survive forever" as a stale ledger (same doc). The npm.npmrcsetting already gets this last-one-out unwind. When the takeover drops the last pnpm hosted record, theredirect_pnpm_workspace_trustedit should be unwound in the same transaction (its inverseInverse::PnpmTrustalready exists inreplay.rs). A user-settrustLockfilemust stay untouched.vendor --revert.OS × version (Linux, Node 22)
vendorscan --mode vendoredvendor --revertrollback <purl>after hosted onlyFresh frozen installs stay patched at every step, so nothing visibly breaks; the defect is the leftover policy loosening. Tested on main
f6b7fb9, and released 4.0.0 behaves the same (pnpm 11.27.0). The logic is OS-independent string surgery, so macOS and Windows weren't probed.Suspect code
crates/socket-patch-core/src/patch/redirect/takeover.rs:1069-1096: the "LAST ONE OUT" block handles only.npmrc(npmrc_unwind_due,crates/socket-patch-core/src/patch/redirect/npmrc.rs:748). There's no pnpm counterpart forredirect_pnpm_workspace_trustwhen the last pnpm-lock record is dropped.crates/socket-patch-core/src/patch/redirect/replay.rs:131already maps the kind toInverse::PnpmTrustfor whole-ledger replay, which is why barerollbackdoes clean it up.