Repository navigation
Agent-mode scan ignores socket.yml includePaths / ignorePaths (and the built-in tests/ default) for nested npm projects, patching every nested project's node_modules #554
Description
[agent] Found by the scheduled npm bug-hunt routine (ledger #302). The Bun routine first reported it as a handover (Bun nested projects); I've reproduced it with real npm projects.
Summary
Run socket-patch scan --mode agent at a repo root that holds independent nested npm projects, each with its own package-lock.json and node_modules. The crawler patches the installed copies in every nested project. The socket.yml path policy is only evaluated once, for the scan root, so patches.ignorePaths, patches.includePaths, projectIgnorePaths and the built-in test/ tests/ fixtures/ … defaults never exclude a nested project. The JSON policy block reports counts: {filtered: 0, retained: 0}, so nothing tells the user that the policy wasn't applied.
Hosted and vendored modes honour the same file. scan '*/*' --mode hosted skips services/legacy with /services/ (patches.ignorePaths).
Impact
- In agent mode, a repo can't use path policy to keep socket-patch out of a legacy service, an example, or a test fixture project. Those projects'
node_modulesget rewritten in place anyway. The docs' own headline example (includePaths: ["apps/**", "services/**"],ignorePaths: ["services/legacy/**"]) does nothing in agent mode. includePaths: ["/*", "!/*/"], documented as "targets only the repo-root project", still patches every nested project.- Default-ignored fixture projects under
tests/get patched, which can break fixture tests that pin the upstream bytes. - Agent PATH globs (
scan 'services/**' --mode agent) also reportfiltered: 0. Policy is never consulted per copy.
Repro (Linux, main 61cfb9b, npm 10.9.4 / Node 22 and npm 12.2.0 / Node 24.21; reproduced 3× on npm 10 and 1× on npm 12)
The patch API is a local mock (the one described in ledger #302) serving patches for left-pad@1.3.0, is-number@6.0.0 and is-number@7.0.0. Any patch source works.
mkdir repo && cd repo && git init -q
mk(){ mkdir -p $1; (cd $1; echo "{\"name\":\"$(basename $1)\",\"version\":\"1.0.0\",\"private\":true,\"dependencies\":{$2}}" > package.json; npm install --no-audit --no-fund); }
mk . '"left-pad":"1.3.0"'
mk apps/web '"is-number":"6.0.0"'
mk services/legacy '"left-pad":"1.3.0","is-number":"7.0.0"'
mk tests/e2e '"is-number":"6.0.0"'
printf 'version: 2\npatches:\n ignorePaths: ["/services/"]\n' > socket.yml
socket-patch scan --mode agent --yes --json > scan.json # exit 0
jq -c .policy.counts scan.json # {"filtered":0,"retained":0}
head -c 21 services/legacy/node_modules/left-pad/index.js # /* SOCKET-PATCHED */ <- should be untouched
head -c 21 tests/e2e/node_modules/is-number/index.js # /* SOCKET-PATCHED */ <- default-ignored dirWith includePaths: ["/*", "!/*/"] instead, all five copies are patched too (the root, apps/web, both services/legacy copies and tests/e2e).
Control, using the same tree and the same socket.yml:
socket-patch scan '*/*' --mode hosted
== services/legacy ==
Policy (socket.yml): 1 skipped by filters, 0 patched packages held.
skipped project services/legacy: /services/ (patches.ignorePaths)
# apps/web lock is rewired; services/legacy and tests/e2e locks untouched
Expected vs actual
- CLI_CONTRACT.md, "socket.yml patch policy" → Paths: path lists "are matched against a project root's marker files … the lockfiles in the root's directory". A root is ignored iff every marker is ignored, and
includePaths: ["/*", "!/*/"]"targets only the repo-root project". The built-in defaults "apply only to discovered roots". docs/configuration.md saysincludePaths/ignorePaths"include or exclude project roots by their dependency-file paths". services/legacy/package-lock.jsonis a project root marker that matches/services/. Copies installed under that root should be filtered (and reported inpolicy.filtered[]), or at minimum the agent run should warn that path policy doesn't apply to nested roots.- Actual: every nested project is patched, with
filtered: 0and exit 0.
Matrix (Linux)
| npm / Node | ignorePaths: ["/services/"] |
includePaths: ["/*","!/*/"] |
tests/ default |
hosted '*/*' control |
|---|---|---|---|---|
| 10.9.4 / 22.22 | fail (3/3) | fail | fail | pass |
| 12.2.0 / 24.21 | fail (1/1) | not run | fail | not run |
macOS and Windows weren't probed. The defect is in the OS-independent policy wiring. Bun projects reproduce it too (Bun routine handover, ledger #306), so it applies to the whole npm-family crawler.
First bad release: none. socket.yml patch policy is new in v5 (#293); v4.0.0 has no policy.
Suspect code
crates/socket-patch-cli/src/commands/scan/mod.rs:1472: a non-hosted/vendored scan builds oneScanPolicy::for_root(invocation, &args.common.cwd, …)for the whole run.crates/socket-patch-cli/src/commands/scan/policy.rs:141:for_rootevaluatesadmits_rootonce, for the cwd ("disk scans run one root perrun_scan"). The agent crawl, though, descends into nested projects'node_modules, so their copies are never judged against their own root's markers.
Activity
mikolalysenko commentedon Oct 2, 2026
[agent] Triaged as
priority:p1(npm family, and Bun per the handover). It isn't a duplicate, and I found no open or merged PR that fixes it. I confirmed the cause on main61cfb9b. In agent mode,run_scan(crates/socket-patch-cli/src/commands/scan/mod.rs~L1472) builds a singleScanPolicy::for_rootforargs.common.cwd.for_root(scan/policy.rs~L141) runsadmits_rootonly once, against the cwd's markers. Nothing ever judges a crawled copy under a nested project'snode_modulesagainst that nested root's own markers, so nested projects are never filtered andpolicy.countsstays at 0.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
Being fixed in draft PR #1008 (batch fix for open
pm:npmissues).Fix agent scan ignoring socket.yml paths for nested npm projects (#554)
Merge origin/main into agent/fix-npm-open-issues