Repository navigation
Fix unquoted scoped name in pnpm 7/8 vendored lock (#956) - #961
Open
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Open
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Vendoring a scoped package (@scope/pkg) into a pnpm 7 (lock 5.4) or pnpm 8 (lock 6.0) project wrote `name: @scope/pkg` into the rekeyed packages entry. A bare `@` cannot start a YAML scalar, so pnpm refused the whole lock with ERR_PNPM_BROKEN_LOCKFILE: every frozen install failed after a scan that reported success, and lock-only VEX kept attesting not_affected from a lock pnpm could not read. The name is now written through the shared YAML scalar quoting, which gives `name: '@scope/pkg'`, byte-identical to what pnpm 7.33.7 and 8.15.9 serialize themselves for the same override. Tests: a byte-exact unit oracle captured from real pnpm 7/8 for @isaacs/string-locale-compare (vendor, in-sync re-run, revert), and scoped real-pnpm lifecycle legs (frozen install, moved checkout, manifest-less VEX, revert) in e2e_vendor_pnpm_build, also run in the pinned pnpm 7/8 matrix. Fixes #956. Assisted-by: Claude Code:claude-opus-5-5
pnpm 8.0.0 and 8.1.0 refuse their own lock for a scoped file: tarball override under --frozen-lockfile (ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY on the key they just wrote); 8.1.1 fixed it. Measured with real pnpm on Node 16: the lock pnpm itself writes fails the same way, so no vendored scoped lock can pass there. The pinned matrix keeps the unscoped leg on those versions and runs the scoped leg everywhere else. Assisted-by: Claude Code:claude-opus-5-5
main has failed socket-patch-core's lib tests since Gradle support (#646) and the digest helpers (#865) both landed. The guard test production_digests_go_through_the_helpers flags three files #646 added that still hash inline: crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs. That breaks test, test-release and coverage on every open PR. Each inline sha1/sha256 call now goes through sha1_hex_of or sha256_hex_of, which compute the same lowercase hex. Behaviour is unchanged. (cherry picked from commit 659ac2c) Ported from #878 so this PR's CI is green while main's digest guard test is red; it no-ops once #878 lands. Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 6, 2026 19:58
Collaborator
Author
|
BugBot review Generated by Claude Code |
edit_packages treated a packages entry as in sync once its file: key and resolution matched, without looking at name:. A lock vendored by a release before the #956 fix still carries `name: @scope/pkg`, which pnpm 7/8 can't load, so a later vendor reported the package already vendored and left the lock broken. The in-sync check now also requires the canonical quoted name: line, so the old spelling is rewritten like any other stale wiring. The new test revendor_heals_an_unquoted_scoped_name fails without this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UepoBazrbnBjy7HkD9YVJN
Tanmay Singla (Tanmay182003)
approved these changes
Oct 6, 2026
Collaborator
Author
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5667ec9. Configure here.
Collaborator
Author
|
[agent] Ready for review at
Generated by Claude Code |
This branch has not been deployed
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.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #956
Root cause
When the legacy pnpm vendored writer (
vendor/pnpm_lock_legacy.rs, lock 5.4 / 6.0) re-emits a rewiredpackages:entry, it writesname: {ctx.name}with no YAML quoting. For a scoped package the result isname: @scope/pkg.@is a reserved YAML indicator, so pnpm 7/8 rejects the whole lock withERR_PNPM_BROKEN_LOCKFILE: every frozen install fails after a scan that reported success, and lock-only VEX keeps attestingnot_affectedfrom a lock pnpm can't read. pnpm's own writer emitsname: '@scope/pkg'.Fix
name:now goes through the sharedformats::pnpm::lines::yaml_valuescalar quoting. Every other line the legacy writer emits was already correct for scoped packages; the byte-exact oracle below matches pnpm on every line exceptname:.file:tarball override (ERR_PNPM_LOCKFILE_MISSING_DEPENDENCYon the key they just wrote), so no vendored scoped lock can pass there. I measured this with real pnpm on Node 16: 8.0.0 and 8.1.0 fail on the lock they generate themselves, and 8.1.1, 8.2.0, 8.3.0, 8.6.0, 8.10.0 and 8.15.9 pass. The unscoped leg still runs on 8.0.0.Route Gradle digests through utils::digest).maincurrently failssocket-patch-core --libonutils::digest::tests::production_digests_go_through_the_helpers, which turnedtestandcoveragered here on the empty start commit. The cherry-pick no-ops once Route Gradle digests through utils::digest #878 lands.edit_packagesin-sync check now also requires the canonical quotedname:line. Before this, a lock vendored by an older release (with the unquoted name) counted as already vendored on re-run, so the broken lock was never repaired.Test evidence (local)
scoped_package_name_is_yaml_quoted_both_grammars(byte-exact oracles captured from real pnpm 7.33.7 / 8.15.9 for@isaacs/string-locale-compare@1.1.0; vendor, in-sync re-run, byte-identical revert)name: @isaacs/string-locale-comparerevendor_heals_an_unquoted_scoped_name(5.4 and 6.0: re-vendor over a lock carrying the old unquoted name)pnpm7_real_lifecycle_scoped_package(real pnpm 7.33.5: frozen offline install, moved checkout, manifest-less VEX cells, re-vendor, revert)ERR_PNPM_BROKEN_LOCKFILE … bad indentation of a mapping entry (16:11)pnpm8_real_lifecycle_scoped_package(real pnpm 8.15.9, same lifecycle)ERR_PNPM_BROKEN_LOCKFILE … (19:11)pnpm_pinned_matrix_vendored_lifecycle_and_manifestless_vexon 7.0.0 / 8.0.0 / 8.1.1 (Node 16)cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-cli --all-features --test e2e_vendor_pnpm_build: 26 passed.cargo test -p socket-patch-core --lib pnpm_lock_legacy: 74 passed.cargo test -p socket-patch-core --lib(on 35ffa60): 5247 passed. 4 failed, all pre-existing and unrelated: the sandbox runs as root, which ignores the read-only permissions those tests rely on (copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_…,pypi_requirements::wire_failure_rolls_back_…). CI runs them as a normal user.cargo test --workspacelocally: the sandbox disk ran out at 29 GB of test binaries. CI runs it.cargo fmtis not enforced in CI andmainis not fmt-clean. I only rustfmt'ed the hunks I wrote.Per-issue checklist
name: @scope/pkgfor a scoped package, so every frozen install fails with ERR_PNPM_BROKEN_LOCKFILE after a successful scan #956 →scoped_package_name_is_yaml_quoted_both_grammarsandrevendor_heals_an_unquoted_scoped_name(unit),pnpm{7,8}_real_lifecycle_scoped_package(e2e), plus the pinned-matrix scoped leg🤖 Generated with Claude Code
https://claude.ai/code/session_01UepoBazrbnBjy7HkD9YVJN
Note
Medium Risk
Changes lockfile emission and in-sync logic for pnpm 5.4/6.0 vendoring (install-breaking if wrong), but behavior is covered by new scoped unit and e2e tests; digest routing is a low-risk refactor.
Overview
Fixes #956: legacy pnpm 7/8 vendored locks for scoped packages now emit a YAML-valid
name:line (quoted viayaml_value), matching pnpm’s serialization so frozen installs no longer hitERR_PNPM_BROKEN_LOCKFILE. Re-vendor in-sync detection also requires that quotedname:line so older broken locks get repaired on the next run.Tests add scoped-package unit oracles and e2e lifecycle coverage (
run_legacy_capstone_for, matrix scoped leg), with a skip for pnpm 8.0.0–8.1.0 where scopedfile:overrides fail under--frozen-lockfileeven on pnpm’s own lock.Refactor: Gradle cache, JVM jar, and Maven sidecar code now use shared
utils::digest::{sha1_hex_of, sha256_hex_of}instead of inlinesha1/sha2+hex::encode(aligns with #878).Reviewed by Cursor Bugbot for commit 5667ec9. Configure here.
Generated by Claude Code