Repository navigation
Deny unneeded esbuild/fsevents install scripts in every v2 install, and guard against unreviewed ones #2712
Description
Problem
npm 11.19 gates dependency install scripts behind an allowScripts policy (RFC npm/rfcs#868). In 11.x a package that is unreviewed (neither allowed nor denied) still runs its script with only a warning. Only an explicit false blocks it (@npmcli/arborist/lib/arborist/rebuild.js: isScriptAllowed(...) === false).
v1 denied the two packages that have scripts in #2077. v2 never got the same change, so every v2 install runs them today. npm install-scripts ls on v2/main:
| Install | Unreviewed install scripts |
|---|---|
| root | fsevents@2.3.3 |
| clients/web | esbuild@0.28.2, fsevents@2.3.2, fsevents@2.3.3 |
| clients/cli, clients/mcpdo, clients/tui | esbuild@0.28.2, fsevents@2.3.3 |
| clients/launcher | none |
Neither script is needed, for the reasons #2077 gives. esbuild gets its platform binary through optionalDependencies (@esbuild/<platform>), so its install.js only validates it or downloads a fallback. fsevents ships a prebuilt fsevents.node, and its install script is only a node-gyp rebuild fallback.
Proposed change
-
Deny by bare name in each install that has a script. v2 is not a workspace, and npm reads
allowScriptsonly from thepackage.jsonof the install it is running in, so each install needs its own entry:- root:
"allowScripts": { "fsevents": false } - web, cli, mcpdo, tui:
"allowScripts": { "esbuild": false, "fsevents": false }
Deny rather than approve-and-pin. A deny by bare name blocks every version, so the version not being pinned does not matter. Approving would mean exact-version pins and dependency churn for scripts we don't want.
- root:
-
Add a
verify:install-scriptsguard invalidate:guards. It runsnpm install-scripts ls --jsonin all six installs and fails on any unreviewed entry. Until npm makes blocking the default, this is the only thing that stops a new dependency's install script from running silently. With the guard, each new script becomes a deliberate approve-or-deny decision in review.
Do not use ignore-scripts. It would also disable the root postinstall (scripts/install-clients.mjs) that installs every client.
Verification
npm install-scripts lsreports nothing unreviewed in all six installs.npm run buildandnpm run local:gatepass from a clean install, i.e. with the scripts skipped. chore: deny esbuild and fsevents install scripts #2077 verified this on v1 only.
Related
- chore: deny esbuild and fsevents install scripts #2077 / v1: npm 11.19 warns about unreviewed install scripts (esbuild, fsevents) on every install #2079: the v1 equivalent.
- Build errors on MacOS 26.6 (Tahoe) #2518: a separate problem. A user's npmrc
allow-scriptsvalue reaches the per-client installs through the environment and makes them fail withEALLOWSCRIPTS. That is fixed ininstall-clients.mjs, independently of this issue.
Activity
fix(scripts): match allowScripts keys and identity the way npm does (#…
fix(scripts): fail closed on bundled install scripts (#2712)
fix(scripts): require a decision for every non-registry dependency (#…
fix(scripts): apply the prepare fallback only to resolved non-registr…
docs(scripts): state why the guard is needed under npm 10/11, not 'un…
docs: describe the non-registry and bundled cases verify:install-scri…
cliffhall commentedon Oct 13, 2026
Shipped in #2714 (merge 15d7721). CI's npm 10 still runs the denied scripts; that follow-up is #2715.
chore(deps): deny esbuild/fsevents install scripts; guard unreviewed …