Skip to content

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

Closed

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-lockfile exits 0 with the patched bytes but skips the approved build script. pnpm only prints "Ignored build scripts: sp-build@file:…".
  • pnpm 11 / 12 (strictDepBuilds on by default), and pnpm 10 with strictDepBuilds: true: every frozen install fails with ERR_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.txt

Recovery checks on 12.11.2:

  • Adding 'sp-build@file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz': true to allowBuilds makes 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 --all reports "There are no packages awaiting approval" and changes nothing.
  • socket-patch rollback restores 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) and vendor_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 with ERR_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 writers apply_pkg_override (:1870) and apply_workspace_override (:2084). Nothing reads allowBuilds / onlyBuiltDependencies / neverBuiltDependencies / strictDepBuilds, or the package's scripts / binding.gyp.
  • Prior art for the warning: crates/socket-patch-core/src/vendor/bun_lock.rs:657 (default_trust_warning) and crates/socket-patch-core/src/vendor/npm_lock.rs:1588 (vendor_npm_allow_file).

Activity

  1. mikolalysenko commented on Oct 16, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged as p1 (pnpm). Confirmed on main 657fce2: no vendored pnpm path reads allowBuilds / onlyBuiltDependencies / strictDepBuilds before writing the file: override (vendor/pnpm_lock.rs). Related to #1595 (npm 12 allowScripts) 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

  2. mikolalysenko commented on Oct 16, 2026

    @mikolalysenko
    CollaboratorAuthor

    [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.0 with a postinstall script, and a project whose only dependency is that package. The project explicitly denies the build. I ran scan --mode vendored (exit 0, warnings: [], writes overrides: '@sp/pad@1.0.0': file:.socket/vendor/npm/<uuid>/@sp/pad-1.0.0.tgz), then ran a fresh pnpm install --frozen-lockfile on a copy of the committed tree.

    pnpm denial install before scan fresh frozen install after vendored scan
    12.11.2 allowBuilds: {"@sp/pad": false} (pnpm-workspace.yaml) exit 0, not built exit 1, ERR_PNPM_IGNORED_BUILDS: Ignored build scripts: @sp/pad@file:.socket/vendor/npm/<uuid>/@sp/pad-1.0.0.tgz (2/2 runs)
    11.28.5 allowBuilds: {"@sp/pad": false} exit 0, not built exit 0, not built, patched (2/2)
    10.34.7 ignoredBuiltDependencies: ["@sp/pad"] + strictDepBuilds: true (package.json pnpm) exit 0 exit 0, not built, patched
    10.34.7 neverBuiltDependencies: ["@sp/pad"], with and without strictDepBuilds: true exit 0 exit 0, not built, patched
    9.15.9 neverBuiltDependencies: ["@sp/pad"] exit 0 exit 0, not built, patched

    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": false to allowBuilds makes the frozen install pass again (exit 0), so a fix that carries approvals over should carry false entries too. Hosted mode isn't affected.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 18, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Follow-up from the pnpm bug-hunt routine (ledger #303), on main 7d3086f (code unchanged since 657fce2), 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 on sp-build@1.0.0. sp-build has a postinstall and is the patched package. The build is approved by name (pnpm 10: pnpm.onlyBuiltDependencies: ["sp-build"]; pnpm 11/12: allowBuilds: {sp-build: true} in pnpm-workspace.yaml). scan --mode vendored exits 0 with warnings: [] and writes sp-build@1.0.0: file:.socket/vendor/npm/<uuid>/sp-build-1.0.0.tgz. The lock's snapshot for sp-buildwrap@1.0.0 then depends on sp-build: file:.socket/vendor/.... I then ran a fresh pnpm install --frozen-lockfile on a copy of the committed tree with an empty store.

    pnpm install before scan fresh frozen install after vendored scan hosted scan, same fixture
    10.34.7 built exit 0, Ignored build scripts: sp-build@file:.socket/vendor/..., not built (2/2) built, patched
    11.28.6 built exit 1, ERR_PNPM_IGNORED_BUILDS (1/1) built, patched
    12.14.0 built exit 1, ERR_PNPM_IGNORED_BUILDS (2/2) built, patched

    The patched bytes do land in every vendored cell. Only the approval is lost.


    Generated by Claude Code

  4. mikolalysenko commented on Oct 22, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: vendored pnpm rewires the package to a file: spec without carrying its allowBuilds / onlyBuiltDependencies decision over to that spec). Branch: agent/fix-pnpm-vendored-build-approvals. Claim-ID: 2026-10-22T16:21:18Z-eab349


    Generated by Claude Code

  5. mikolalysenko commented on Oct 22, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1668


    Generated by Claude Code

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