Skip to content

npm_and_yarn: add --no-save to pnpm deep-update fallback#15105

Open
ivnnv wants to merge 2 commits into
dependabot:mainfrom
ivnnv:fix/pnpm-deep-update-no-save
Open

npm_and_yarn: add --no-save to pnpm deep-update fallback#15105
ivnnv wants to merge 2 commits into
dependabot:mainfrom
ivnnv:fix/pnpm-deep-update-no-save

Conversation

@ivnnv
Copy link
Copy Markdown

@ivnnv ivnnv commented May 21, 2026

What are you trying to accomplish?

Fix a manifest/lockfile mismatch produced by the deep-update fallback during pnpm security updates. pnpm update <dep> --depth Infinity --lockfile-only rewrites caret ranges in package.json and the matching specifier: lines in pnpm-lock.yaml to ^<currently-resolved-version> for every direct dep whose resolved version is newer than its declared floor. Dependabot only returns the lockfile from this flow, so the package.json mutations are dropped while the lockfile keeps specifier: entries that no longer match the manifest. CI's frozen-lockfile install rejects the PR.

The comment above run_pnpm_deep_update_command claims this command does not modify package.json. That has not been true on the pnpm versions Dependabot ships against (9.0.5 via corepack, 10.16.0 global).

Fix: add --no-save to the deep-update command. --no-save tells pnpm to leave package.json ranges alone while still resolving and writing the lockfile graph for the target transitive.

Fixes: #15104

Anything you want to highlight for special attention from reviewers?

How will you know you've accomplished your goal?

Reproducer: https://github.com/ivnnv/dependabot-pnpm-deep-update-bug

=== Without --no-save (current dependabot behavior) ===
  command : pnpm update ws --depth Infinity --lockfile-only
  lockfile specifier rewrites : 10
  package.json diff lines     : 18

=== With --no-save (this PR) ===
  command : pnpm update ws --depth Infinity --lockfile-only --no-save
  lockfile specifier rewrites : 0
  package.json diff lines     : 0

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
    Run via this PR's CI — the call-site spec at pnpm_lockfile_updater_spec.rb:775-776 already asserts the exact pnpm update --depth Infinity command string and is updated in this PR to match the new flag. Lint is green; e2e/integration/updater suites are still in progress at the time of writing and will be monitored.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
    Verified against the public reproducer at https://github.com/ivnnv/dependabot-pnpm-deep-update-bug (before/after --no-save: 10 → 0 specifier: rewrites, 18 → 0 lines of package.json mutations). Also verified against a real workspace with a vulnerable transitive ws@8.18.3 that --no-save still bumps ws to 8.20.1 wherever parent ranges allow.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.
    The previous comment above run_pnpm_deep_update_command claimed the command did not modify package.json; that claim was wrong on the pnpm versions Dependabot ships against. The replacement comment spells out exactly when and why --no-save is required, so the next reader does not have to rediscover this.

@ivnnv ivnnv requested a review from a team as a code owner May 21, 2026 15:23
Copilot AI review requested due to automatic review settings May 21, 2026 15:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates PNPM deep-update behavior to avoid unintended manifest/specifier mutations by adding --no-save, and aligns the corresponding spec expectations.

Changes:

  • Append --no-save to pnpm update ... --lockfile-only in the deep update helper.
  • Update the lockfile updater spec to expect the new flag and fingerprint.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
npm_and_yarn/lib/dependabot/npm_and_yarn/native_helpers.rb Adds --no-save to the pnpm deep update command and documents why it’s required.
npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater_spec.rb Updates test expectations to match the new pnpm command line and fingerprint.

Comment on lines +88 to +89
"#{flags}update #{dependency_name} --depth Infinity --lockfile-only --no-save",
fingerprint: "#{flags}update <dependency_name> --depth Infinity --lockfile-only --no-save"
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

--no-save is already used by dependabot-core on the primary pnpm update path in three places:

  • file_updater/pnpm_lockfile_updater.rb:192 (run_pnpm_update_packages)
  • update_checker/subdependency_version_resolver.rb:256 (pnpm_update_command when a target version is known)

All ship the same --no-save flag. The flag is supported on pnpm 7-10 (the versions the npm_and_yarn ecosystem documents support for); this PR brings the deep-update fallback in line with what the primary path already does, no new minimum-version requirement is introduced.

ivnnv added 2 commits May 25, 2026 10:52
pnpm update <dep> --depth Infinity --lockfile-only rewrites caret ranges
in package.json and the matching specifier: lines in pnpm-lock.yaml to
^<currently-resolved-version> for every direct dep whose resolved version
is newer than its declared range floor. Dependabot returns only the
lockfile from this flow, so the package.json mutations are discarded
while the lockfile keeps specifier: entries that no longer match the
manifest, and a downstream frozen-lockfile install rejects the PR.

Adding --no-save tells pnpm to leave package.json ranges alone while
still resolving and writing the lockfile graph for the target transitive
dependency. Verified locally to: still bump the target transitive in
the lockfile, produce zero specifier: rewrites, produce zero
package.json mutations.

Fixes dependabot#15104
@ivnnv ivnnv force-pushed the fix/pnpm-deep-update-no-save branch from b2c7e41 to 222a7c9 Compare May 25, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pnpm security update PRs ship pnpm-lock.yaml specifier rewrites unmatched by package.json changes

3 participants