Fix npm crawler missing Bun, Deno and Yarn 4 stores (#366, #373, #405, #495) - #496
Conversation
With Bun's isolated linker, Deno's isolated nodeModulesDir or Yarn 4's pnpm linker, a transitive dependency lives only in the package manager's store, which the crawler never looked in. Agent-mode apply and scan reported those packages as not installed and left them unpatched with exit 0, and VEX treated a hosted or vendored Bun pin as having no installed copy, so it attested without checking the bytes. The crawler now walks node_modules/.bun and node_modules/.deno like pnpm's store, in scan, apply's resolver and the peer-copy fan-out. In Yarn 4's node_modules/.store it finds each package at the entry's package/ dir, which the entry's own node_modules link points to. Assisted-by: Claude Code:claude-opus-5-5
Installs is-odd with the real yarn 4 pnpm linker, so is-number lives only in node_modules/.store, then checks agent-mode apply patches it, is-odd loads the patched copy, and rollback restores it. Assisted-by: Claude Code:claude-opus-5-5
With bun.lock pinning the hosted tarball and the package installed only in node_modules/.bun, a pristine store copy must be reported not_applied, and a patched one attested. Before the crawler fix VEX saw no installed copy and attested the pristine one. Assisted-by: Claude Code:claude-opus-5-5
A real bun install with linker = "isolated" puts is-number only in node_modules/.bun; apply must patch it and is-odd must load the patched copy. A Deno-shaped node_modules/.deno tree gets the same check without needing deno installed. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
b5985fc ran cargo fmt over the whole workspace, so 124 files outside the crawler fix changed formatting only. That buried the real change for reviewers and invites conflicts with every other open PR. Restore those files to their main versions; npm_crawler.rs keeps its fix. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
|
Burn-down agent: ready for review at
Generated by Claude Code |
|
Reviewed The new Yarn 4 store support can report a successful apply while the package actually loaded at runtime remains unpatched.
Validation: |
A Yarn 4 pnpm-linker store entry keeps its package at <entry>/package and links <entry>/node_modules/<name> to it. The scan descends into that package's own node_modules through the link, but the resolver never follows links, so it missed bundled dependencies there. Apply then patched the regular store copy and reported success while Node kept loading the unpatched bundled copy. When a store entry links to its own package dir, the resolver now also enqueues that dir's node_modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T2DjA5mBwq29D5rrFa5Fvd
|
Fixed the P1 in 2d9eb4d. Thanks for the repro. The resolver now does what the scan does. When a store entry's Tests:
Generated by Claude Code |
|
BugBot review Generated by Claude Code |
|
[agent] Independent check of 2d9eb4d: I had drafted the same fix in parallel. I ran my two extra regressions against 2d9eb4d and both pass, so I dropped my branch and pushed nothing:
Both fail on 7f41839 and pass on 2d9eb4d. CI on 2d9eb4d is still running, and I have asked Bugbot to re-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 2d9eb4d. Configure here.
|
Follow-up reviewed The resolver now visits bundled dependencies inside a Yarn 4 store entry’s physical Validation on this head: original reviewer resolver regression 1 passed; |
The bundled-copy e2e test matched Node's resolved path against a
forward-slash substring, which fails on Windows where Node prints
backslashes. Compare the canonical path of what `require('parent')`
resolves to with the bundled copy's instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T2DjA5mBwq29D5rrFa5Fvd
Keep the Bun, Deno, and Yarn 4 store regressions alongside main's Yarn modules-folder and Rush install-root regressions when resolving the appended-test conflicts. Production changes from both parents are preserved. Signed-off-by: Mikola Lysenko <mikolalysenko@gmail.com>
|
Fixed the merge conflicts and re-reviewed All three conflicts were overlapping appended tests. Both regression sets are preserved: Bun/Deno/Yarn 4 isolated stores, plus Yarn’s configured modules folder and Rush’s shared install root. No production implementation was discarded, and no further actionable defect was found. Validation: 78 crawler tests, 3 hosted VEX tests, 3 apply fixtures, and 2 real Yarn 4 pnpm-linker tests pass. The Yarn tests verify runtime-loaded bytes and rollback, including bundled copies; they ran in required mode without skips. Tests ran on macOS with Node 24.21.0; real Bun installation and the full platform matrix were not rerun locally. |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #366
Fixes #373
Fixes #405
Fixes #495
Root cause
The npm crawler (
crates/socket-patch-core/src/crawlers/npm_crawler.rs) knows isolated dependency stores only by hard-coded names and shapes:.pnpm,.vlt, the pnpm <=3 legacy.registry.*, a relocatedvirtualStoreDir, and npm's linked.storewith a realnode_modules/<name>dir. Under isolated linkers these stores are the only physical home of transitive dependencies.Bun (Bun isolated linker: transitive packages under node_modules/.bun are "not installed" in agent mode, and scan --mode agent exits 0 with them unpatched #366, With Bun's isolated linker,
vexattests a hosted patch as not_affected (verified) while the installed copy under node_modules/.bun is still unpatched (v5 regression) #405) usesnode_modules/.bun/<name>@<ver>[+hash]/node_modules/<name>(pnpm-shaped).Deno (Deno nodeModulesDir: transitive npm packages under node_modules/.deno are "not installed", and apply/scan exit 0 leaving them unpatched #373) uses
node_modules/.deno/<name>@<ver>[_peer]/node_modules/<name>(pnpm-shaped).Both names fall into the generic hidden-entry skip in all three walks:
gather_node_modules(scan),nested_node_modules_of(apply/rollback/VEX lookup) andfind_store_peer_variant_copies.Yarn 4 pnpm linker (Yarn 4 pnpm linker: transitive packages that live only in node_modules/.store are "not installed" in agent mode and stay unpatched #495) reuses the
.storename, but its entry'snode_modules/<name>is a link to the entry's ownpackage/dir. The store-entry real-dir check rejects that link, and nothing walks<entry>/packagedirectly.#405 is the hosted/vendored VEX symptom of the same thing: the installed-copy lookup can't see
.bun, so VEX takes the "nothing installed" branch.Fix
PNPM_SHAPED_STORES(.pnpm,.bun,.deno) is now the one table all three walks consult, with a per-layout entry-name decoder. Bun names carrying a+tail are left undecoded, which keeps them probeable, so a peer hash is never mistaken for build metadata.store_entry_own_package_syncaccepts a store-entry link only when it resolves to that entry's own realpackage/dir (Yarn 4). The copy is recorded atpackage/. Every other link in an entry is still a dependency edge. This is used by the scan, the resolver and the peer-copy fan-out.<entry>/package/node_modules, where the package's bundled dependencies live and where Node loads them from. The scan already descended there, so apply and scan now agree.list_npm_store_entries_synctreats an@…store child that has its ownnode_modulesas an entry, not a scope dir. That is Yarn 4's@scope-leaf-npm-…naming; an npm scope dir can never containnode_modules.docs/ecosystems.mdnow lists the new stores.Tests (red on
main, green here)in_process_alternate_installers::bun_isolated_linker_transitive_only_dep_apply_patches_store: realbun installwithlinker = "isolated", apply patches.bun/is-number@6.0.0, and is-odd loads the patched copy. Also the core unit testtest_bun_isolated_store_transitive_packages_are_found(scan, resolver, peer+hashtwin, hosted-URL entry name, scoped).in_process_alternate_installers::deno_node_modules_dir_transitive_only_dep_apply_patches_store(a Deno 2.x-shaped.denotree), plustest_deno_node_modules_store_transitive_packages_are_found(scan, resolver,_peertwin, scoped,.deno.lock, hoist dir).e2e_vex_redirect::bun_hosted_ref_is_judged_by_the_bun_store_copy: hostedbun.lockpin with the copy only in.bun, under both the stale (left-pad@1.3.0) and fresh (mangled-URL) entry names. A pristine copy now givesnot_applied, wheremainfalsely attested it (exit 0).e2e_yarn4_pnpm_linker_build::yarn4_pnpm_linker_agent_apply_patches_transitive_store_copy: real yarn 4.12.0 withnodeLinker: pnpm, apply patches.store/is-number-npm-6.0.0-*/package,yarn nodeloads it from is-odd, and rollback restores it. Alsotest_yarn4_pnpm_linker_store_transitive_packages_are_found.test_yarn4_pnpm_linker_bundled_copy_inside_store_package_is_resolvedand real yarn 4.12.0yarn4_pnpm_linker_agent_apply_patches_bundled_copy_inside_store_package: a package bundling is-number@7.0.0 keeps that copy at.store/parent-…/package/node_modules/is-number, which Node loads. Apply patches it alongside the regular store copy, and rollback restores both.On
maineach of these fails:package_not_installed(apply exit 1), or the VEX false attestation.Local verification
cargo clippy --workspace --all-features -- -D warnings: clean. The workspace-widecargo fmt --checkreports the same pre-existing diffs asmain(7f41839 reverted the unrelated reformat; CI doesn't run fmt).cargo test -p socket-patch-core --lib npm_crawler: 67 passed, including the randomized oracle-equivalence tests.cargo test --workspace --all-features --no-fail-fast: every suite passes except 14 tests in 5 targets that can't pass in this sandbox, all unrelated to the crawler:covgap_commands_vendor,in_process_redirect,repair, and 4 core lib tests). The container runs as root, so the writes never fail.mode_migration_npmberry takeover tests, which fail TLS against the sandbox proxy's CA.CI runs all of these as non-root, with normal network.
Real-toolchain e2e: bun 1.3.14 and yarn 4.12.0 legs pass, and each fails when run against
main's crawler. The yarn 4 bundled-copy test (2d9eb4d) passes withSOCKET_PATCH_YARN_E2E_REQUIRED=1and fails with the fix disabled.CI: green on 3f8e0c8 (382/382 non-skipped, Windows included). 3f8e0c8 only fixes the bundled-copy e2e test's Windows path comparison. Bugbot clean on 2d9eb4d.
No wrapper changes are needed:
npm/,pypi/andgem/only dispatch to the Rust binary.🤖 Generated with Claude Code
https://claude.ai/code/session_01T2DjA5mBwq29D5rrFa5Fvd