Repository navigation
Hosted scan with pnpm gitBranchLockfile pins the stale pnpm-lock.yaml and reports success, while pnpm installs unpatched bytes from pnpm-lock.<branch>.yaml #556
Description
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
pnpm's gitBranchLockfile setting (git-branch-lockfile=true in .npmrc on pnpm ≤10, gitBranchLockfile: true in pnpm-workspace.yaml) makes pnpm read and write pnpm-lock.<branch>.yaml instead of pnpm-lock.yaml. Hosted mode only looks at files named exactly pnpm-lock.yaml / shrinkwrap.yaml. That causes two failures:
- Both locks present (the usual case:
pnpm-lock.yamlcommitted on main, and a branch lock written once the feature branch changes deps):scan --mode hostedpins the stalepnpm-lock.yamland reportsstatus: success, redirected: 1. pnpm installs frompnpm-lock.feature.yaml, which still points at the registry, so a freshpnpm install --frozen-lockfilesilently installs the unpatched upstream bytes.vexhonestly declines (not_applied), so it's the only signal. - Only a branch lock present: the scan exits 0 with
redirected: 0and the warningredirect_pnpm_no_lockfile, whose remedy ("runpnpm installto generate one") cannot work, because pnpm will just rewrite the branch lock.
Impact
On a feature branch with this setting, the user is told the patch is pinned (and the pin lands in a file they will commit), but CI and fresh checkouts on that branch install the vulnerable package. When the branch merges, pnpm's mergeGitBranchLockfiles flow can carry the unpinned branch entry over the pinned main one.
Repro (Linux, pnpm 12.8.1; local mock of the patch API serving a patched is-number@7.0.0 tarball)
mkdir app && cd app && git init -q -b main
echo '{"name":"app","version":"1.0.0","dependencies":{"is-number":"7.0.0"}}' > package.json
printf "packages:\n - '.'\n" > pnpm-workspace.yaml; echo node_modules > .gitignore
pnpm install && git add -A && git commit -qm init && git checkout -qb feature
printf "gitBranchLockfile: true\n" >> pnpm-workspace.yaml # pnpm 10: echo git-branch-lockfile=true > .npmrc
pnpm add is-odd@3.0.1 # writes pnpm-lock.feature.yaml; pnpm-lock.yaml stays as on main
socket-patch scan --mode hosted --json --yes --api-url $MOCK --org test-org --api-token fake
# -> status success, redirected 1, rewrittenFiles [pnpm-lock.yaml, pnpm-workspace.yaml]
grep -c $MOCK pnpm-lock.yaml pnpm-lock.feature.yaml # 1 / 0
# fresh checkout, empty store:
rm -rf node_modules && pnpm install --frozen-lockfile --store-dir $(mktemp -d)
head -1 node_modules/is-number/index.js # "/*!" (upstream), not the patch marker
socket-patch vex --output v.json # "omitting pkg:npm/is-number@7.0.0 ... (not_applied)"Only-branch-lock variant: git init -b feature, enable the setting before the first pnpm install. Hosted scan then gives redirected 0 plus redirect_pnpm_no_lockfile.
Expected vs actual
- Expected: CLI_CONTRACT and docs/ecosystems.md say hosted mode pins the lock the package manager actually installs from, or refuses loudly when it can't. So hosted mode should either rewrite
pnpm-lock.<current-branch>.yaml(and leave the stale lock alone, or pin both), or refuse with a dedicated warning code that names the setting. - Actual: it pins a file pnpm ignores on this branch, and reports success. With only the branch lock, it gives a misleading "no lockfile" remedy.
Matrix (Linux; each cell run twice)
| pnpm | branch lock written | both-locks case | only-branch-lock case |
|---|---|---|---|
| 9.15.9 | no (this fixture's .npmrc setting produced no branch lock) |
n/a: pinned pnpm-lock.yaml is the one used, patched |
n/a |
| 10.34.5 | yes | fail: success, fresh frozen install unpatched | not run |
| 11.28.3 | yes | fail | not run |
| 12.8.1 | yes | fail | fail (misleading redirect_pnpm_no_lockfile) |
macOS and Windows weren't tested (no probe branch this run); the logic is filename-based, so they're likely the same. Vendored mode with this setting wasn't tested.
Suspect code
crates/socket-patch-core/src/formats/pnpm/hosted.rs:180–lock_keysmatches onlypnpm-lock.yaml/shrinkwrap.yaml.crates/socket-patch-core/src/formats/registry.rs:72– the hosted read set lists onlypnpm-lock.yaml.crates/socket-patch-core/src/patch/redirect/mod.rs:806–redirect_pnpm_no_lockfilefires without consideringpnpm-lock.*.yaml.
Tested on main 61cfb9b (CLI 4.0.0).
Activity
mikolalysenko commentedon Oct 2, 2026
[agent] Triage: priority:p1 (pnpm). Hosted lock discovery only considers
pnpm-lock.yaml/shrinkwrap.yamland never consults pnpm'sgitBranchLockfilesetting, so the pin lands in a lock pnpm ignores on this branch. Distinct root cause from other open pnpm issues; no open PR covers it.Generated by Claude Code
mikolalysenko commentedon Oct 2, 2026
[agent] More from the pnpm bug-hunt routine (ledger #303): vendored mode has the same lock-selection gap. Tested on main
203e092, Linux, pnpm 10.34.5 / 11.28.3 / 12.8.1, and it reproduced 2/2 on each.Setup:
maincommitspnpm-lock.yaml. Onfeature,gitBranchLockfile: trueis added topnpm-workspace.yamland an unpatched dep (ms@2.1.3) is added, so pnpm writespnpm-lock.feature.yaml.Running
scan --mode vendored --json --yesonfeature:status: success(applied+vendor_prebuilt_downloaded) and no warnings.file:.socket/vendor/npm/<uuid>/is-number-7.0.0.tgzoverride intopackage.jsonpnpm.overridesandpnpm-workspace.yamloverrides:, and rewires the stalepnpm-lock.yaml.pnpm-lock.feature.yaml, the lock pnpm actually uses on this branch, untouched (0 Socket references).Result on a fresh checkout of the branch:
pnpm install --frozen-lockfilepnpm install(non-frozen)So a "successful" vendor breaks every frozen install (CI) on the branch. Vendored mode needs to select the active branch lock as well. Alternatively, while
gitBranchLockfileis on, both modes could refuse with a diagnostic that names it.Separately, when the branch lock contains a patched dep that
pnpm-lock.yamllacks, vendored fails loudly ("pnpm-lock.yaml has no packages entry for left-pad@1.3.0",partial_failure). That message also points at the wrong lock.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Claiming this issue as part of the pnpm open-issue sweep in draft PR #1007. Branch: agent/fix-pnpm-open-issues. Claim-ID: 2026-10-07T12:44:29Z-pnpm07
Fix pnpm gitBranchLockfile pins landing in a stale lock (#556)
Refuse member pnpm branch locks under per-member locks (#556 review)
Merge branch 'pnpm-fix/b3-lockselect' into agent/fix-pnpm-open-issues
mikolalysenko commentedon Oct 7, 2026
[agent] PR #1007 fixes this issue. It has a regression test that fails on
main, CI is fully green (552 checks) and it's ready for review. The issue will close when #1007 merges. The PR description's table gives the root cause, the fix and the test for each issue.Merge main into agent/fix-pnpm-open-issues