From 0ebb8f2f1d03ee4d848b3b908dcacf3e532e371e Mon Sep 17 00:00:00 2001 From: "Abram Sanderson (He/Him)" Date: Tue, 5 May 2026 13:09:27 -0700 Subject: [PATCH 1/5] PR feedback on pnpm workspace and update script: specify more options in .npmrc, move only-pnpm script --- packages/test/test-version-utils/.npmignore | 2 ++ packages/test/test-version-utils/compat-workspaces/full/.npmrc | 3 +++ .../test-version-utils/compat-workspaces/full/package.json | 2 +- .../compat-workspaces/{ => full}/scripts/only-pnpm.cjs | 0 packages/test/test-version-utils/package.json | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) rename packages/test/test-version-utils/compat-workspaces/{ => full}/scripts/only-pnpm.cjs (100%) diff --git a/packages/test/test-version-utils/.npmignore b/packages/test/test-version-utils/.npmignore index 83fce4bddd3c..423f3ef732b9 100644 --- a/packages/test/test-version-utils/.npmignore +++ b/packages/test/test-version-utils/.npmignore @@ -8,3 +8,5 @@ lib/test # Default .npmignore rules only include the root node_modules. # Adding an explicit rule here ensures we don't publish the compat_workspace's node_modules. **/node_modules +# Preserve the .npmrc file in the compat-workspaces folder so that its settings apply to the postinstall script in test-version-utils +!compat-workspaces/.npmrc diff --git a/packages/test/test-version-utils/compat-workspaces/full/.npmrc b/packages/test/test-version-utils/compat-workspaces/full/.npmrc index 1aa498c4e2ee..33b51528c47f 100644 --- a/packages/test/test-version-utils/compat-workspaces/full/.npmrc +++ b/packages/test/test-version-utils/compat-workspaces/full/.npmrc @@ -1 +1,4 @@ node-linker=isolated +frozen-lockfile=true +engine-strict=true +strict-peer-dependencies=true diff --git a/packages/test/test-version-utils/compat-workspaces/full/package.json b/packages/test/test-version-utils/compat-workspaces/full/package.json index 7c8dd93cfba6..dd12e9fb1f47 100644 --- a/packages/test/test-version-utils/compat-workspaces/full/package.json +++ b/packages/test/test-version-utils/compat-workspaces/full/package.json @@ -11,6 +11,6 @@ "license": "MIT", "author": "Microsoft and contributors", "scripts": { - "preinstall": "node ../scripts/only-pnpm.cjs" + "preinstall": "node ./scripts/only-pnpm.cjs" } } diff --git a/packages/test/test-version-utils/compat-workspaces/scripts/only-pnpm.cjs b/packages/test/test-version-utils/compat-workspaces/full/scripts/only-pnpm.cjs similarity index 100% rename from packages/test/test-version-utils/compat-workspaces/scripts/only-pnpm.cjs rename to packages/test/test-version-utils/compat-workspaces/full/scripts/only-pnpm.cjs diff --git a/packages/test/test-version-utils/package.json b/packages/test/test-version-utils/package.json index 0f4b8e15972a..9ba06548f76e 100644 --- a/packages/test/test-version-utils/package.json +++ b/packages/test/test-version-utils/package.json @@ -43,7 +43,7 @@ "eslint:fix": "eslint --quiet --format stylish src --fix --fix-type problem,suggestion,layout", "format": "npm run format:biome", "format:biome": "biome check . --write", - "postinstall": "pnpm --dir compat-workspaces/full install --frozen-lockfile", + "postinstall": "pnpm --dir compat-workspaces/full install", "lint": "fluid-build . --task lint", "lint:fix": "fluid-build . --task eslint:fix --task format", "test": "npm run test:mocha", From b53c6df80f2c01e6a52c0277faef687fe3437fc5 Mon Sep 17 00:00:00 2001 From: "Abram Sanderson (He/Him)" Date: Tue, 5 May 2026 13:13:59 -0700 Subject: [PATCH 2/5] feat(test-version-utils): forward extra args from update-compat-versions to pnpm install Any arguments passed after `--` are now forwarded verbatim to the `pnpm install` invocation inside the script, enabling callers to pass flags such as `--lockfile-only` or `--store-dir` without modifying the script. Co-Authored-By: Claude Sonnet 4.6 --- .../scripts/updateCompatVersions.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/test/test-version-utils/scripts/updateCompatVersions.ts b/packages/test/test-version-utils/scripts/updateCompatVersions.ts index 810e07c2a79f..27992085a0eb 100644 --- a/packages/test/test-version-utils/scripts/updateCompatVersions.ts +++ b/packages/test/test-version-utils/scripts/updateCompatVersions.ts @@ -16,10 +16,15 @@ * 3. Writes `compat-workspaces/generated-versions.cjs` with the resolved exact versions. * 4. Creates or updates per-version `package.json` files in `compat-workspaces/full/`. * 5. Removes version directories that are no longer needed. - * 6. Runs `pnpm install --no-frozen-lockfile` in the workspace to regenerate the lockfile. + * 6. Runs `pnpm install --no-frozen-lockfile [extra args]` in the workspace to regenerate the lockfile. * * Commit all files produced by this script, including the updated `pnpm-lock.yaml`. * + * Any extra arguments passed to this script are forwarded verbatim to `pnpm install`. For example: + * + * pnpm run update-compat-versions -- --lockfile-only + * pnpm run update-compat-versions -- --store-dir /custom/store + * * MACHINE-MAINTAINED (do not edit by hand — regenerated by this script): * compat-workspaces/generated-versions.cjs * compat-workspaces/full//package.json (one per version) @@ -204,9 +209,10 @@ function removeStaleVersionDirs(workspaceDir: string, keepVersions: Set) return removed; } -function pnpmInstallWorkspace(workspaceDir: string): void { - console.log(`\nRunning pnpm install in ${path.relative(pkgRoot, workspaceDir)} ...`); - execSync(`pnpm install --no-frozen-lockfile`, { +function pnpmInstallWorkspace(workspaceDir: string, extraPnpmArgs: string[] = []): void { + const args = ["install", "--no-frozen-lockfile", ...extraPnpmArgs].join(" "); + console.log(`\nRunning pnpm ${args} in ${path.relative(pkgRoot, workspaceDir)} ...`); + execSync(`pnpm ${args}`, { cwd: workspaceDir, env: { ...process.env, NODE_OPTIONS: "" }, stdio: "inherit", @@ -218,6 +224,9 @@ function pnpmInstallWorkspace(workspaceDir: string): void { // --------------------------------------------------------------------------- async function main(): Promise { + // Any arguments after the script name are forwarded to pnpm install. + const extraPnpmArgs = process.argv.slice(2); + // Read current package version const pkgJsonPath = path.join(pkgRoot, "package.json"); const { version: pkgVer } = JSON.parse(readFileSync(pkgJsonPath, "utf8")) as { @@ -331,7 +340,7 @@ async function main(): Promise { if (anyChanged) { // Regenerate lockfile - pnpmInstallWorkspace(fullDir); + pnpmInstallWorkspace(fullDir, extraPnpmArgs); console.log("\nDone. Commit all changes in compat-workspaces/ to the repository."); } else { From 6b322cfe753972665b7e0f70449982bf11631b4d Mon Sep 17 00:00:00 2001 From: "Abram Sanderson (He/Him)" Date: Wed, 6 May 2026 08:35:36 -0700 Subject: [PATCH 3/5] make script pass policy check --- .../test/test-version-utils/compat-workspaces/full/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test/test-version-utils/compat-workspaces/full/package.json b/packages/test/test-version-utils/compat-workspaces/full/package.json index dd12e9fb1f47..6714b0df44ee 100644 --- a/packages/test/test-version-utils/compat-workspaces/full/package.json +++ b/packages/test/test-version-utils/compat-workspaces/full/package.json @@ -11,6 +11,6 @@ "license": "MIT", "author": "Microsoft and contributors", "scripts": { - "preinstall": "node ./scripts/only-pnpm.cjs" + "preinstall": "node scripts/only-pnpm.cjs" } } From 481887d142fe684e450a27ff5624fa9ea4c2cc5c Mon Sep 17 00:00:00 2001 From: Abram Sanderson Date: Wed, 6 May 2026 11:47:54 -0700 Subject: [PATCH 4/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- packages/test/test-version-utils/.npmignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/test/test-version-utils/.npmignore b/packages/test/test-version-utils/.npmignore index 423f3ef732b9..1e67af1c625a 100644 --- a/packages/test/test-version-utils/.npmignore +++ b/packages/test/test-version-utils/.npmignore @@ -8,5 +8,5 @@ lib/test # Default .npmignore rules only include the root node_modules. # Adding an explicit rule here ensures we don't publish the compat_workspace's node_modules. **/node_modules -# Preserve the .npmrc file in the compat-workspaces folder so that its settings apply to the postinstall script in test-version-utils -!compat-workspaces/.npmrc +# Preserve the .npmrc file in compat-workspaces/full so that its settings apply to the postinstall script in test-version-utils +!compat-workspaces/full/.npmrc From 977fc582791b53795ec0b5d9ffce91e7e5d4b39c Mon Sep 17 00:00:00 2001 From: "Abram Sanderson (He/Him)" Date: Wed, 6 May 2026 16:45:52 -0700 Subject: [PATCH 5/5] fix(test-version-utils): pass pnpm install args via execFileSync array Avoids shell-string interpolation of caller-supplied args, which both allowed shell injection and broke for arguments containing spaces/quotes. Uses pnpm.cmd + shell: true on Windows to satisfy Node's CVE-2024-27980 restriction on spawning .cmd shims; in that mode Node still escapes array args for cmd.exe, so arguments remain verbatim. --- .../scripts/updateCompatVersions.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/test/test-version-utils/scripts/updateCompatVersions.ts b/packages/test/test-version-utils/scripts/updateCompatVersions.ts index 27992085a0eb..4daad19d7251 100644 --- a/packages/test/test-version-utils/scripts/updateCompatVersions.ts +++ b/packages/test/test-version-utils/scripts/updateCompatVersions.ts @@ -31,7 +31,7 @@ * compat-workspaces/full/pnpm-lock.yaml */ -import { execSync } from "node:child_process"; +import { execFileSync, execSync } from "node:child_process"; import { existsSync, mkdirSync, @@ -210,12 +210,19 @@ function removeStaleVersionDirs(workspaceDir: string, keepVersions: Set) } function pnpmInstallWorkspace(workspaceDir: string, extraPnpmArgs: string[] = []): void { - const args = ["install", "--no-frozen-lockfile", ...extraPnpmArgs].join(" "); - console.log(`\nRunning pnpm ${args} in ${path.relative(pkgRoot, workspaceDir)} ...`); - execSync(`pnpm ${args}`, { + const args = ["install", "--no-frozen-lockfile", ...extraPnpmArgs]; + console.log( + `\nRunning pnpm ${args.join(" ")} in ${path.relative(pkgRoot, workspaceDir)} ...`, + ); + // On Windows, pnpm is a .cmd shim, which Node refuses to spawn without shell: true + // (CVE-2024-27980). With shell: true on Windows, Node escapes array args for cmd.exe, + // so this still passes arguments verbatim — no shell parsing of caller-provided values. + const isWindows = process.platform === "win32"; + execFileSync(isWindows ? "pnpm.cmd" : "pnpm", args, { cwd: workspaceDir, env: { ...process.env, NODE_OPTIONS: "" }, stdio: "inherit", + shell: isWindows, }); }