Skip to content

Hosted pnpm rollback drops the upstream tarball: URL from locks written with lockfileIncludeTarballUrl, so the restore isn't byte-exact #557

Description

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

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions