Repository navigation
Vendored pnpm 10.34.2+ / 11 / 12 scan breaks build approvals (allowBuilds / onlyBuiltDependencies): the patched package's install script stops running, and on pnpm 11/12 every frozen install fails with ERR_PNPM_IGNORED_BUILDS #1597
Description
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
scan --mode vendored (and vendor) wires a pnpm project to the vendored tarball through an override, sp-build@1.0.0: file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz. pnpm then installs the package as sp-build@file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz.
Since pnpm 10.34.2, pnpm doesn't apply a build approval written for the registry package to that local tarball. This holds for both a name-only key (sp-build) and a pinned key (sp-build@1.0.0), in allowBuilds (pnpm 11/12) and in onlyBuiltDependencies (pnpm 10). Only a key that spells the full file: spec matches.
So once a package with an approved postinstall / install script is vendored:
- pnpm 10.34.2–10.34.7: the next
pnpm install --frozen-lockfileexits 0 with the patched bytes but skips the approved build script. pnpm only prints "Ignored build scripts: sp-build@file:…". - pnpm 11 / 12 (
strictDepBuildson by default), and pnpm 10 withstrictDepBuilds: true: every frozen install fails withERR_PNPM_IGNORED_BUILDS, until the patch is rolled back.
The scan exits 0 with no warning. Hosted mode is not affected: the lock keeps the sp-build@1.0.0 package key, and the approved script still runs.
This is the pnpm counterpart of Bun's vendor_bun_default_trust_lost (docs/testing/bun-compatibility.md, #371). It is related to, but separate from, npm 12's #1595: that bug is npm-specific and also hits hosted mode, while on pnpm even name-only approvals break and only vendored mode is affected.
Impact
In any pnpm ≥ 10.34.2 project that approves builds for a package Socket patches (native addons and binary installers such as esbuild, sharp, bcrypt, better-sqlite3), vendoring the patch does one of two things. On pnpm 10 it silently leaves the package unbuilt. On pnpm 11/12, which are the default for new projects, it breaks every CI install. Meanwhile vex attests the patch, because the files are patched.
Repro
This is current main 657fce2 (5.0.1) on Linux with Node 22.22.0. A local mock registry serves sp-build@1.0.0 (index.js plus "postinstall": "node post.js", which writes built.txt), and a mock org patch API serves a one-line patch to index.js.
mkdir app && cd app
echo '{"name":"app","version":"1.0.0","dependencies":{"sp-build":"1.0.0"}}' > package.json
echo 'registry=http://127.0.0.1:4873/registry/' > .npmrc
printf "allowBuilds:\n 'sp-build': true\n" > pnpm-workspace.yaml # pnpm 10: onlyBuiltDependencies: [sp-build]
pnpm install # postinstall runs, built.txt exists
socket-patch scan --mode vendored --yes --api-url http://127.0.0.1:4873 --org org --api-token fake
# exit 0, warnings: []
# pnpm-workspace.yaml gains: overrides: sp-build@1.0.0: file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz
rm -rf node_modules && pnpm install --frozen-lockfile
# pnpm 12.11.2: Error: ERR_PNPM_IGNORED_BUILDS (exit 1)
# pnpm 11.28.5: [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: sp-build@file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz (exit 1)
# pnpm 10.34.6: exit 0, "Ignored build scripts: sp-build@file:…", no built.txtRecovery checks on 12.11.2:
- Adding
'sp-build@file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz': truetoallowBuildsmakes the frozen install pass and the script run. That key is relative, but it names the patch uuid, so it has to change on every supersede. pnpm approve-builds --allreports "There are no packages awaiting approval" and changes nothing.socket-patch rollbackrestores the workspace file, and the next frozen install passes with the script run.
Expected vs actual
- Expected: a vendored scan doesn't change which dependency build scripts pnpm runs. If it can't keep an approval valid, it warns, or adds the matching
name@file:<spec>approval beside the user's own and removes it on revert. Other install gates already do this:vendor_bun_default_trust_lost(bun-compatibility.md) andvendor_npm_allow_file(npm-compatibility.md). docs/testing/pnpm-compatibility.md says a vendored pnpm project is patched by a plain frozen install, and doesn't mention build approvals. - Actual: exit 0 and
warnings: []. On pnpm 10.34.2+ the approved script is silently skipped. On pnpm 11/12 every frozen install fails withERR_PNPM_IGNORED_BUILDS.
Matrix (Linux, Node 22.22.0, main 657fce2)
| pnpm | approval | hosted: fresh frozen | vendored: fresh frozen |
|---|---|---|---|
| 9.15.9 | pnpm.onlyBuiltDependencies: [sp-build] |
exit 0, script runs | exit 0, script runs |
| 10.0.0 / 10.10.0 / 10.20.0 / 10.28.0 / 10.32.0 / 10.33.2 / 10.33.4 / 10.34.0 / 10.34.1 | onlyBuiltDependencies: [sp-build] |
exit 0, runs (10.0.0) | exit 0, script runs |
| 10.34.2 / 10.34.3 / 10.34.6 / 10.34.7 | onlyBuiltDependencies: [sp-build] (workspace file or package.json) |
exit 0, runs | exit 0, script skipped |
| 10.34.6 | [sp-build@1.0.0] |
exit 0, runs | exit 0, script skipped |
| 10.34.6 | [sp-build] + strictDepBuilds: true |
— | exit 1, ERR_PNPM_IGNORED_BUILDS (the unscanned control passes) |
| 11.28.5 | allowBuilds: {sp-build: true} / {sp-build@1.0.0: true} |
exit 0, runs | exit 1, ERR_PNPM_IGNORED_BUILDS (3/3 runs) |
| 12.11.2 | allowBuilds: {sp-build: true} / {sp-build@1.0.0: true} |
exit 0, runs | exit 1, ERR_PNPM_IGNORED_BUILDS (2/2 runs each) |
In every vendored cell the patched marker landed in index.js. macOS and Windows weren't run, because this routine's probe branches are on hold. pnpm's matcher is platform-independent.
First bad version
Not a socket-patch regression: every socket-patch release vendors pnpm through a file: override. The bug became reachable with pnpm 10.34.2 (published 2026-06-10). 10.34.1 still applies a name-only approval to the local tarball; 10.34.2 doesn't. pnpm 11 and 12 behave like 10.34.2, and also fail the install by default.
Suspect code
crates/socket-patch-core/src/vendor/pnpm_lock.rs:128(vendor_pnpm), with the override writersapply_pkg_override(:1870) andapply_workspace_override(:2084). Nothing readsallowBuilds/onlyBuiltDependencies/neverBuiltDependencies/strictDepBuilds, or the package'sscripts/binding.gyp.- Prior art for the warning:
crates/socket-patch-core/src/vendor/bun_lock.rs:657(default_trust_warning) andcrates/socket-patch-core/src/vendor/npm_lock.rs:1588(vendor_npm_allow_file).
Activity
pnpm: run 45 ledger (#1597, #1557 verified)
mikolalysenko commentedon Oct 16, 2026
[agent] Triaged as p1 (pnpm). Confirmed on main
657fce2: no vendored pnpm path readsallowBuilds/onlyBuiltDependencies/strictDepBuildsbefore writing thefile:override (vendor/pnpm_lock.rs). Related to #1595 (npm 12allowScripts) but not the same root cause: different package manager, different matcher, and the fix lives in a different writer, so I'm not clustering them.Generated by Claude Code
mikolalysenko commentedon Oct 16, 2026
[agent] Follow-up from the pnpm bug-hunt routine (ledger #303), on main
657fce2, Linux, Node 22.22.0: explicit build denials break the same way on pnpm 12.I used a registry package
@sp/pad@1.0.0with apostinstallscript, and a project whose only dependency is that package. The project explicitly denies the build. I ranscan --mode vendored(exit 0,warnings: [], writesoverrides: '@sp/pad@1.0.0': file:.socket/vendor/npm/<uuid>/@sp/pad-1.0.0.tgz), then ran a freshpnpm install --frozen-lockfileon a copy of the committed tree.allowBuilds: {"@sp/pad": false}(pnpm-workspace.yaml)ERR_PNPM_IGNORED_BUILDS:Ignored build scripts: @sp/pad@file:.socket/vendor/npm/<uuid>/@sp/pad-1.0.0.tgz(2/2 runs)allowBuilds: {"@sp/pad": false}ignoredBuiltDependencies: ["@sp/pad"]+strictDepBuilds: true(package.jsonpnpm)neverBuiltDependencies: ["@sp/pad"], with and withoutstrictDepBuilds: trueneverBuiltDependencies: ["@sp/pad"]So on pnpm 12, a project that has already denied the package's install script gets every frozen install failing after a vendored scan, which exits 0 with no warning. That is the same mechanism as above: the name-only key stops matching the
file:spec. Adding the full-spec key"@sp/pad@file:.socket/vendor/npm/<uuid>/@sp/pad-1.0.0.tgz": falsetoallowBuildsmakes the frozen install pass again (exit 0), so a fix that carries approvals over should carryfalseentries too. Hosted mode isn't affected.Generated by Claude Code
mikolalysenko commentedon Oct 18, 2026
[agent] Follow-up from the pnpm bug-hunt routine (ledger #303), on main
7d3086f(code unchanged since657fce2), Linux, Node 22.22.0: the transitive case breaks the same way, so a fix needs to cover more than root dependencies.Fixture: the project depends only on
sp-buildwrap@1.0.0, which depends onsp-build@1.0.0.sp-buildhas apostinstalland is the patched package. The build is approved by name (pnpm 10:pnpm.onlyBuiltDependencies: ["sp-build"]; pnpm 11/12:allowBuilds: {sp-build: true}inpnpm-workspace.yaml).scan --mode vendoredexits 0 withwarnings: []and writessp-build@1.0.0: file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz. The lock's snapshot forsp-buildwrap@1.0.0then depends onsp-build: file:.socket/vendor/.... I then ran a freshpnpm install --frozen-lockfileon a copy of the committed tree with an empty store.Ignored build scripts: sp-build@file:.socket/vendor/..., not built (2/2)ERR_PNPM_IGNORED_BUILDS(1/1)ERR_PNPM_IGNORED_BUILDS(2/2)The patched bytes do land in every vendored cell. Only the approval is lost.
Generated by Claude Code
mikolalysenko commentedon Oct 22, 2026
[agent] Claiming this issue (shared root cause: vendored pnpm rewires the package to a
file:spec without carrying itsallowBuilds/onlyBuiltDependenciesdecision over to that spec). Branch: agent/fix-pnpm-vendored-build-approvals. Claim-ID: 2026-10-22T16:21:18Z-eab349Generated by Claude Code
mikolalysenko commentedon Oct 22, 2026
[agent] Draft PR: #1668
Generated by Claude Code
Keep pnpm build approvals for vendored packages
Test vendored pnpm build approvals on real pnpm
Gate vendored pnpm build keys on the pnpm version
Gate vendored pnpm build keys per major: 10.34.2+, 11.5.3+, 12+