fix(startup): drop the other-cased PATH key from the Windows probe env

Caught by running the suite on a real Windows machine, not a mocked
platform. The spread of process.env is a plain, case-sensitive object,
while Windows resolves env names case-insensitively. Writing the captured
`Path` back onto it left the seeded value still live under `PATH`, so the
probe shell could read either one — the exact duplicate-key hazard the
win32 branch was supposed to prevent.

Drop any other-cased variant of the key before writing.
This commit is contained in:
Neil
2026-08-24 19:21:52 -07:00
parent ccd246a613
commit a8f1a2d98c
2 changed files with 16 additions and 4 deletions
@@ -211,8 +211,10 @@ describe('hydrateShellPath', () => {
})
it('overwrites the captured key in place so Windows never carries both Path and PATH', async () => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
const originalWindowsPath = process.env.Path
delete process.env.PATH
process.env.PATH = 'C:\\Users\\u\\.nvm\\versions\\node\\v22.9.0\\bin;C:\\Windows'
process.env.Path = 'C:\\Users\\u\\.nvm\\versions\\node\\v22.9.0\\bin;C:\\Windows'
_setLaunchPathForTests('C:\\Windows', 'Path')
+14 -4
View File
@@ -121,11 +121,21 @@ function shellProbeEnv(): NodeJS.ProcessEnv {
const key = launchPathOverride?.key ?? LAUNCH_PATH_KEY
const value = launchPathOverride?.value ?? LAUNCH_PATH
const env: NodeJS.ProcessEnv = { ...process.env, [PROBE_MARKER_ENV_VAR]: '1' }
if (value !== null) {
// Why the captured key, not a literal 'PATH': overwrite in place so Windows
// never ends up carrying both `Path` and `PATH` on the spawn env.
env[key] = value
if (value === null) {
return env
}
if (process.platform === 'win32') {
// Why: the spread is a plain, case-sensitive object, but Windows resolves env
// names case-insensitively. Writing our key back without dropping the other
// casing leaves the seeded value live under `PATH` beside a clean `Path`, and
// the shell may read either one.
for (const name of Object.keys(env)) {
if (name !== key && name.toLowerCase() === key.toLowerCase()) {
delete env[name]
}
}
}
env[key] = value
return env
}