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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user