feat(pnpm): pnpm 7-12 vendor+hosted support — legacy grammars, zero-touch trustLockfile, takeover reconciliation, revert guards - #213
Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
…rs, zero-touch trustLockfile, takeover reconciliation, revert guards Built and verified against real corepack-pinned pnpm 7.33.5 / 8.15.9 / 9.15.9 / 10.34.5 / 11.22.0 / 12.0.0-rc.7 (plus legacy 1-6 probes) in the 2026-08-18 e2e campaign. HOSTED, pnpm 7/8: the v5.4/v6.0 refusal is replaced by a real rewrite — every instance key of a dep is spliced (v5 /name/ver and _peer-suffixed, v6 (peer)-parenthesized; each owns its resolution), one ledger edit per instance; a post-splice residual detector refuses the dep set-wide if any instance shape the splice regex cannot claim remains (no partial rewrites). Frozen installs from empty stores land patched bytes on both majors; tamper fails ERR_PNPM_TARBALL_INTEGRITY. HOSTED, pnpm 11/12 zero-touch: rewriting a v9 root lock now auto-writes trustLockfile: true into pnpm-workspace.yaml (create with scaffold or byte-preserving append; ledger-recorded as redirect_pnpm_workspace_trust; --no-trust-lockfile-config opt-out; only ErrorKind::NotFound creates — an unreadable existing file falls back to guidance, never overwrite; re-scans heal a missing config on already-redirected locks). pnpm 11.22 and 12-rc frozen installs succeed with no flags and no CI changes; 9/10 ignore the key (verified); the sha512 pin still fails closed under trust. Warnings name the actual spliced host (userinfo stripped) and both per-major error codes, and pre-empt pnpm 12's own rebuild-the-lock advice that silently unpatches. VENDOR, pnpm 7/8: new pnpm-legacy backend (flavor-stamped so older binaries fail closed) — package.json pnpm.overrides + legacy lock surgery emitting exactly what those majors serialize (byte-stable under pnpm's own re-lock). pnpm <= 8 absolutizes file: specifiers, so frozen installs are path-bound: surfaced as vendor_pnpm_legacy_absolute_specifier, with plain `pnpm install --offline` as the moved-checkout path (marker bytes verified). Windows-shaped canonical paths are normalized (verbatim prefix stripped, forward slashes). CONVERSIONS + SAFETY: vendoring over a hosted-redirected npm-family purl now reconciles the redirect ledger (artifact-uuid-anchored matching — version-exact, v5 underscore keys claimed; degraded ledgers keep edits fail-closed), firing vendor_supersedes_redirect exactly once; vendor --revert byte-restores the hosted lock from the wiring originals. All six npm-family vendor backends refuse to delete an artifact the live lock still references when a repair-reconstructed entry has no wiring (vendor_wiring_unknown_revert_blocked — the revert-brick fix); repair stamps detected flavors and preserves corrupt artifacts when no rebuild source exists. Legacy-era diagnostics: shrinkwrap.yaml projects get pnpm-flavored no-lockfile guidance and join the lockfile-only supplement; vendored lock entries get redirect_pnpm_entry_vendored instead of entry-not-found. Tests: e2e_redirect_pnpm_build.rs (new hosted capstone: pnpm 7-11 real corepack legs incl. the zero-touch pnpm 11 proof, tamper negative, hermetic v5/v6 legs), e2e_vendor_pnpm_build.rs ladder (@9/@10/@11 + real pnpm 7/8 lifecycle legs), takeover/reconciliation/guard/heal unit + e2e suites — all RED-verified where behavior changed. CLI_CONTRACT.md and docs/ecosystems.md updated. Stacked on #203 (lock-inventory legacy grammars); trivially overlapping test hunks with #204/#208 carry identical content. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(pnpm defaults frozen on under CI) CI caught what local runs could not: pnpm turns --frozen-lockfile ON when CI=true, and the pnpm <= 8 moved-checkout recovery works precisely by re-resolving the path-bound absolute specifier — frozen semantics skip that re-resolution (pnpm 8: ERR_PNPM_OUTDATED_LOCKFILE; pnpm 7: stale-path install). The lifecycle legs' recovery step now passes --no-frozen-lockfile explicitly, and the vendor_pnpm_legacy_absolute_ specifier remedy (warning text, module doc, CLI_CONTRACT.md, docs/ecosystems.md) recommends `pnpm install --offline --no-frozen-lockfile` so real CI users get working advice. Verified: the full capstone (10 legs incl. real pnpm 7/8 lifecycles) passes under CI=true locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… byte-exactness) Windows CI proved the production normalizer right and the test oracle wrong: the hermetic splice legs built their expected absolute specifier with raw canonicalize().display() — the \\?\C:\ verbatim form the normalizer exists to strip. normalize_canonical_root is now pub and the oracle consumes it at both assertion sites, so the expected string is built by the same transformation the backend writes and cannot drift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Windows CI surfaced the same oracle-drift bug in the module's own unit tests: the fixture helper handed raw canonicalize().display() (verbatim \\?\C:\ form) to the ROOT_TOKEN substitution, the no-leak contains probe, and the moved-checkout fixture builder. All three now go through a canon_root_str() helper built on normalize_canonical_root, so every oracle spells the root exactly as the splice writes it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the pnpm support gap end to end: every pnpm major since 7 now works in vendor and hosted mode, pnpm 11/12 hosted installs are zero-touch (no flags, no CI changes), and the conversion/revert/repair lifecycle around them is fail-closed. Everything here was built spike-first and verified against real corepack-pinned pnpm 7.33.5 / 8.15.9 / 9.15.9 / 10.34.5 / 11.22.0 / 12.0.0-rc.7 in the 2026-08-18 e2e campaign (54 matrix/probe legs), then adversarially reviewed (10 verified findings, all remediated in this diff, each RED-verified).
Stacked on #203 (lock-inventory legacy grammars — this diff extends the same file). Three test hunks overlap #204/#208 with identical content (env-var mirrors for the new global flag); merge those first and this rebases clean.
Hosted mode
/name/ver+_peer-suffixed, v6 parenthesized-peer; each key owns its ownresolution:), one revert-ledger edit per instance. A post-splice residual detector refuses the dep set-wide if any instance shape the splice cannot claim remains — no partial rewrites (review finding: nested-paren suffixes provably unmatchable by the regex are now a refusal, not a silent skip). Proven: frozen installs from empty stores land patched bytes on real pnpm 7/8; tamper failsERR_PNPM_TARBALL_INTEGRITY.trustLockfile: trueintopnpm-workspace.yaml(create-with-scaffold or byte-preserving merge; ledger editredirect_pnpm_workspace_trust;--no-trust-lockfile-configopt-out). Hardened per review: onlyErrorKind::NotFoundcreates (an unreadable existing file gets a warning, never an overwrite), and re-scans heal a missing config on already-redirected locks. Verified: pnpm 11.22 + 12-rc frozen installs succeed with no flags; 9/10 ignore the key; the sha512 pin still fails closed under trust. The warning names the actual spliced host (userinfo stripped, only spliced-lock hosts), both per-major error codes, and pre-empts pnpm 12's ownpnpm clean --lockfileadvice that silently unpatches; legacy locks get legacy-correct guidance (pnpm 7/8 reject--trust-lockfile).Vendor mode
pnpm-legacybackend for 5.4/6.0 locks (flavor-stamped so older binaries fail closed on revert):package.jsonpnpm.overrides+ lock surgery emitting byte-exactly what those majors serialize (idempotent under pnpm's own re-lock; byte-identical revert). Discovered + documented inherent limit: pnpm ≤ 8 absolutizesfile:specifiers, so frozen installs are path-bound — surfaced asvendor_pnpm_legacy_absolute_specifier; a moved checkout runs onepnpm install --offline(marker bytes verified). Windows-shaped canonical paths normalized (verbatim prefix stripped, forward slashes; synthetic-input unit tests — a Windows CI leg should confirm pnpm's own emission spelling).pnpm-workspace.yamlamong committables and tell users to reinstall (the live tree keeps pre-vendor bytes by design).Conversions, revert safety, repair
vendor_supersedes_redirectfires exactly once.vendor --revertbyte-restores the hosted lock from the wiring originals.vendor_wiring_unknown_revert_blocked, recovery guidance included); repair stamps detected flavors so the right guard fires, and preserves corrupt artifacts when no rebuild source exists (forensics over ENOENT).shrinkwrap.yamlprojects (pnpm ≤ 2) get pnpm-flavored no-lockfile guidance and join scan's lockfile-only supplement; a vendored lock entry getsredirect_pnpm_entry_vendoredinstead of a misleading entry-not-found;--mode redirectparses as the legacy alias of hosted.Tests
e2e_redirect_pnpm_build.rs— the hosted capstone pnpm never had (npm/yarn/bun did): real corepack pnpm 7/8/9/10/11 legs (the pnpm 11 leg is the zero-touch proof + opt-out control), tamper negative, hermetic v5/v6 splice legs. 14/14 green locally including all gated legs.e2e_vendor_pnpm_build.rsladder: Anson (@10) primary, @9/Doug Rudolph (@11) opportunistic, real pnpm 7/8 full-lifecycle legs (same-path frozen+offline proof, moved-checkout recovery, byte-identical revert).Review status
Two adversarial review rounds ran over this campaign's diffs (10 + 10 verified findings); all are fixed here or in the sibling PRs #202/#203/#204/#208. Known accepted residuals are documented in code/PR-body where they live (rollback fan-out of patch-added files in store twins fails toward patched bytes; pnpm ≤ 3 custom non-
registry.*hosts; Windows emission spelling needs a Windows CI leg).🤖 Generated with Claude Code
Note
Medium Risk
Changes lockfile and workspace mutation paths, redirect/vendor ledger persistence, and install-time pnpm trust behavior—high impact for CI installs but heavily covered by new e2e and contract tests.
Overview
pnpm hosted (
scan --mode hosted) now rewrites lockfileVersion 5.4/6.0/9.0 grammars (not only v9), with pnpm-specific no-lockfile diagnostics and clearer warnings when a lock entry is already vendored. For root v9 locks, the CLI can auto-writetrustLockfile: trueintopnpm-workspace.yaml(ledger editredirect_pnpm_workspace_trust), with heal-on-rerun when the lock was already redirected, safe handling of unreadable workspace files, and opt-out via new global--no-trust-lockfile-config/SOCKET_NO_TRUST_LOCKFILE_CONFIG. Legacy locks get guidance that does not recommend--trust-lockfileon pnpm 7/8.Vendor / repair / mode switches: Documents and implements
pnpm-legacyvendor flavor for 5.4/6.0 locks; post-vendor human hints namepnpm-workspace.yamlfor pnpm ≥11 and suggest reinstall commands sonode_modulescatches rewired locks. When vendoring supersedes hosted redirects, npm-family purls can automatically drop matching halves fromredirect-state.json(with reconciled vs manual warning text).repairstamps reconstructed ledger entries with the npm lock flavor from the referencing lockfile, movesvendor_wiring_unknownto run-levelwarnings[], and defers deleting corrupt vendor artifacts until a rebuild source exists.Contracts & tests:
CLI_CONTRACT.mdand rollback JSON semantics (package_not_installedmarker records) are updated; newe2e_redirect_pnpm_build.rsand expanded CLI/apply invariant tests pin trust config, splice grammars, and unmatched-purl exit behavior.Reviewed by Cursor Bugbot for commit 2d49af0. Configure here.