From 3307561f8533578e36d530d726b8ef762d2ff45f Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Wed, 10 Jun 2026 02:20:27 -0700 Subject: [PATCH] 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 --- .github/workflows/studio-frontend-ci.yml | 11 +++++------ studio/frontend/.npmrc | 7 ++----- studio/frontend/package.json | 5 +++++ studio/setup.ps1 | 4 +++- studio/setup.sh | 4 +++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/studio-frontend-ci.yml b/.github/workflows/studio-frontend-ci.yml index 1270a57ef6..b5a7efb29d 100644 --- a/.github/workflows/studio-frontend-ci.yml +++ b/.github/workflows/studio-frontend-ci.yml @@ -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 diff --git a/studio/frontend/.npmrc b/studio/frontend/.npmrc index 8e21abe7a2..f2d15a4f15 100644 --- a/studio/frontend/.npmrc +++ b/studio/frontend/.npmrc @@ -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 ` locally. This # does NOT rewrite already-present ranges (those need an explicit diff --git a/studio/frontend/package.json b/studio/frontend/package.json index 1e527813f9..2217dd080b 100644 --- a/studio/frontend/package.json +++ b/studio/frontend/package.json @@ -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 } } diff --git a/studio/setup.ps1 b/studio/setup.ps1 index 920d1af13a..9a919e31e3 100644 --- a/studio/setup.ps1 +++ b/studio/setup.ps1 @@ -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) { diff --git a/studio/setup.sh b/studio/setup.sh index 0db9a612c8..15a20a572f 100755 --- a/studio/setup.sh +++ b/studio/setup.sh @@ -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)"