fix(scan): parse pnpm v5.4/v6 lock grammars in the lockfile supplement - #203
fix(scan): parse pnpm v5.4/v6 lock grammars in the lockfile supplement#203Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
Conversation
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>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
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))); | ||
| } |
There was a problem hiding this comment.
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.
Reviewed by Cursor Bugbot for commit 6596621. Configure here.


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_atparsed only the v9name@versionkey grammar. v6 keys (/name@1.2.8:) produced a leading-slash name thatis_safe_npm_namedropped fail-closed, and v5.4 keys (/name/1.2.8:) were skipped by therfind('@')guard entirely. Confirmed against real pnpm-7/8-emitted locks in the 2026-08-18 e2e matrix.Fix
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 v5name/versionform — 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.2and scoped v5 keys. Anything unparseable is skipped, never guessed (the function keeps its fail-closed character).pnpm-lock.yamlis narrowed to pnpm-specific refusal codes (vendor_lockfile_version_unsupported,vendor_pnpm_pnp_unsupported). Previously it fired on any flavor-probe error, so a stalepnpm-lock.yamlleft behind by a pnpm→yarn-berry/bun migration was inventoried as the project's live dependency set.Verification
_-peered, v6 paren-peered, and v9-unchanged cases asserting exact (name, version) pairs..pnp.cjsmarker 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.🤖 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.yamluses v5.4 (/name/version) or v6 (/name@version) package keys.inventory_pnpm_lock_atnow routes keys throughsplit_pnpm_key, which strips peer parentheses, handles the leading/, and for legacy keys parses v5 slash-separated names/versions (including_peer/_hashsuffix stripping) while still failing closed on unparseable keys.When the npm flavor probe refuses the project, direct root
pnpm-lock.yamlinventory 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.