Repository navigation
Fix lockless nested npm projects in root scans (#1554) - #1591
Open
Mikola Lysenko (mikolalysenko) wants to merge 6 commits into
Open
Mikola Lysenko (mikolalysenko) wants to merge 6 commits into
Mikola Lysenko (mikolalysenko) wants to merge 6 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A root `scan --mode vendored` over a repo that holds an npm project installed without a lockfile (`package-lock=false` in its .npmrc, or `npm install --no-package-lock`) handed that project's packages to the root's lockfile. The root lock never lists them, so every run failed with vendor_lock_entry_not_found, exited 1 and dropped the in-run VEX, and the suggested `npm install` could not clear it. Such a directory, with its own package.json and node_modules and not listed by any workspace, is now treated like a nested project with its own lock: its packages get the nested_project_skipped warning naming the PATH to scan, and the root run succeeds. A member of a lockless inner workspace counts as part of that workspace's project. Fixes #1554 Assisted-by: Claude Code:claude-opus-5-5
The nested_project_skipped warning for a project installed without a lockfile said it had its own lockfile and told the user to run a hosted or vendored scan of it, which is refused there for lack of a lock. It now says the project has no lockfile and offers two remedies that work: create the lock with `npm install --package-lock` and scan it, or patch its node_modules in place with agent mode. The lockless check also stops at the scan root, so a workspace file above the directory being scanned no longer decides what counts as nested below it; a pnpm workspace root no longer claims a directory it does not list; and Rush projects stay the Rush root's. Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 15, 2026 21:43
Collaborator
Author
|
BugBot review Generated by Claude Code |
A pnpm-workspace.yaml whose packages: globs use braces or classes
(`{apps,libs}/*`), or that could not be read, made every lockless
project below it count as a workspace member, so a root vendored scan
still failed on it. Such globs are now matched with the shared
workspace glob grammar, and an unreadable file lists nothing, since
pnpm cannot install from it either.
Assisted-by: Claude Code:claude-opus-5-5
Collaborator
Author
|
BugBot review Generated by Claude Code |
The brace-glob fallback for pnpm-workspace.yaml matched a directory if any package manager's reading did, so a `!` exclusion, a `test` or `tests` directory, or a dot directory could still count as a member, and a lockless project there failed the root vendored scan. The fallback now reads each glob pnpm's way. Assisted-by: Claude Code:claude-opus-5-5
Collaborator
Author
|
BugBot review Generated by Claude Code |
The brace-glob fallback stripped every leading `!`, so `!!apps/x` excluded apps/x, while pnpm's own matcher strips one `!` and treats the rest as a literal that matches nothing. It now strips one. Assisted-by: Claude Code:claude-opus-5-5
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 6f4c327. Configure here.
Collaborator
Author
|
Ready for review — head
Slack announcement not sent this run (send unavailable); the next run retries. Generated by Claude Code |
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 #1554
Summary
A root
scan --mode vendoredover a repo that holds an npm project installed without a lockfile (package-lock=falsein its.npmrc, ornpm install --no-package-lock) failed every run withvendor_lock_entry_not_found, exited 1 and dropped the in-run VEX. The suggestednpm installcouldn't clear it. Such a project is now treated like a nested project that has its own lock (#1534/#1543): its packages get anested_project_skippedwarning, and the root run succeeds and writes its VEX.Root cause
nested_npm_project(crates/socket-patch-core/src/hosted/governing_root.rs) only counted a directory below the scan root as an independent project if it held its own npm-family lock. A lockless project was never recognised, so its copies stayed with the root's vendor backend, and the root lock never lists them.Fix
nested_npm_projectchecks lock roots first, as before. If none matches, it falls back tolockless_npm_project. That function takes the directory that owns the copy's firstnode_modulesand, as long as a workspace lists it, climbs to that workspace's root. The result counts as independent when it sits strictly below the scan root and has apackage.json.listing_workspacedecides membership whether or not the workspace was ever locked. It readspackage.json/vlt.jsonworkspacesin every package manager's dialect, pluspnpm-workspace.yamlpackages:vialists_as_member, which leans toward "member" when it can't tell. It also treats a Rush root as an owner. The walk stops at the scan root.nested_project_skippedwarning for a lockless project now says the project has no lockfile. It offers remedies that work: runnpm install --package-lockthere and then scan it, orsocket-patch scan --mode agent <dir>. The old text claimed the project had its own lockfile and pointed to a hosted/vendored rerun, which would be refused.docs/ecosystems.mdis updated to match.Tests (red → green)
governing_root::tests::nested_npm_project_finds_a_lockless_projectleft: None, right: Some(".../tools/x")governing_root::tests::lockless_project_under_other_roots.npmrc package-lock=falseand plain lockless; 2 runs +--vex)scan::scan_nested_project_e2e::root_vendored_scan_skips_a_lockless_nested_projectnpmrc=true run 1: exit 0assertion fails (exit 1)Commands run locally:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test -p socket-patch-core --lib governing_root: 45 passedcargo test -p socket-patch-cli --all-features --test scan scan_nested_project: 7 passedcargo test -p socket-patch-cli --all-features --test remedy_commands_parse: 2 passed (the new remedy commands parse)cargo test --workspace --all-features --no-fail-fast: all pass except 10 tests that rely on a write or remove being denied (*_write_failure_*,*_unremovable_*,repair_cleanup_failure_*,relax_loop_must_not_traverse_symlinked_root,e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed). The sandbox runs as uid 0, so those denials never happen there. None of them reachesnested_npm_projector the scan nested-project path. CI runs as non-root and is the check for them.Bugbot
!,testand dot rules). Fixed in 121882e with a test; the thread is resolved. CI on 80868e4: 34 pass, 0 fail.!was stripped). Fixed in 6f4c327; the thread is resolved./code-review high
I fixed every confirmed finding except two:
tools/xlocked,tools/x/sublockless): not changed. The existing Rootscan --mode vendoredexits 1 forever and drops its in-run VEX when a nested independent npm project installs a patched package the root lock doesn't have (hosted mode only warns) #1534 test pins this ("a lockless directory belongs to the nearest lock root"). In either case the copy is skipped from the root run. Only the directory the warning names differs.package_json_workspace_root/vlt_workspace_root: not done. Those walks canonicalize and weigh locks, while this one is deliberately lock-agnostic and bounded at the scan root. Merging them would widen this PR into a refactor (see Tracking: derive scan candidates, lock entries and hosted refs from one project inventory instead of four discovery systems #1112).file:link targets: the root lock lists their copies, so they are alreadylockedand never reach this check.🤖 Generated with Claude Code
https://claude.ai/code/session_01LYN2ka9heR9fMVjsgTJGfZ
Generated by Claude Code