Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: preserve integrity of remote tarball dependencies on re-resolution#12096

Merged
zkochan merged 4 commits into
pnpm:mainfrom
subwai:fix/preserve-tarball-integrity-on-reresolution
Jun 1, 2026
Merged

fix: preserve integrity of remote tarball dependencies on re-resolution#12096
zkochan merged 4 commits into
pnpm:mainfrom
subwai:fix/preserve-tarball-integrity-on-reresolution

Conversation

@subwai

@subwai subwai commented Jun 1, 2026

Copy link
Copy Markdown

What

Re-resolving a remote (non-registry) tarball dependency — e.g. running pnpm update, or installing/changing an unrelated dependency — dropped the integrity field from its lockfile entry. URL/tarball resolvers don't return an integrity (it's only known after the tarball is downloaded), so when the entry is rebuilt without a re-fetch the freshly resolved resolution has none, and the previously recorded integrity was lost. Later installs then fail with ERR_PNPM_MISSING_TARBALL_INTEGRITY.

How

toLockfileDependency now carries the integrity over from the previous lockfile entry when the rebuilt resolution is a tarball that lost its integrity and the tarball URL is unchanged. It's guarded so it never overwrites an integrity that's already present, and never attaches a stale hash to a different URL.

Relationship to #12040

This is a follow-up to #12040 ("preserve tarball dependency integrity in the lockfile", which closed #12001). That fix addresses the same root cause but in the package-requester layer — it carries the integrity over from currentPkg during resolve, guarded to tarball resolutions with an unchanged id. That carryover doesn't fire on the re-resolution path in #12067 (pnpm update): the resolution reaches the lockfile builder without an integrity, so the entry is still dropped. This PR adds the equivalent carryover one layer down, when the lockfile entry is rebuilt — complementing #12040 rather than replacing it.

Closes #12067. Related: #12040, #12001.

pacquet parity

pacquet cannot lose tarball integrity the way pnpm did: it builds the lockfile before the install pass, so its TarballResolver learns the integrity directly from the tarball's bytes on every resolution and never drops it. The existing integration test (tarball_url_dependency.rs::remote_tarball_integrity_survives_unrelated_install) is extended to cite this issue and document that immunity — no updateLockfile-style carryover is needed on the Rust side.

Porting it surfaced a performance gap (not a correctness one): pnpm reuses a warm store on re-resolution and skips the fetch, whereas pacquet re-downloaded the tarball every time it re-resolved (e.g. pacquet update). This PR closes that gap too — the resolver now reuses the prior lockfile's recorded integrity + the store-extracted manifest on a warm hit, and downloads only on a miss (safe by construction: the store key embeds the integrity, so a miss just falls back to a download). A discriminating test (remote_tarball_reresolves_from_warm_store_without_refetch) serves the tarball from a throwaway server, tears it down, then runs pacquet update — which succeeds only because the warm store is reused. The test proves the refetch is skipped; it doesn't quantify the speedup (a vlt.sh benchmark would).


Written by an agent (Claude Code, claude-opus-4-8).

Summary by CodeRabbit

  • Bug Fixes
    • Prevented loss of integrity metadata for remote tarball dependencies when lockfile entries are rebuilt, avoiding ERR_PNPM_MISSING_TARBALL_INTEGRITY and improving install reliability for tarball-based packages.
  • Tests
    • Added unit and end-to-end tests verifying integrity preservation and correct behavior when re-resolving tarball dependencies without re-fetching.

@subwai subwai requested a review from zkochan as a code owner June 1, 2026 05:22
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR preserves a prior integrity value for remote tarball lockfile resolutions when re-resolving unchanged tarball URLs and adds a Changesets entry documenting the patch release.

Changes

Tarball integrity preservation

Layer / File(s) Summary
Preserve tarball integrity across re-resolution
installing/deps-resolver/src/updateLockfile.ts
toLockfileDependency now uses a mutable lockfileResolution and, when a new tarball resolution has no type and integrity is unset, copies integrity from the previous snapshot if the tarball URL matches.
Tests for lockfile integrity handling
installing/deps-resolver/test/updateLockfile.test.ts
Adds tests that verify: preserving existing integrity when none is produced on rebuild; new integrity replaces old; and changing the tarball URL does not carry stale integrity.
Pacquet warm-store reuse and wiring
pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs, pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs, pacquet/crates/cli/tests/tarball_url_dependency.rs, pacquet/crates/cli/Cargo.toml
Compute prior_tarball_entries from the wanted lockfile, pass store/index and prior entries through TarballFetchContext, attempt warm-store reuse in TarballResolver::resolve_impl via reuse_from_warm_store, and add end-to-end tests and dev-deps to exercise the flow.
Release notes
.changeset/preserve-tarball-integrity-on-reresolution.md
Adds a Changesets markdown entry declaring patch bumps for @pnpm/installing.deps-resolver and pnpm, documenting the integrity-preservation behavior change.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • pnpm/pnpm#11773: Extends pacquet TarballResolver with warm-store re-resolution logic closely related to the resolver-side changes.
  • pnpm/pnpm#12040: Implements a similar tarball integrity carryover fix in an alternative resolver path.
  • pnpm/pnpm#11966: Adds a lockfile-read guard that throws ERR_PNPM_MISSING_TARBALL_INTEGRITY when tarball resolutions omit integrity, directly related to this PR's prevention of that omission.

