[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
With pnpm's lockfile-include-tarball-url=true (.npmrc) or lockfileIncludeTarballUrl: true (pnpm-workspace.yaml), pnpm records every resolution as {integrity: …, tarball: https://registry.npmjs.org/<name>/-/<name>-<ver>.tgz}. The hosted pin itself works: integrity and tarball are both replaced, and a fresh frozen install is patched. But rollback restores only {integrity: …}, so the lock no longer matches what pnpm wrote and the project setting asks for. pnpm doesn't re-add the field: a plain pnpm install afterwards leaves the lock unchanged ("up to date"), so the tarball URL stays lost until someone re-resolves.
Impact
Low. Installs still work, because pnpm derives the URL from the configured registry. But rollback isn't byte-exact, which docs/testing/pnpm-compatibility.md lists as a covered property. It also gives a spurious lock diff in projects that rely on recorded tarball URLs (mirrors, air-gapped tooling, audits).
Repro (Linux; local patch-API mock with SOCKET_PATCH_SERVER_URL / SOCKET_NPM_REGISTRY pointed at it)
mkdir app && cd app
echo '{"name":"app","version":"1.0.0","dependencies":{"is-number":"7.0.0"}}' > package.json
echo lockfile-include-tarball-url=true > .npmrc # pnpm 12: lockfileIncludeTarballUrl: true in pnpm-workspace.yaml
pnpm install && cp pnpm-lock.yaml before.yaml
socket-patch scan --mode hosted --json --yes … # success, redirected 1
socket-patch rollback --json --yes # success
diff before.yaml pnpm-lock.yaml
# - resolution: {integrity: sha512-41Cifkg6…, tarball: https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz}
# + resolution: {integrity: sha512-41Cifkg6…}
pnpm install && diff before.yaml pnpm-lock.yaml # still differs; pnpm doesn't re-add it
Expected vs actual
- Expected: CLI_CONTRACT ("Unwinding hosted state", npm family) says rollback restores the "resolution + integrity … from the npm registry's version document", and that document carries
dist.tarball. When the pre-pin entry had a tarball: field (or the project sets lockfileIncludeTarballUrl), rollback should write the registry dist.tarball back. When it didn't, rollback should keep omitting it.
- Actual:
tarball is always omitted.
Matrix (Linux, each run twice)
| pnpm |
hosted pin + fresh frozen install |
rollback byte-exact |
9.15.9 (.npmrc) |
pass |
fail |
10.34.5 (.npmrc) |
pass |
not run |
| 12.8.1 (workspace setting) |
pass |
fail |
Suspect code
crates/socket-patch-core/src/formats/pnpm/grammar.rs:203 – Resolution::restore drops tarball unconditionally ("pnpm omits tarball for a package the configured registry serves"), which isn't true under this setting.
Tested on main 61cfb9b (CLI 4.0.0).
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
With pnpm's
lockfile-include-tarball-url=true(.npmrc) orlockfileIncludeTarballUrl: true(pnpm-workspace.yaml), pnpm records every resolution as{integrity: …, tarball: https://registry.npmjs.org/<name>/-/<name>-<ver>.tgz}. The hosted pin itself works: integrity and tarball are both replaced, and a fresh frozen install is patched. Butrollbackrestores only{integrity: …}, so the lock no longer matches what pnpm wrote and the project setting asks for. pnpm doesn't re-add the field: a plainpnpm installafterwards leaves the lock unchanged ("up to date"), so the tarball URL stays lost until someone re-resolves.Impact
Low. Installs still work, because pnpm derives the URL from the configured registry. But rollback isn't byte-exact, which
docs/testing/pnpm-compatibility.mdlists as a covered property. It also gives a spurious lock diff in projects that rely on recorded tarball URLs (mirrors, air-gapped tooling, audits).Repro (Linux; local patch-API mock with
SOCKET_PATCH_SERVER_URL/SOCKET_NPM_REGISTRYpointed at it)Expected vs actual
dist.tarball. When the pre-pin entry had atarball:field (or the project setslockfileIncludeTarballUrl), rollback should write the registrydist.tarballback. When it didn't, rollback should keep omitting it.tarballis always omitted.Matrix (Linux, each run twice)
.npmrc).npmrc)Suspect code
crates/socket-patch-core/src/formats/pnpm/grammar.rs:203–Resolution::restoredropstarballunconditionally ("pnpm omitstarballfor a package the configured registry serves"), which isn't true under this setting.Tested on main
61cfb9b(CLI 4.0.0).