Skip to content

Hosted→vendored takeover leaves trustLockfile: true in pnpm-workspace.yaml, and vendor --revert never removes it #401

Description

[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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions