[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
On Windows, global mode never finds a globally installed npm package. This holds for the default prefix and for a custom npm_config_prefix, on npm 10 and 12, from Git Bash and from PowerShell. Only an explicit --global-prefix <dir> works.
scan -g -e npm prints "No global packages found." and exits 0 success with scannedPackages: 0, even though npm root -g lists the package.
get <uuid> -g returns partial_failure (exit 1) and patches nothing.
vex -g omits the patch as package_not_found.
SOCKET_GLOBAL=1 behaves the same way.
It's the same mechanism as #421 (RubyGems / gem.cmd), but on the npm path.
Root cause
get_npm_global_prefix_with (crates/socket-patch-core/src/crawlers/npm_crawler.rs:487) runs runner.run("npm", &["root", "-g"]) through SystemCommandRunner. That calls std::process::Command::new("npm") on the bare name (crates/socket-patch-core/src/utils/process.rs:138). On Windows, std resolves a bare program name to .exe only, so the npm.cmd shim is never found. The spawn fails, get_global_node_modules_paths (npm_crawler.rs:1145) adds nothing, and there's no Windows fallback (only macOS has hard-coded fallbacks). The pnpm, yarn and bun probes next to it use the same bare spawn.
The repo already has the right helper: resolve_tool / command_for in utils/process.rs, which honours PATHEXT and spawns .cmd shims safely.
Impact
This is a silent miss on the most common Windows setup. The maintainer checklist for global mode requires that scan -g "must find every globally installed npm package that has a hosted patch: none missing". Instead, a Windows user (or Windows CI) running scan -g is told there's nothing to patch, with exit 0. get -g fails, and a VEX for global tools can't be produced. Linux and macOS pass the identical probe.
Repro (probe runs on GitHub Actions)
The patch API is a local mock serving a free patch for pkg:npm/[email protected]. SPA="--api-url http://127.0.0.1:8765 --org o --api-token fake --patch-server-url http://127.0.0.1:8765".
npm install -g [email protected]
npm root -g # C:\npm\prefix\node_modules (contains left-pad)
socket-patch scan -g -e npm $SPA --json # status success, scannedPackages 0, packages [] <- bug
socket-patch scan --global-prefix "$(npm root -g)" -e npm $SPA --json # packages: [pkg:npm/[email protected]] <- works
socket-patch get 1732b55e-2d2d-57b9-95b7-ce027791a596 -g $SPA --download-mode file # partial_failure, exit 1, nothing patched
# custom prefix: npm install -g --prefix D:\…\gp [email protected]; npm_config_prefix=D:\…\gp -> npm root -g = D:\…\gp\node_modules; scan -g still finds nothing
Same result from pwsh with socket-patch.exe scan -g -e npm … --json: scannedPackages: 0.
Expected vs actual
- Expected: CLI_CONTRACT.md documents
--global / -g as "Operate on globally-installed packages", with --global-prefix defaulting to "(auto)", i.e. discovered via npm root -g. Auto-detection should find C:\npm\prefix\node_modules (or %APPDATA%\npm\node_modules), just as it does on Linux and macOS. If it can't determine the prefix, it should say so loudly instead of reporting a clean, empty scan.
- Actual: auto-detection silently finds nothing on Windows.
Matrix (main 2463257, Node 24.15.0)
| Runner |
npm |
scan -g (default prefix) |
scan -g (custom npm_config_prefix) |
get -g |
vex -g |
--global-prefix scan / get / rollback |
| windows-latest |
10.9.7 |
FAIL (0 packages, exit 0) |
FAIL |
FAIL (exit 1) |
FAIL |
pass |
| windows-latest |
12.1.0 |
FAIL |
FAIL |
FAIL |
FAIL |
pass |
| windows-2022 |
10.9.7 |
FAIL |
FAIL |
FAIL |
n/a |
pass |
| windows-2022 |
12.1.0 |
FAIL |
FAIL |
FAIL |
n/a |
pass |
| ubuntu-latest |
10.9.7 / 12.1.0 |
pass |
pass |
pass |
pass |
pass |
| macos-latest |
10.9.7 / 12.1.0 |
n/a |
pass |
pass |
pass |
n/a |
| Linux sandbox |
10.9.7 / 12.1.0 |
pass |
pass |
pass |
pass |
pass |
Probe runs: https://github.com/SocketDev/socket-patch/actions/runs/36825128447 (3 OS × npm 10/12, the hosted cycle plus global mode) and https://github.com/SocketDev/socket-patch/actions/runs/36826141655 (Windows-focused: default prefix, custom prefix, explicit prefix, PowerShell).
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
On Windows, global mode never finds a globally installed npm package. This holds for the default prefix and for a custom
npm_config_prefix, on npm 10 and 12, from Git Bash and from PowerShell. Only an explicit--global-prefix <dir>works.scan -g -e npmprints "No global packages found." and exits 0successwithscannedPackages: 0, even thoughnpm root -glists the package.get <uuid> -greturnspartial_failure(exit 1) and patches nothing.vex -gomits the patch aspackage_not_found.SOCKET_GLOBAL=1behaves the same way.It's the same mechanism as #421 (RubyGems /
gem.cmd), but on the npm path.Root cause
get_npm_global_prefix_with(crates/socket-patch-core/src/crawlers/npm_crawler.rs:487) runsrunner.run("npm", &["root", "-g"])throughSystemCommandRunner. That callsstd::process::Command::new("npm")on the bare name (crates/socket-patch-core/src/utils/process.rs:138). On Windows,stdresolves a bare program name to.exeonly, so thenpm.cmdshim is never found. The spawn fails,get_global_node_modules_paths(npm_crawler.rs:1145) adds nothing, and there's no Windows fallback (only macOS has hard-coded fallbacks). Thepnpm,yarnandbunprobes next to it use the same bare spawn.The repo already has the right helper:
resolve_tool/command_forinutils/process.rs, which honoursPATHEXTand spawns.cmdshims safely.Impact
This is a silent miss on the most common Windows setup. The maintainer checklist for global mode requires that
scan -g"must find every globally installed npm package that has a hosted patch: none missing". Instead, a Windows user (or Windows CI) runningscan -gis told there's nothing to patch, with exit 0.get -gfails, and a VEX for global tools can't be produced. Linux and macOS pass the identical probe.Repro (probe runs on GitHub Actions)
The patch API is a local mock serving a free patch for
pkg:npm/[email protected].SPA="--api-url http://127.0.0.1:8765 --org o --api-token fake --patch-server-url http://127.0.0.1:8765".Same result from
pwshwithsocket-patch.exe scan -g -e npm … --json:scannedPackages: 0.Expected vs actual
--global/-gas "Operate on globally-installed packages", with--global-prefixdefaulting to "(auto)", i.e. discovered vianpm root -g. Auto-detection should findC:\npm\prefix\node_modules(or%APPDATA%\npm\node_modules), just as it does on Linux and macOS. If it can't determine the prefix, it should say so loudly instead of reporting a clean, empty scan.Matrix (main
2463257, Node 24.15.0)scan -g(default prefix)scan -g(customnpm_config_prefix)get -gvex -g--global-prefixscan / get / rollbackProbe runs: https://github.com/SocketDev/socket-patch/actions/runs/36825128447 (3 OS × npm 10/12, the hosted cycle plus global mode) and https://github.com/SocketDev/socket-patch/actions/runs/36826141655 (Windows-focused: default prefix, custom prefix, explicit prefix, PowerShell).