Skip to content

fix(scan): parse pnpm v5.4/v6 lock grammars in the lockfile supplement - #203

Open
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/pnpm-lock-inventory-legacy
Open

fix(scan): parse pnpm v5.4/v6 lock grammars in the lockfile supplement#203
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/pnpm-lock-inventory-legacy

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Problem

scan's lockfile-only supplement (the fresh-clone / partial-install rescue path) discovered zero packages from pnpm 7 and pnpm 8 projects, silently: inventory_pnpm_lock_at parsed only the v9 name@version key grammar. v6 keys (/name@1.2.8:) produced a leading-slash name that is_safe_npm_name dropped fail-closed, and v5.4 keys (/name/1.2.8:) were skipped by the rfind('@') guard entirely. Confirmed against real pnpm-7/8-emitted locks in the 2026-08-18 e2e matrix.

Fix

  • New split_pnpm_key(base, legacy) handles all three grammars: peer-paren suffix trimmed first (v6/v9), one leading / stripped and remembered as legacy. Legacy keys may use the v5 name/version form — the segment after the last /, truncated at the first _ (v5 peer/hash suffix), must be digit-leading with no @ — which correctly parses v5 peered keys like /styled-components/5.3.3_react@17.0.2 and scoped v5 keys. Anything unparseable is skipped, never guessed (the function keeps its fail-closed character).
  • The probe-failure fallback that reads a root pnpm-lock.yaml is narrowed to pnpm-specific refusal codes (vendor_lockfile_version_unsupported, vendor_pnpm_pnp_unsupported). Previously it fired on any flavor-probe error, so a stale pnpm-lock.yaml left behind by a pnpm→yarn-berry/bun migration was inventoried as the project's live dependency set.

Verification

  • Grammar tests quoted verbatim from real captured 5.4 and 6.0 locks (mkdirp/minimist shapes), plus synthetic scoped-v5, v5 _-peered, v6 paren-peered, and v9-unchanged cases asserting exact (name, version) pairs.
  • Migration regressions: stale pnpm-lock behind a .pnp.cjs marker or a bun lock is not inventoried; a legacy 5.4 lock alone still is; a pnpm-PnP layout with a 9.0 lock still is.
  • Full core suite green.

🤖 Generated with Claude Code


Note

Medium Risk
Changes read-only lock discovery and fallback routing for scan supplements; incorrect parsing or overly broad fallback could misreport dependencies on fresh clones, though wiring/patch paths remain gated by the flavor probe.

Overview
Lockfile-only scan no longer returns an empty dependency set for pnpm 7/8 projects whose pnpm-lock.yaml uses v5.4 (/name/version) or v6 (/name@version) package keys.

inventory_pnpm_lock_at now routes keys through split_pnpm_key, which strips peer parentheses, handles the leading /, and for legacy keys parses v5 slash-separated names/versions (including _peer/_hash suffix stripping) while still failing closed on unparseable keys.

When the npm flavor probe refuses the project, direct root pnpm-lock.yaml inventory runs only for pnpm-specific codes (vendor_lockfile_version_unsupported, vendor_pnpm_pnp_unsupported)—so stale locks left after pnpm→yarn/bun migrations are not treated as the live set. Rush common-lock fallback on other probe failures is unchanged.

Tests cover real v5/v6 lock shapes, exact v9 entry sets, migration regressions (yarn PnP / bun markers), and pnpm-PnP layouts that should still inventory.

Reviewed by Cursor Bugbot for commit 6596621. Configure here.

Fresh-clone scan of a pnpm 7 or pnpm 8 project discovered ZERO packages:
inventory_pnpm_lock_at parsed only the v9 `name@version` key grammar, so
v6 keys (`/name@1.2.8:`) produced a leading-slash name dropped fail-closed
by is_safe_npm_name, and v5.4 keys (`/name/1.2.8:`) were skipped outright.
Confirmed against real pnpm-7/8-emitted locks (2026-08-18 matrix).

- split_pnpm_key handles all three grammars: peer-paren suffix trimmed,
  one leading slash stripped and remembered as legacy; legacy keys may use
  the v5 name/version form (segment after the last '/', truncated at the
  first '_' peer/hash suffix, digit-leading, no '@') — correctly parsing
  v5 peered keys like /styled-components/5.3.3_react@17.0.2; scoped v5
  keys parse via the same rule.
- The probe-failure fallback that reads a root pnpm-lock.yaml is narrowed
  to pnpm-specific refusals (vendor_lockfile_version_unsupported,
  vendor_pnpm_pnp_unsupported): a stale pnpm-lock.yaml left behind by a
  pnpm->yarn/bun migration is no longer resurrected as the live dependency
  set.

Tests: grammar cases quoted verbatim from real captured 5.4/6.0 locks,
plus migration regressions (stale lock behind .pnp.cjs / bun lock is not
inventoried; legacy lock alone still is).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 6596621. Configure here.

let pnpm = inventory_pnpm_lock(project_root).await.unwrap_or_default();
if !pnpm.is_empty() {
return Some((NpmLockFlavor::Pnpm, finalize_npm(pnpm)));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale pnpm outranks yarn/npm locks

Medium Severity

The new probe-failure fallback inventorizes a root pnpm-lock.yaml on vendor_lockfile_version_unsupported, but the flavor probe returns that code as soon as a legacy pnpm lock exists and never inspects a sibling yarn.lock or package-lock.json. A pnpm→yarn/npm migration that leaves a v5.4/v6 lock behind therefore still surfaces dead pnpm resolutions as the live dependency set. Migration guards cover PnP and bun.lockb only, where those markers win before the pnpm step.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6596621. Configure here.

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.

1 participant