Repository navigation
Hosted pnpm rollback/remove adds registry tarball: URLs the lock never had when lockfileIncludeTarballUrl sits in a settings file the installed pnpm ignores (workspace file on pnpm 9, .npmrc on pnpm 11/12) #902
Description
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
The #557 fix (#818, e889d6d) decides whether a restored pnpm-lock.yaml resolution gets a tarball: URL from PnpmTarballPolicy. That policy reads lockfileIncludeTarballUrl from pnpm-workspace.yaml, falling back to lockfile-include-tarball-url in .npmrc, without checking which of those files the project's pnpm actually reads:
- pnpm 9 ignores settings in
pnpm-workspace.yaml, solockfileIncludeTarballUrl: truethere has no effect, and the lock pnpm 9 writes has notarball:fields. - pnpm 11 and 12 ignore
lockfile-include-tarball-urlin.npmrc. Again, the lock has notarball:fields.
In both cases hosted rollback (and remove) treats the setting as active, so it writes tarball: https://registry.npmjs.org/<name>/-/<name>-<ver>.tgz into every restored resolution. The lock no longer matches its pre-hosted bytes. pnpm keeps the extra field, and a later plain pnpm install doesn't remove it, so the change persists.
Impact
- Rollback and remove aren't byte-exact, which is what Hosted pnpm rollback drops the upstream
tarball:URL from locks written withlockfileIncludeTarballUrl, so the restore isn't byte-exact #557 was fixed to guarantee. Users get an unexplained diff inpnpm-lock.yamlafter undoing hosted mode. - Each restored package is now hard-pinned to
registry.npmjs.orgin the lock, where pnpm would otherwise derive the URL from the configured registry. I haven't reproduced it, but a project that later pointsregistry=at an internal mirror would then still fetch these packages from npmjs. - Installs still succeed with the right upstream bytes; the integrity is correct. So this is low severity, but it is a regression introduced by the Hosted pnpm rollback drops the upstream
tarball:URL from locks written withlockfileIncludeTarballUrl, so the restore isn't byte-exact #557 fix.
Repro (Linux, main 9c43dfc, local mock of the patch API, SOCKET_NPM_REGISTRY pointed at a mirror that serves the real npmjs dist)
mkdir tb && cd tb
echo '{"name":"tb","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
# pnpm 11 / 12 variant:
echo 'lockfile-include-tarball-url=true' > .npmrc
# (pnpm 9 variant instead: printf 'packages:\n - .\nlockfileIncludeTarballUrl: true\n' > pnpm-workspace.yaml)
pnpm install # lock has NO tarball: field (pnpm ignores the setting)
cp pnpm-lock.yaml lock.orig
socket-patch scan --mode hosted --yes
socket-patch rollback --yes # status success
diff lock.orig pnpm-lock.yaml
# > resolution: {integrity: sha512-XI5M…CoEA==, tarball: https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz}socket-patch remove pkg:npm/left-pad@1.3.0 instead of rollback gives the same diff.
Expected vs actual
- Expected: a hosted rollback or remove restores the resolution as the project's pnpm wrote it. CLI_CONTRACT's hosted unwind restores "resolution + integrity from the npm registry's version document", and Hosted pnpm rollback drops the upstream
tarball:URL from locks written withlockfileIncludeTarballUrl, so the restore isn't byte-exact #557/Fix hosted restore dropping registry tarball URLs (#557, #817) #818 made the pnpm restore byte-exact for locks with and without tarball URLs. - Actual: the policy follows a setting pnpm ignored, so the restore adds a
tarball:field.
Matrix (each row run twice, in fresh projects)
| pnpm | setting location | lock after pnpm install has tarball: |
rollback byte-exact |
|---|---|---|---|
| 9.15.9 | pnpm-workspace.yaml lockfileIncludeTarballUrl: true |
no (ignored) | no |
| 9.15.9 | .npmrc (control) |
yes | yes |
| 10.34.5 | pnpm-workspace.yaml / .npmrc (control) |
yes / yes | yes / yes |
| 11.28.3 | .npmrc |
no (ignored) | no |
| 12.8.1 | .npmrc |
no (ignored) | no |
| 12.8.1 | pnpm-workspace.yaml (control) |
yes | yes |
Linux only; the logic is OS-independent. I couldn't use release 4.0.0 as a baseline, because its hosted rollback can't unwind against the mock. Before #818 the restore never wrote tarball: at all (that was #557), so this exact symptom starts with e889d6d.
Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/npm.rs:735(pnpm_tarball_policy):always(:758) honors the workspace-file key and the.npmrckey whatever the pnpm major. A safer signal is the lock itself: if any unpinnedresolution:in the same lock already carries atarball:that the registry could derive, the setting is active. With no such evidence, keep the restore bare. (pnpm 9 locks arelockfileVersion: '9.0'too, so the lock version alone can't tell 9 from 10+.)- Used at
:842inrestore_pnpm_locks.
Probe runs: none (Linux reproduction only).
Backlog review — 2026-10-08
Priority: P1 → P3. The reported trigger adds unnecessary registry tarball URLs on rollback; it does not demonstrate a current install or security failure.
Activity
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 restore following a tarball setting pnpm ignored (#902)
Ignore pnpm 11's env lockfile document in tarball evidence (#902)
Format the pnpm registry lookup and tests; clippy is_none_or
Address review findings on the pnpm open-issues branch
Warn when the pnpm tarball restore guesses; name the pin in the scaff…
Fix the pnpm tarball-guess warning's remedy, scope and Rush handling (#…
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.Read a capitalized lockfileIncludeTarballUrl