Studio: npm v12 readiness for install-script gating (#6128)

npm 12 (July 2026) stops running dependency install scripts unless they
are approved via allowScripts, and npm 11.16 already warns. Studio has
no git or remote URL deps anywhere, so script gating is the only
exposure:

- commit the allowScripts policy that npm approve-scripts writes for
  @biomejs/biome and msw, plus a manual fsevents entry: the tooling
  cannot match a darwin-only optional dep from Linux, but the strict
  check walks the platform independent ideal tree and flags it anyway
- drop the minimum-release-age npmrc alias; npm >=11.16 flags it as an
  unknown project config that stops working in npm 12
- approve bun's postinstall in the setup.sh / setup.ps1 bun bootstrap;
  under npm 12 defaults npm install -g bun otherwise leaves a broken
  stub and setup falls back to the slower npm install path
- fix the stale esbuild comment in studio-frontend-ci.yml: the vite 8
  chain ships napi binaries with no install scripts
This commit is contained in:
Daniel Han 2026-06-10 02:20:27 -07:00 committed by GitHub
commit 3307561f85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 18 additions and 13 deletions

View file

@ -69,12 +69,11 @@ jobs:
run: python3 scripts/lockfile_supply_chain_audit.py
- name: Lockfile must agree with package.json (npm ci is strict)
# Lifecycle scripts (esbuild native-binary postinstall, etc.) are
# required for `vite build`. The pre-install lockfile structural
# audit (lockfile_supply_chain_audit.py) is the practical defence
# against the npm postinstall-dropper class -- it fires BEFORE any
# tarball runs, on the injection pattern itself rather than an
# advisory-DB lookup.
# The vite 8 chain (rolldown, lightningcss, tailwind oxide) ships napi
# binaries with no install scripts. The only script-bearing deps are
# covered by `allowScripts` in package.json (npm >=11.16, default in
# npm 12). The pre-install lockfile audit above stays the first line
# of defence -- it fires before any tarball can run code.
run: npm ci --no-fund --no-audit
- name: npm ci must not have modified the working tree

View file

@ -6,11 +6,8 @@
# upstream removal. npm interprets the bare integer as DAYS; do not
# append `d`, npm 11.x will parse `7d` as a Date string and abort.
min-release-age=7
# Defensive alias: `minimum-release-age` takes minutes (10080 = 7 days).
# Some npm versions / wrappers consult one key but not the other; setting
# both means a single setting-name parse change upstream cannot silently
# disable the cooldown. The two keys MUST agree; do not let them drift.
minimum-release-age=10080
# Do not re-add the old `minimum-release-age` alias: npm >=11.16 warns on
# unknown project configs and npm 12 stops accepting them.
# Belt-and-braces: refuse to write back loose `^x.y.z` ranges into
# package.json when a maintainer runs `npm install <pkg>` locally. This
# does NOT rewrite already-present ranges (those need an explicit

View file

@ -108,5 +108,10 @@
"typescript": "~5.9.3",
"typescript-eslint": "^8.55.0",
"vite": "^8.0.1"
},
"allowScripts": {
"@biomejs/biome@1.9.4": true,
"msw@2.14.3": true,
"fsevents": true
}
}

View file

@ -1405,7 +1405,9 @@ if ($IsPipInstall) {
substep "installing bun (faster frontend package installs)..."
$prevEAP_bun = $ErrorActionPreference
$ErrorActionPreference = "Continue"
Invoke-SetupCommand { npm install -g bun } | Out-Null
# --allow-scripts=bun: npm >=11.16 gates install scripts and bun's
# postinstall fetches its binary; without it the install is a broken stub.
Invoke-SetupCommand { npm install -g bun --allow-scripts=bun } | Out-Null
$ErrorActionPreference = $prevEAP_bun
Refresh-Environment
if (Get-Command bun -ErrorAction SilentlyContinue) {

View file

@ -435,7 +435,9 @@ verbose_substep "node check: NEED_NODE=$NEED_NODE NODE_OK=${NODE_OK:-unknown} NP
# avoids platform-specific installers, PATH issues, and admin requirements.
if ! command -v bun &>/dev/null; then
substep "installing bun..."
if run_maybe_quiet npm install -g bun && command -v bun &>/dev/null; then
# --allow-scripts=bun: npm >=11.16 gates install scripts and bun's
# postinstall fetches its binary; without it the install is a broken stub.
if run_maybe_quiet npm install -g bun --allow-scripts=bun && command -v bun &>/dev/null; then
substep "bun installed ($(bun --version))"
else
substep "bun install skipped (npm will be used instead)"