Repository navigation
Fix npm linked-store alias copies left unpatched (#852) - #987
Merged
Mikola Lysenko (mikolalysenko) merged 4 commits intoOct 7, 2026
Merged
Conversation
Assisted-by: Claude Code:claude-opus-5-5
With npm 9-11's install-strategy=linked, an alias install such as
"lp": "npm:left-pad@1.3.0" lives in a store entry named after the
alias (node_modules/.store/lp@1.3.0-<hash>/node_modules/lp). Agent
mode only looked for node_modules/left-pad inside store entries, so:
- beside a plain left-pad copy, apply patched only the plain copy and
exited 0, and vex attested not_affected while require('lp') still
loaded unpatched code;
- with only the alias installed, apply reported the package "not
found on disk" and vex refused with package_not_found.
The resolver now searches npm linked-store entries for alias copies
the same way it searches an importer tree. The store variant fan-out
used by apply, rollback and vex also probes a same-version entry under
another name at its own dir. In both cases the entry's package.json
stays the authority on name and version.
Fixes #852
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. Assisted-by: Claude Code:claude-opus-5-5 (cherry picked from commit 659ac2c)
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 7, 2026 06:51
Collaborator
Author
|
BugBot review 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 87bbd60. Configure here.
Collaborator
Author
|
[agent] Resolved: both one-time re-runs passed on Original note: two CI jobs failed on
Generated by Claude Code |
Collaborator
Author
|
[agent] Ready for review at
Generated by Claude Code |
Tanmay Singla (Tanmay182003)
approved these changes
Oct 7, 2026
Mikola Lysenko (mikolalysenko)
deleted the
agent/fix-npm-linked-store-alias
branch
October 7, 2026 12:40
4 tasks
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 #852
Summary
With npm 9–11's
install-strategy=linked, agent mode now patches, verifies and rolls back an npm alias copy that lives in an alias-named store entry. Before this change:applypatched onlyleft-padand exited 0.vexattestednot_affectedwhilerequire('lp')loaded unpatched code.applyreported "1 not found on disk" (exit 0), andvexomitted the purl as not installed.Root cause
npm names the store entry for an alias install after the alias:
node_modules/.store/lp@1.3.0-<hash>/node_modules/lpholds the realleft-pad@1.3.0. Agent mode missed that copy in two places:NpmCrawler::find_by_purls→visit_resolver_dir): inside a store entry it only probednode_modules/<real name>. The Fix agent mode skipping npm-aliased copies (#356) #738 alias pass (alias_copies) ran on importer trees only.find_store_peer_variant_copies, used by apply, rollback and VEX throughwith_store_peer_variant_copies): it skipped every entry whose dir name advertised another name, then probednode_modules/<real name>.Fix
visit_resolver_diralso runsalias_copieson npm linked-store entries (newis_npm_linked_store_entry, which handles.store/<entry>and.store/@scope/<entry>). It counts real dirs only, and the dir'spackage.jsonstays the authority on name@version.NpmLinkedlayout,find_store_peer_variant_copiesprobes a same-version entry under another name atnode_modules/<advertised name>. That dir must be a real directory, since a link is a dependency edge into another entry. Itspackage.jsonmust name the target, and the name's components passis_safe_npm_component..storeentries don't decode as npm entries.Ported CI fix: this PR carries
87bbd60, a cherry-pick of #878's "Route Gradle digests through utils::digest".main'sutils::digest::tests::production_digests_go_through_the_helpersguard is red: Gradle/JVM/Maven code hashes inline. Without the port,coveragefails for reasons unrelated to this PR. It becomes a no-op once #878 lands.Test evidence
npm_crawler::tests::test_npm_linked_store_alias_entry_beside_a_plain_copy_is_a_copynpm_crawler::tests::test_npm_linked_store_alias_only_install_is_resolvedvexevery-copy rule, newnpm linked-store alias entry (#852)layoute2e_vex::verify_mode_requires_every_store_copy_patchedThe issue's repro with a real npm 10.9.4 / Node 22
install-strategy=linkedinstall and the hand-stagedleft-pad@1.3.0patch, run with a binary built frommainand one built from this branch:not_affected;lpunpatchednot_affected;left-padandlpboth patchedlpunpatchednot_affected;lppatchedrollback --offline --yeson the alias + plain case restores both copies.Commands run locally:
cargo clippy --workspace --all-features -- -D warnings: clean.cargo fmt --all -- --check: no diffs in files this PR touches. The local rustfmt reports existing diffs in files this PR doesn't touch.cargo test -p socket-patch-core --all-features --lib: 5247 passed, 5 failed.chmodcan't make a dir read-only:copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouched,pypi_requirements::wire_failure_rolls_back_already_written_files.maindigest guard, passes after the port.cargo test -p socket-patch-core --all-features --test crawler_npm_e2e --test covgap_crawlers_npm_crawler: 93 passed.cargo test -p socket-patch-cli --all-features --test e2e_vex: 19 passed.cargo test --workspace --all-featurescouldn't finish here: it hit the sandbox's disk allowance while linking test binaries, with no test failures. CI runs the full matrix.🤖 Generated with Claude Code
https://claude.ai/code/session_01RL7etZZRZ4tKZVNsPFD3KL
Generated by Claude Code