From 8e6ad0a347b07934e288e3227e9e409c0b2037d2 Mon Sep 17 00:00:00 2001 From: Huanqi Cao Date: Fri, 19 Jun 2026 23:46:52 +0800 Subject: [PATCH] fix(scripts): launch lefthook bin shim via shell on Windows spawnSync on a .cmd shim returns EINVAL/null status on recent Node (CVE-2024-27980) unless shell:true, which made postinstall fail and blocked every 'pnpm run' on Windows. (cherry picked from commit 65a08f889ff9738ddaceeeb724e6e24f3be4b2ea) --- scripts/install-lefthook.mjs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/install-lefthook.mjs b/scripts/install-lefthook.mjs index be81daa153..9256a9b462 100644 --- a/scripts/install-lefthook.mjs +++ b/scripts/install-lefthook.mjs @@ -6,8 +6,16 @@ import { join } from 'node:path' const git = spawnSync('git', ['rev-parse', '--git-dir'], { stdio: 'ignore' }) if (git.status !== 0) process.exit(0) -const lefthook = join(process.cwd(), 'node_modules', '.bin', process.platform === 'win32' ? 'lefthook.cmd' : 'lefthook') +const isWindows = process.platform === 'win32' +const lefthook = join(process.cwd(), 'node_modules', '.bin', isWindows ? 'lefthook.cmd' : 'lefthook') if (!existsSync(lefthook)) process.exit(0) -const result = spawnSync(lefthook, ['install', '--force'], { stdio: 'inherit' }) +// On Windows the bin shim is a `.cmd` file, and recent Node (CVE-2024-27980) +// refuses to launch `.cmd`/`.bat` via spawn without `shell: true` — it returns +// `EINVAL` with a null status, which would otherwise fail postinstall. Quote +// the path because a shell re-parses the command line and the path may contain +// spaces. POSIX needs no shell: the extensionless shim is directly executable. +const result = isWindows + ? spawnSync(`"${lefthook}"`, ['install', '--force'], { stdio: 'inherit', shell: true }) + : spawnSync(lefthook, ['install', '--force'], { stdio: 'inherit' }) process.exit(result.status ?? 1)