fix(coding-agent): confine browser executable probe to linux

The executable version probe added in ecb22957 ("validate Linux browser
executables") replaced the file-only check in resolveSystemChromium with
isChromiumExecutable, which spawns the candidate `--version` for every
platform. On Windows chrome.exe is a GUI-subsystem binary: `--version`
does not print to a detached stdout and can hand off to a running
instance, opening/activating the user's normal browser window, after
which the probe rejects the candidate and falls back to cached Chrome
for Testing.

Gate the spawn probe on process.platform === "linux" (its intended
platform, where non-Chromium PATH wrappers are the real risk) and trust
the executable-file check on Windows and macOS.

Fixes #8445
This commit is contained in:
roboomp
2026-08-13 16:28:57 +00:00
parent 326d24bd40
commit cf1ff14f5f
3 changed files with 37 additions and 0 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed the browser tool executable probe launching the user's installed GUI Chromium on Windows: the `--version` version probe from ecb22957 was Linux-scoped but ran for every platform candidate, so on Windows it could hand off to a running `chrome.exe`, open a normal browser window, then reject the candidate and fall back to cached Chrome for Testing. The probe is now confined to Linux ([#8445](https://github.com/can1357/oh-my-pi/issues/8445)).
## [17.3.0] - 2026-08-13
### Breaking Changes
@@ -204,6 +204,15 @@ function isExecutableFile(p: string): boolean {
async function isChromiumExecutable(p: string): Promise<boolean> {
if (!isExecutableFile(p)) return false;
// The version probe below launches the candidate. It exists to reject
// non-Chromium `chrome`/`chromium` wrapper scripts that appear on a Linux
// PATH (ecb22957, "validate Linux browser executables"). On Windows and
// macOS the candidates are fixed GUI application paths, not PATH wrappers,
// and executing them is harmful: a GUI `chrome.exe --version` does not print
// to a detached stdout and can hand off to the user's running instance,
// opening/activating a normal browser window (#8445). Confine the probe to
// Linux and trust the executable-file check elsewhere.
if (process.platform !== "linux") return true;
try {
const probeTimeoutMs = 3000;
const proc = Bun.spawn([p, "--version"], {
@@ -138,6 +138,30 @@ describe("browser executable selection", () => {
}
});
it("does not launch the candidate to probe its version on Windows (#8445)", async () => {
const tempDir = TempDir.createSync("@browser-probe-win32-");
try {
const marker = path.join(tempDir.path(), "gui-launched");
const fakeChrome = path.join(tempDir.path(), "chrome.exe");
// A GUI chrome.exe handoff: executing it has a side effect (this marker)
// but prints nothing a console version probe would accept.
await Bun.write(fakeChrome, `#!/bin/sh\ntouch "${marker}"\necho "activating existing window"\n`);
fs.chmodSync(fakeChrome, 0o755);
const platformDescriptor = Object.getOwnPropertyDescriptor(process, "platform");
Object.defineProperty(process, "platform", { value: "win32", configurable: true });
try {
await expect(chromiumExecutableProbeForTest(fakeChrome)).resolves.toBe(true);
} finally {
if (platformDescriptor) Object.defineProperty(process, "platform", platformDescriptor);
}
expect(fs.existsSync(marker)).toBe(false);
} finally {
await tempDir.remove();
}
});
it("honors PUPPETEER_EXECUTABLE_PATH before a detected Windows system Chrome", async () => {
const tempDir = TempDir.createSync("@browser-executable-");
try {