diff --git a/src/infra/browser-open.test.ts b/src/infra/browser-open.test.ts new file mode 100644 index 00000000000..1547af15fbe --- /dev/null +++ b/src/infra/browser-open.test.ts @@ -0,0 +1,47 @@ +import path from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { resolveBrowserOpenCommand } from "./browser-open.js"; +import { _resetWindowsInstallRootsForTests } from "./windows-install-roots.js"; + +afterEach(() => { + vi.restoreAllMocks(); + vi.unstubAllEnvs(); + _resetWindowsInstallRootsForTests(); +}); + +describe("resolveBrowserOpenCommand", () => { + it("does not resolve Windows browser launching through a relative SystemRoot", async () => { + vi.spyOn(process, "platform", "get").mockReturnValue("win32"); + vi.stubEnv("SystemRoot", ".\\fake-root"); + vi.stubEnv("windir", ".\\fake-windir"); + _resetWindowsInstallRootsForTests({ queryRegistryValue: () => null }); + + const resolved = await resolveBrowserOpenCommand(); + + const rundll32 = path.win32.join("C:\\Windows", "System32", "rundll32.exe"); + expect(resolved.argv).toEqual([rundll32, "url.dll,FileProtocolHandler"]); + expect(resolved.command).toBe(rundll32); + }); + + it("prefers the registry-backed Windows system root over process env", async () => { + vi.spyOn(process, "platform", "get").mockReturnValue("win32"); + vi.stubEnv("SystemRoot", "C:\\PoisonedWindows"); + _resetWindowsInstallRootsForTests({ + queryRegistryValue: (key, valueName) => { + if ( + key === "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" && + valueName === "SystemRoot" + ) { + return "D:\\Windows"; + } + return null; + }, + }); + + const resolved = await resolveBrowserOpenCommand(); + + const rundll32 = path.win32.join("D:\\Windows", "System32", "rundll32.exe"); + expect(resolved.argv).toEqual([rundll32, "url.dll,FileProtocolHandler"]); + expect(resolved.command).toBe(rundll32); + }); +}); diff --git a/src/infra/browser-open.ts b/src/infra/browser-open.ts index d48261aa7ad..13d29ab8671 100644 --- a/src/infra/browser-open.ts +++ b/src/infra/browser-open.ts @@ -1,6 +1,7 @@ import path from "node:path"; import { runCommandWithTimeout } from "../process/exec.js"; import { detectBinary } from "./detect-binary.js"; +import { getWindowsInstallRoots } from "./windows-install-roots.js"; import { isWSL } from "./wsl.js"; type BrowserOpenCommand = { @@ -23,7 +24,7 @@ function shouldSkipBrowserOpenInTests(): boolean { } function resolveWindowsRundll32Path(): string { - const systemRoot = process.env.SystemRoot?.trim() || process.env.windir?.trim() || "C:\\Windows"; + const { systemRoot } = getWindowsInstallRoots(); return path.win32.join(systemRoot, "System32", "rundll32.exe"); }