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

Skip to content

fix: preserve tarball dependency integrity in the lockfile#12040

Merged
zkochan merged 3 commits into
pnpm:mainfrom
esetnik:fix/tarball-integrity-dropped
May 29, 2026
Merged

fix: preserve tarball dependency integrity in the lockfile#12040
zkochan merged 3 commits into
pnpm:mainfrom
esetnik:fix/tarball-integrity-dropped

Conversation

@esetnik

@esetnik esetnik commented May 28, 2026

Copy link
Copy Markdown
Contributor

What

Fixes #12001 — the integrity field is dropped from the lockfile entry of a remote (non-registry) https-tarball dependency whenever an unrelated package is installed afterwards.

Why

URL/tarball resolvers (@pnpm/resolving.tarball-resolver) intentionally do not return an integrity — it is only known after the tarball is downloaded and hashed. In resolveAndFetch, the freshly resolved resolution overwrites the previous one:

resolution = resolveResult.resolution // { tarball } — no integrity

The integrity is re-attached only on the download path (if (fetchedResult.integrity ...)). So when a tarball dependency is reused from the lockfile without being re-fetched (e.g. any subsequent pnpm add of an unrelated package), its integrity is never restored and is written out of the lockfile.

Since the lockfile-integrity hardening, a hash-less remote-tarball entry then makes the next --frozen-lockfile install fail closed with ERR_PNPM_MISSING_TARBALL_INTEGRITY. This bites CI frequently when a bot (e.g. Renovate) regenerates the lockfile for an unrelated bump.

How

In installing/package-requester, when the resolver returns no integrity and the package was not updated, carry the integrity over from the current (lockfile) resolution instead of dropping it. The change is narrowly guarded to tarball-type resolutions whose id is unchanged.

Reproduction

# package.json: { "dependencies": { "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" } }
pnpm install --store-dir /tmp/store          # integrity present in lockfile
pnpm add --store-dir /tmp/store [email protected] # integrity now gone from the xlsx entry
pnpm install --store-dir /tmp/store --frozen-lockfile
# -> ERR_PNPM_MISSING_TARBALL_INTEGRITY

Test

Added a unit test in package-requester that drives the buggy path with a custom resolver returning no integrity and a currentPkg that has one, asserting the integrity is preserved. It fails on main and passes with this change. Existing package-requester (21) and deps-installer tarball/lockfile/local/custom-resolver suites remain green.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented integrity from being lost for remote tarball dependencies reused from the lockfile, avoiding failures for subsequent --frozen-lockfile installs.
  • Tests
    • Added unit and integration tests that verify tarball dependency integrity is preserved when a resolver omits integrity.
  • Chores
    • Added a changeset and bumped patch versions to ship the fix.

Review Change Stack

Copilot AI review requested due to automatic review settings May 28, 2026 20:57
@esetnik esetnik requested a review from zkochan as a code owner May 28, 2026 20:57
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a4632da7-c0ea-484c-b999-8a3531d8f409

📥 Commits

Reviewing files that changed from the base of the PR and between 8920c44 and 1303f84.

📒 Files selected for processing (2)
  • installing/package-requester/src/packageRequester.ts
  • pacquet/crates/cli/tests/tarball_url_dependency.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • installing/package-requester/src/packageRequester.ts
📜 Recent 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). (1)
  • GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (2)
