Skip to content

Agent mode ignores pnpm's virtualStoreDir: transitive dependencies are reported package_not_installed with a custom virtualStoreDir or the global virtual store #362

Description

[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).

Summary

The npm crawler only looks for pnpm's virtual store at node_modules/.pnpm (or a pnpm ≤3 node_modules/.<registry-host>). pnpm lets you move it:

  • virtualStoreDir / virtual-store-dir, supported on every major. For example .vstore, or node_modules/.custom.
  • the global virtual store (enableGlobalVirtualStore, pnpm 10.12+), where entries live under <store>/v10|v11/links/....

pnpm records the location in node_modules/.modules.yaml ("virtualStoreDir": "..."). With either setting, every transitive dependency is invisible to agent mode. apply skips the patch with package_not_installed ("No installed package matches this PURL"), even though Node loads the package from that directory. Direct dependencies are still reachable through their node_modules/<name> symlink. With the global virtual store, reaching them that way causes #361.

The failure is loud (partialFailure), but agent mode simply can't patch transitive deps in these layouts. The reason it gives is wrong ("not installed"), and the docs don't mention the limitation (docs/ecosystems.md, "npm: which node_modules trees are crawled"). Commands that treat "not installed" as a signal (scan --prune / --sync, remove, repair, vex) inherit the blind spot.

Repro

mkdir p && cd p
echo '{"name":"p","version":"0.0.0","private":true,"dependencies":{"is-odd":"3.0.1"}}' > package.json   # is-odd -> [email protected] (transitive)
printf 'virtualStoreDir: .vstore\n' > pnpm-workspace.yaml     # pnpm <=10 also: printf 'virtual-store-dir=.vstore\n' > .npmrc
pnpm install
ls .vstore/[email protected]/node_modules/is-number/index.js
# hand-stage .socket/manifest.json + blobs for pkg:npm/[email protected] (before = that file)
socket-patch apply --offline --json
#  "status": "partialFailure", "action": "skipped", "reason": "No installed package matches this PURL", "errorCode": "package_not_installed"
node -e "console.log(require('fs').readFileSync(require.resolve('is-number',{paths:[require('path').dirname(require.resolve('is-odd'))]}),'utf8').slice(0,18))"
# still the original bytes; the same project without virtualStoreDir -> applied, node sees the patch

For the global virtual store, replace the workspace line with enableGlobalVirtualStore: true. is-number then lives only under <store>/v11/links/@/is-number/6.0.0/<hash>/node_modules/is-number, with the same package_not_installed result.

Expected vs actual

  • Expected: agent mode patches every installed copy that Node resolves (docs/ecosystems.md npm row: "any install layout ... every store copy"), locating the virtual store from node_modules/.modules.yaml. At minimum it should say the store lives elsewhere, not "not installed".
  • Actual: skipped as not installed.

Matrix (current main f6b7fb9; default = no virtualStoreDir setting, always passes)

OS pnpm custom virtualStoreDir global virtual store
Linux 8.15.9 fail n/a
Linux 9.15.9 fail n/a
Linux 10.34.5 fail fail (sandbox); not engaged on GH runner (pnpm 10 ignores the global virtual store under CI)
Linux 11.27.0 / 12.8.1 fail fail
macOS (GH runner) 10.34.5 / 11.27.0 / 12.8.1 fail fail on 11 / 12 (10: not engaged)
Windows (GH runner) 10.34.5 / 11.27.0 / 12.8.1 fail fail on 11 / 12 (10: not engaged)

Release 4.0.0 behaves the same.

Suspect code

crates/socket-patch-core/src/crawlers/npm_crawler.rs:1033 and :1362: .pnpm is matched by name only, and node_modules/.modules.yaml's virtualStoreDir is never read.

Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36759597534

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions