Files
openclaw/src/secrets/test-node-command.test-support.ts
Hiroshi Tanaka 52f412bf17 fix(browser): tab creation steals window focus during agent automation (#105356)
* fix(browser): tab creation steals window focus during agent automation

Agent-created tabs inherited CDP's foreground default: direct CDP
Target.createTarget omitted the background flag, and the extension
relay's createTab defaulted to active:true, so every agent tab open
activated the new tab (and, on the extension driver, focused the
window), interrupting whatever the human was doing in that browser.

Direct CDP tab creation now requests background:true (agent tab
ownership/selection is target-id based and never depended on
activation), and the extension relay defaults an omitted background
to true while preserving an explicit background:false, matching the
Codex/Claude-in-Chrome model the extension driver mirrors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(browser): keep focus fix LOC-neutral

Preserve background tab creation while keeping the oversized CDP and relay modules within the current LOC ratchet.\n\nCodex-Session: 019f5e93-780a-7350-88f9-1986cdb64914

* fix(browser): honor explicit CDP focus requests

Keep background-by-default automation while treating Target.createTarget focus=true as an explicit foreground request in the extension relay.

Codex-Session: 019f5e93-780a-7350-88f9-1986cdb64914

* fix(browser): preserve explicit CDP focus semantics

Apply the background-by-default automation policy only when focus is omitted, preserving focus=false foreground-tab requests as well as focus=true.

Codex-Session: 019f5e93-780a-7350-88f9-1986cdb64914

* fix(browser): preserve create target window focus

Carry the resolved CDP focus intent through the extension relay and explicitly focus the containing Chrome window when requested.\n\nCodex-Session: 019f5e93-780a-7350-88f9-1986cdb64914

* style(browser): refresh relay import order

* test(secrets): use secure node exec fixtures

* test(doctor): secure exec secret fixture

* test(doctor): retain narrowed temp path

* test(secrets): secure remaining exec fixtures

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 21:35:40 -07:00

44 lines
1.5 KiB
TypeScript

import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
function shellQuote(value: string): string {
return `'${value.replaceAll("'", `'"'"'`)}'`;
}
export async function withSecureTestNodeCommand<T>(
run: (command: string) => Promise<T>,
): Promise<T> {
if (process.platform === "win32") {
return await run(process.execPath);
}
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-node-"));
const command = path.join(rootDir, "node");
try {
await fs.chmod(rootDir, 0o700);
await fs.writeFile(command, `#!/bin/sh\nexec ${shellQuote(process.execPath)} "$@"\n`, {
mode: 0o700,
});
return await run(command);
} finally {
await fs.rm(rootDir, { recursive: true, force: true });
}
}
export async function withSecureTestNodeExecPath<T>(run: () => Promise<T>): Promise<T> {
return await withSecureTestNodeCommand(async (command) => {
const original = Object.getOwnPropertyDescriptor(process, "execPath");
if (!original) {
throw new Error("process.execPath descriptor is unavailable");
}
// Plugin ${node} materialization reads process.execPath directly. Keep that global swap
// bounded to one awaited test and always restore it before deleting the wrapper.
Object.defineProperty(process, "execPath", { ...original, value: command });
try {
return await run();
} finally {
Object.defineProperty(process, "execPath", original);
}
});
}