pacquet/**/*.rs

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/*.rs: Warnings are errors (--deny warnings in lint). Do not silence them with #[allow(...)] unless there is a specific, justified reason.
Choose owned vs. borrowed parameters to minimize copies; widen to the most encompassing type (&Path over &PathBuf, &str over &String) when it doesn't force extra copies.
Prefer Arc::clone(&x) / Rc::clone(&x) over x.clone() for reference-counted types, so the cost is visible at the call site.
Follow Rust API Guidelines for naming: https://rust-lang.github.io/api-guidelines/naming.html
No star imports inside module bodies. Write use super::{Foo, bar} instead of use super::*;, and the same for any other glob whose target is a module you control. Two forms stay allowed: external-crate preludes such as use rayon::prelude::*; and root-of-module re-exports such as pub use submodule::*; in a lib.rs.
Doc comments (///, //!) document the contract: preconditions, postconditions, panics, the reason the function exists. They are not a re-narration of the body.
Do not restate at call sites what the callee's doc comment already says. If /// on the function says 'no-op when …', the caller should not repeat that. Update the doc once; let every call site benefit.
Tests are documentation. Do not duplicate them in prose. If a behavioral scenario, edge case, failure mode, or worked example is already captured by a test, do not also narrate it in the doc comment on the implementation. The same applies in reverse: a test's own doc comment should not re-explain what the asserts already say, only the why if it is not obvious.
Use // SAFETY:, // TODO:, and similar prefixes to signal hidden invariants or known follow-ups that a reader cannot recover from the code alone.
When editing existing code, do not break a method chain (including pipe-trait .pipe(...) chains) into intermediate let bindings unless you can justify the rewrite. Valid justifications include a chain that fails to compile after your...

Files:

  • pacquet/crates/cli/tests/tarball_url_dependency.rs
pacquet/**/{tests,test}/*.rs

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/{tests,test}/*.rs: Tests must not be tolerant of a missing build / runtime environment by silently returning early when a tool isn't found. If the test needs a tool, just call into it and let the existing .unwrap() / .expect(...) panic when the tool is absent.
Prefer platform-specific gates like #[cfg_attr(target_os = "windows", ignore = "...")] or #[cfg(unix)] over runtime probe-and-skip helpers for platform-locked tools, because the gate is visible to cargo test and shows up in the test report.
Follow the test-logging guidance in the style guide — log before non-assert_eq! assertions, dbg! complex structures, skip logging for simple scalar assert_eq!.

Files:

  • pacquet/crates/cli/tests/tarball_url_dependency.rs
🧠 Learnings (3)
📚 Learning: 2026-05-20T19:40:55.051Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:40:55.051Z
Learning: In the pacquet Rust code, ensure the semver implementation uses the `node-semver` crate (not `nodejs-semver`). `node-semver`’s public API does not include a `satisfies_with_prerelease`-style method; prerelease-tolerant matching should be implemented inline by first calling `Range::satisfies`, and when it rejects a prerelease version, retry matching against a stripped `MAJOR.MINOR.PATCH` base of the prerelease version.

Applied to files:

  • pacquet/crates/cli/tests/tarball_url_dependency.rs
📚 Learning: 2026-05-22T00:08:44.646Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11837
File: pacquet/crates/resolving-npm-resolver/src/pick_package.rs:33-51
Timestamp: 2026-05-22T00:08:44.646Z
Learning: In the pnpm/pnpm repo’s pacquet Rust crates, do not flag Unicode ellipsis characters (U+2026, `…`) in Rust doc comments (`///` / `/** */`) as a lint violation. The pacquet crate’s `dylint.toml` only enables `perfectionist::derive_ordering`, and the Dylint `unicode-ellipsis` rule is not enabled for this project—so `…` in doc comments is an intentional, repo-consistent style.

Applied to files:

  • pacquet/crates/cli/tests/tarball_url_dependency.rs
📚 Learning: 2026-05-20T23:07:58.444Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:07:58.444Z
Learning: When reviewing code in this pacquet Rust port, follow the upstream pnpm compatibility rule: only match pnpm’s behavior exactly. Do not propose review changes that intentionally deviate from pnpm’s documented/observed behavior, even if pnpm appears buggy. If you identify a real bug in pnpm behavior, the review should prioritize fixing it upstream in pnpm first, and avoid implementing a pnpm-behavior workaround here unless the same fix has already landed upstream.

Applied to files:

  • pacquet/crates/cli/tests/tarball_url_dependency.rs
🔇 Additional comments (1)
pacquet/crates/cli/tests/tarball_url_dependency.rs (1)

1-134: LGTM!


📝 Walkthrough

Walkthrough

Preserves tarball resolution integrity when reusing lockfile entries that lack resolver-provided integrity, adds a changeset documenting the patch, a unit test for the package requester, and a Rust integration test that verifies frozen-lockfile installs succeed after unrelated lockfile rewrites.

Changes

Tarball Integrity Preservation

Layer / File(s) Summary
Integrity carry-over implementation
installing/package-requester/src/packageRequester.ts, .changeset/fix-tarball-integrity-dropped.md
resolveAndFetch now copies the prior lockfile integrity onto a reused tarball/URL resolution when the resolver omits integrity, the package was not updated, and the resolution is not a directory-style resolution. A changeset documents patch releases.
Regression test for integrity preservation
installing/package-requester/test/index.ts
Adds a Jest test with a custom tarball resolver that omits resolution.integrity and verifies that, with skipFetch: true and an existing currentPkg integrity, the requester returns updated: false and preserves the carried-over integrity in body.resolution.
Integration test: frozen-lockfile with remote tarball
pacquet/crates/cli/tests/tarball_url_dependency.rs
Adds an integration test that records a tarball dependency's integrity in pnpm-lock.yaml, performs an unrelated install that rewrites the lockfile, and asserts the tarball integrity is unchanged and pacquet install --frozen-lockfile succeeds; includes helpers and a known-failure gate for unsupported external tarball dependencies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • zkochan

Poem

🐰 I hopped through lockfiles late at night,
Found a missing hash, tucked it back tight.
Tarballs rejoice, frozen installs sing,
I carried the integrity home like a wing.
Hooray — no more missing-integrity fright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: preserving tarball dependency integrity in the lockfile, which is the core fix implemented across the codebase.
Linked Issues check ✅ Passed The PR directly addresses issue #12001 by implementing the fix to preserve integrity field for tarball dependencies across subsequent installs, including unit and integration tests validating the solution.
Out of Scope Changes check ✅ Passed All changes are narrowly scoped to the integrity preservation fix: changeset entry, core fix in package-requester, corresponding unit test, and an integration test validating the regression scenario.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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 in lockfile

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Preserve tarball integrity from lockfile when resolver returns none
• URL/tarball resolvers lack integrity until download completion
• Prevents integrity loss during unrelated package installations
• Fixes frozen-lockfile failures with ERR_PNPM_MISSING_TARBALL_INTEGRITY
Diagram
flowchart LR
  A["Tarball Resolver<br/>no integrity"] -->|resolveAndFetch| B["Check if Updated"]
  B -->|not updated| C["Carry Over<br/>Previous Integrity"]
  B -->|updated| D["Use New<br/>Resolution"]
  C --> E["Lockfile Entry<br/>with Integrity"]
  D --> E

Loading

Grey Divider

File Changes

1. installing/package-requester/src/packageRequester.ts 🐞 Bug fix +15/-0

Preserve tarball integrity from lockfile

• Added logic to preserve tarball integrity from previous resolution when resolver returns none
• Checks if package was not updated and new integrity is absent
• Carries over previous integrity for tarball-type resolutions
• Narrowly guarded to prevent unintended side effects

installing/package-requester/src/packageRequester.ts


2. installing/package-requester/test/index.ts 🧪 Tests +51/-0

Test tarball integrity preservation logic

• Added unit test for tarball integrity preservation scenario
• Mocks URL/tarball resolver that returns no integrity
• Verifies integrity is carried over from currentPkg when skipFetch is true
• Tests the specific buggy path with custom resolver

installing/package-requester/test/index.ts


3. .changeset/fix-tarball-integrity-dropped.md 📝 Documentation +6/-0

Changeset for tarball integrity fix

• Added changeset documenting the bug fix
• Explains the root cause and solution
• References issue #12001
• Marks patch version bump for affected packages

.changeset/fix-tarball-integrity-dropped.md


Grey Divider

Qodo Logo

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes #12001 where the integrity field of a remote https-tarball dependency was dropped from the lockfile when an unrelated package was installed later, because URL/tarball resolvers don't return integrity and the freshly-resolved resolution overwrote the lockfile one without re-fetching.

Changes:

  • In resolveAndFetch, when the resolver returns no integrity and the package was not updated, carry over the previous integrity from the current (lockfile) resolution onto the new tarball resolution.
  • Adds a unit test driving the buggy path with a custom resolver returning no integrity and a currentPkg that has one.
  • Adds a changeset documenting the patch.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
installing/package-requester/src/packageRequester.ts Preserves tarball integrity from current resolution when resolver returns none and package is not updated.
installing/package-requester/test/index.ts New test asserting integrity is preserved for tarball dependencies when the resolver returns none.
.changeset/fix-tarball-integrity-dropped.md Patch changeset describing the fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Actionable comments posted: 0

URL/tarball resolvers do not return an integrity (it is only known after
the tarball is downloaded). When a remote-tarball dependency was reused
from the lockfile without being re-fetched, the freshly resolved
resolution had no integrity and the existing one was dropped, breaking
subsequent --frozen-lockfile installs under the lockfile-integrity
hardening (ERR_PNPM_MISSING_TARBALL_INTEGRITY). Carry the integrity over
from the current resolution instead.

Closes pnpm#12001

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
zkochan and others added 2 commits May 29, 2026 02:53
Align the integrity carryover added in the previous commit with its
sibling block in the download path: use `!resolution.type` (the idiom
already used there) and drop the `newIntegrity == null` clause, which is
redundant once `resolution` is the freshly resolved resolution.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…12001)

pnpm pnpm#12040 fixes dropping a remote-tarball dependency's integrity when
an unrelated package is installed afterwards. Pacquet can't reach that
scenario yet: a non-registry https-tarball direct dependency hits the
TarballResolver, which returns no name_ver/integrity, so lockfile build
panics with MissingSuffix. Add the regression test for the target
behavior, gated with allow_known_failure! until external tarball deps
install. Tracked in pnpm#12053.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Copilot AI review requested due to automatic review settings May 29, 2026 00:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@zkochan zkochan enabled auto-merge (squash) May 29, 2026 00:57
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.95%. Comparing base (75e11a6) to head (1303f84).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12040      +/-   ##
==========================================
+ Coverage   88.94%   88.95%   +0.01%     
==========================================
  Files         235      235              
  Lines       30839    30930      +91     
==========================================
+ Hits        27429    27514      +85     
- Misses       3410     3416       +6     

☔ 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.

@github-actions

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.903 ± 0.473 2.318 3.884 1.27 ± 0.24
pacquet@main 2.292 ± 0.215 2.039 2.720 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.9031439584400003,
      "stddev": 0.47314495315963584,
      "median": 2.79288601574,
      "user": 2.09044614,
      "system": 2.4978693400000003,
      "min": 2.31761192174,
      "max": 3.88386585174,
      "times": [
        2.8053894827400003,
        2.71828572774,
        3.15561667274,
        2.62078264274,
        2.87030676074,
        3.88386585174,
        2.31761192174,
        3.44165807374,
        2.78038254874,
        2.43753990174
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.29243138394,
      "stddev": 0.2153112609049636,
      "median": 2.2093781642400003,
      "user": 2.10419704,
      "system": 2.48583174,
      "min": 2.03949965474,
      "max": 2.72049411874,
      "times": [
        2.1503075807400003,
        2.2055122057400003,
        2.5845158117400002,
        2.03949965474,
        2.21324412274,
        2.17080390374,
        2.23693982674,
        2.42925443774,
        2.1737421767400003,
        2.72049411874
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 789.5 ± 92.1 722.7 1029.7 1.00
pacquet@main 1065.4 ± 486.2 718.2 2296.2 1.35 ± 0.64
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.7895145084800002,
      "stddev": 0.09209700892819776,
      "median": 0.7640212622800001,
      "user": 0.28712652,
      "system": 1.0272518000000002,
      "min": 0.7227021872800001,
      "max": 1.02970735828,
      "times": [
        1.02970735828,
        0.7418368502800001,
        0.7862056742800001,
        0.8128865832800001,
        0.7241934432800001,
        0.7288461112800001,
        0.7990431322800001,
        0.7227021872800001,
        0.7369001242800001,
        0.8128236202800001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.0654062142799998,
      "stddev": 0.4861749470398279,
      "median": 0.9159630687800001,
      "user": 0.28357962,
      "system": 1.0386517999999998,
      "min": 0.71823979928,
      "max": 2.29620017528,
      "times": [
        2.29620017528,
        0.83187058428,
        0.7640364832800001,
        0.9390743392800001,
        0.72728724728,
        0.71823979928,
        0.9169228722800001,
        0.9150032652800001,
        1.06577347128,
        1.47965390528
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.578 ± 0.227 2.289 2.883 1.07 ± 0.19
pacquet@main 2.405 ± 0.362 2.220 3.153 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.57809216502,
      "stddev": 0.22672964249687944,
      "median": 2.60340647172,
      "user": 3.06795368,
      "system": 2.4578305199999995,
      "min": 2.28869623522,
      "max": 2.88321406122,
      "times": [
        2.28869623522,
        2.7071145692200003,
        2.40758811822,
        2.36643241622,
        2.75148364422,
        2.49969837422,
        2.31296932622,
        2.72826968322,
        2.88321406122,
        2.8354552222200002
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.4050073783199997,
      "stddev": 0.3616198284064763,
      "median": 2.23565607372,
      "user": 3.02922798,
      "system": 2.40437852,
      "min": 2.22005801922,
      "max": 3.15284093922,
      "times": [
        3.02374934122,
        3.15284093922,
        2.22005801922,
        2.2521307582200003,
        2.23233831722,
        2.22474420722,
        2.25701891922,
        2.22087980822,
        2.22733964322,
        2.23897383022
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.468 ± 0.017 1.440 1.488 1.02 ± 0.10
pacquet@main 1.443 ± 0.135 1.333 1.798 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.46821183506,
      "stddev": 0.01661131516353495,
      "median": 1.47028000796,
      "user": 1.37153164,
      "system": 1.4836646199999997,
      "min": 1.44042489146,
      "max": 1.48796435746,
      "times": [
        1.44042489146,
        1.48471888946,
        1.47460281146,
        1.48796435746,
        1.46595720446,
        1.4796820664600001,
        1.45568518046,
        1.4850463574600001,
        1.45028082146,
        1.4577557704600002
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.44251585276,
      "stddev": 0.1354950326447229,
      "median": 1.41705637546,
      "user": 1.38729334,
      "system": 1.44172302,
      "min": 1.33287933646,
      "max": 1.79835287946,
      "times": [
        1.4555039784600001,
        1.33287933646,
        1.3444379964600002,
        1.44873659446,
        1.36714859246,
        1.79835287946,
        1.39579634546,
        1.3585881744600001,
        1.43831640546,
        1.4853982244600001
      ]
    }
  ]
}

@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12040
Testbedpacquet

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
isolated-linker.fresh-restore.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
2.90 s
(+38.29%)Baseline: 2.10 s
2.52 s
(115.24%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
🚷 view threshold
2,578.09 ms
(+9.58%)Baseline: 2,352.69 ms
2,823.23 ms
(91.32%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,468.21 ms
(-0.04%)Baseline: 1,468.80 ms
1,762.56 ms
(83.30%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
2,903.14 ms
(+38.29%)Baseline: 2,099.30 ms
2,519.16 ms
(115.24%)

isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
789.51 ms
(+15.56%)Baseline: 683.20 ms
819.84 ms
(96.30%)
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan merged commit 3cf2b86 into pnpm:main May 29, 2026
23 checks passed
@welcome

welcome Bot commented May 29, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

zkochan added a commit that referenced this pull request May 29, 2026
* fix: preserve tarball dependency integrity in the lockfile

URL/tarball resolvers do not return an integrity (it is only known after
the tarball is downloaded). When a remote-tarball dependency was reused
from the lockfile without being re-fetched, the freshly resolved
resolution had no integrity and the existing one was dropped, breaking
subsequent --frozen-lockfile installs under the lockfile-integrity
hardening (ERR_PNPM_MISSING_TARBALL_INTEGRITY). Carry the integrity over
from the current resolution instead.

Closes #12001

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* refactor(package-requester): simplify tarball integrity carryover guard

Align the integrity carryover added in the previous commit with its
sibling block in the download path: use `!resolution.type` (the idiom
already used there) and drop the `newIntegrity == null` clause, which is
redundant once `resolution` is the freshly resolved resolution.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* test(pacquet): cover tarball-dependency integrity preservation (#12001)

pnpm #12040 fixes dropping a remote-tarball dependency's integrity when
an unrelated package is installed afterwards. Pacquet can't reach that
scenario yet: a non-registry https-tarball direct dependency hits the
TarballResolver, which returns no name_ver/integrity, so lockfile build
panics with MissingSuffix. Add the regression test for the target
behavior, gated with allow_known_failure! until external tarball deps
install. Tracked in #12053.

---------

Co-authored-by: Zoltan Kochan <[email protected]>
@pcaversaccio

Copy link
Copy Markdown

@zkochan would it be possible to release today a new pnpm version containing this patch (I face this issue in a few repos)?

zkochan pushed a commit to subwai/pnpm that referenced this pull request Jun 1, 2026
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 pushed a commit to subwai/pnpm that referenced this pull request Jun 1, 2026
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 added a commit that referenced this pull request Jun 1, 2026
…on (#12096)

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

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 #12040, which fixes the
same class of bug in the package-requester layer but does not cover this re-resolution path.

Closes #12067.

* test: cover integrity carryover on tarball re-resolution

* refactor: check integrity before type in the tarball carryover guard

* perf(pacquet): reuse the warm-store tarball on re-resolution instead of re-downloading

---------

Co-authored-by: Zoltan Kochan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integrity hash get's deleted from tarball installs, when subsequent packages are installed

5 participants