Suggested reviewers

  • zkochan

Poem

🐰 A tarball hopped, its checksum snug and tight,
When URLs stayed, I kept its hash in sight.
Re-resolve, re-use from the warm store's graces,
No missing integrity, no worried faces.
Hooray — installs hop forward, safe and light!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: preserving integrity fields for remote tarball dependencies when re-resolution occurs, which is the core fix across all modified files.
Linked Issues check ✅ Passed The PR directly addresses both linked issues (#12001 and #12067) by implementing integrity carryover when re-resolving tarball dependencies, preventing the integrity field from being dropped during pnpm update or related operations.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing tarball integrity preservation across pnpm and pacquet codebases—test additions, Cargo.toml dependency updates, and resolver logic modifications all support the core objective with no extraneous changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Preserve tarball dependency integrity on re-resolution

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Preserve integrity field when re-resolving remote tarball dependencies
• Carry over integrity from previous lockfile entry when tarball URL unchanged
• Prevents ERR_PNPM_MISSING_TARBALL_INTEGRITY on subsequent installs
• Complements #12040 fix in package-requester layer for re-resolution path
Diagram
flowchart LR
  A["Re-resolve tarball<br/>dependency"] --> B["toLockfileResolution<br/>creates new resolution"]
  B --> C{"Tarball lost<br/>integrity?"}
  C -->|Yes| D{"URL unchanged &<br/>prev integrity exists?"}
  D -->|Yes| E["Carry over integrity<br/>from previous entry"]
  D -->|No| F["Keep resolution<br/>as-is"]
  C -->|No| F
  E --> G["Lockfile entry<br/>with integrity preserved"]
  F --> G

Loading

Grey Divider

File Changes

1. installing/deps-resolver/src/updateLockfile.ts 🐞 Bug fix +18/-1

Carry over tarball integrity on re-resolution

• Modified toLockfileDependency to detect when tarball resolution lost integrity
• Added logic to carry over integrity from previous lockfile entry when URL unchanged
• Guarded to only apply when previous resolution exists and is same tarball type
• Prevents integrity field from being dropped during re-resolution without re-fetch

installing/deps-resolver/src/updateLockfile.ts


2. .changeset/preserve-tarball-integrity-on-reresolution.md 📝 Documentation +6/-0

Changeset for tarball integrity preservation fix

• Added changeset entry documenting the fix
• Marks patch version bump for @pnpm/installing.deps-resolver and pnpm
• References issue #12067 and explains the ERR_PNPM_MISSING_TARBALL_INTEGRITY problem

.changeset/preserve-tarball-integrity-on-reresolution.md


Grey Divider

Qodo Logo

@subwai

subwai commented Jun 1, 2026

Copy link
Copy Markdown
Author

Reproduction:

cd "$(mktemp -d)"
pnpm init
# blockExoticSubdeps would block node-xlsx's transitive
pnpm config set blockExoticSubdeps false --location project

# fresh store so the tarball is actually downloaded and its integrity recorded
store=$(mktemp -d)

pnpm --store-dir "$store" add node-xlsx
grep -A1 'cdn.sheetjs' pnpm-lock.yaml
#   resolution: {integrity: sha512-…, tarball: …}

pnpm --store-dir "$store" update
grep -A1 'cdn.sheetjs' pnpm-lock.yaml
#   resolution: {tarball: …}

Just a note: This PR does not solve the scenario where the store is already warm. Neither --update-checksums or --force will force a re-fetch. Only pnpm store prune will do that.

This presents an issue when e.g. adding node-xlsx to two different projects.

@zkochan zkochan force-pushed the fix/preserve-tarball-integrity-on-reresolution branch from 65f9e1a to 19a9680 Compare June 1, 2026 11:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
installing/deps-resolver/test/updateLockfile.test.ts (1)

15-43: 💤 Low value

Consider moving helper functions below the tests.

The coding guideline prefers declaring functions after they are used, relying on hoisting, so that test logic appears first in the file. Moving tarballGraph and lockfileWith below line 87 would follow this pattern.

As per coding guidelines: "declaring functions after they are used (relying on hoisting)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@installing/deps-resolver/test/updateLockfile.test.ts` around lines 15 - 43,
Move the helper functions tarballGraph and lockfileWith so they appear after the
tests (i.e., declared below where they are used) to follow the project's
hoisting-first style; locate the definitions of tarballGraph and lockfileWith
and cut/paste them beneath the test cases (keeping their signatures and returned
types intact) so tests remain at the top and helpers are defined afterwards.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@installing/deps-resolver/test/updateLockfile.test.ts`:
- Around line 15-43: Move the helper functions tarballGraph and lockfileWith so
they appear after the tests (i.e., declared below where they are used) to follow
the project's hoisting-first style; locate the definitions of tarballGraph and
lockfileWith and cut/paste them beneath the test cases (keeping their signatures
and returned types intact) so tests remain at the top and helpers are defined
afterwards.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b4fd4ad3-dea4-4db9-80c7-259bd7424e11

📥 Commits

Reviewing files that changed from the base of the PR and between 19a9680 and a17f43c.

📒 Files selected for processing (1)
  • installing/deps-resolver/test/updateLockfile.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Follow Standard Style with trailing commas, preferring functions over classes, and declaring functions after they are used (relying on hoisting)
Use a single options object instead of multiple parameters when a function needs more than two or three arguments
Follow Import Order: Standard libraries first, then external dependencies (alphabetically), then relative imports
Write self-documenting code where function names, parameters, and types explain what a function does without requiring prose comments
Do not write comments that restate what the code already says; refactor via renaming, splitting helpers, or restructuring instead
Do not repeat documentation at call sites that already exists in JSDoc on the callee; update JSDoc once for all call sites to benefit
Use JSDoc only for a function's contract (preconditions, postconditions, edge cases, why the function exists), not for re-narrating the body
Do not record past implementation shape, refactor history, or 'the previous code did X' framing in code; use git log and git blame instead
Write comments only when: the reason for code is non-obvious (hidden invariant, workaround for known bug, deliberate exception), or the right name doesn't fit (temporary technical constraint)

Files:

  • installing/deps-resolver/test/updateLockfile.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use util.types.isNativeError() instead of instanceof Error for error type checking in Jest tests

Files:

  • installing/deps-resolver/test/updateLockfile.test.ts
🧠 Learnings (1)
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • installing/deps-resolver/test/updateLockfile.test.ts
🔇 Additional comments (2)
installing/deps-resolver/test/updateLockfile.test.ts (2)

1-8: LGTM!


45-87: LGTM!

subwai and others added 4 commits June 1, 2026 15:04
Re-resolving a remote tarball dependency without re-fetching it (e.g. `pnpm update`)
produced a resolution with no integrity, so the previously recorded integrity was
dropped from the lockfile, breaking later installs with ERR_PNPM_MISSING_TARBALL_INTEGRITY.

Carry the integrity over from the previous lockfile entry when the rebuilt tarball
resolution lost it and the URL is unchanged. This complements pnpm#12040, which fixes the
same class of bug in the package-requester layer but does not cover this re-resolution path.

Closes pnpm#12067.
@zkochan zkochan force-pushed the fix/preserve-tarball-integrity-on-reresolution branch from a17f43c to 1126480 Compare June 1, 2026 13:42
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.05%. Comparing base (0a4d665) to head (1126480).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...package-manager/src/install_with_fresh_lockfile.rs 95.00% 1 Missing ⚠️
...resolving-tarball-resolver/src/tarball_resolver.rs 96.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12096      +/-   ##
==========================================
+ Coverage   87.04%   87.05%   +0.01%     
==========================================
  Files         252      252              
  Lines       28146    28196      +50     
==========================================
+ Hits        24499    24546      +47     
- Misses       3647     3650       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zkochan zkochan merged commit 6f382f4 into pnpm:main Jun 1, 2026
20 checks passed
@welcome

welcome Bot commented Jun 1, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

zkochan added a commit that referenced this pull request Jun 1, 2026
During a non-frozen install, reuse the prior pnpm-lock.yaml's resolution and
transitive subtree for dependencies still satisfied and not being updated,
instead of re-resolving everything from manifests.

Faithful port of pnpm's getInfoFromLockfile / resolvedDependencies /
parentPkg.updated machinery, adapted to pacquet's resolver as a hybrid resolve:
snapshot-walk unchanged subtrees, fresh-resolve new/changed/update-targeted
deps, with an `updated` flag propagated down. Semver-satisfies reuse gate
(pnpm parity).

Conservative by construction — registry resolutions only, gated on the whole
subtree being synthesizable; `pacquet update` targets, packageExtensions drift,
and dependency cycles all fall through to a fresh resolve.
  
Follow-up to #12096 (which covered only remote tarballs). Lockfile
canonical-ordering tracked separately as #12117.
@zkochan zkochan mentioned this pull request Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants