feat: harden enterprise control plane
This commit is contained in:
@@ -186,6 +186,41 @@ test("browser smoke runtime emits target url when objective contains a website",
|
||||
assert.match(result.executionSummary, /open_url/);
|
||||
});
|
||||
|
||||
test("browser smoke runtime normalizes bare domains from app control text", async () => {
|
||||
const result = await runRuntime(path.join(repoRoot, "scripts", "browser-control-smoke.mjs"), {
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-smoke-bare-domain",
|
||||
objective: "打开Chrome浏览器,访问 example.com,完成后回复一句任务小结。",
|
||||
context: {
|
||||
riskLevel: "medium",
|
||||
dryRun: true,
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetUrl, "https://example.com");
|
||||
assert.match(result.executionSummary, /open_url/);
|
||||
});
|
||||
|
||||
test("browser smoke runtime derives a YouTube search url from natural language playback requests", async () => {
|
||||
const result = await runRuntime(path.join(repoRoot, "scripts", "browser-control-smoke.mjs"), {
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-youtube-search",
|
||||
objective: "打开浏览器,用浏览器打开YouTube,找一个蔡徐坤的MV播放",
|
||||
context: {
|
||||
riskLevel: "medium",
|
||||
dryRun: true,
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(
|
||||
result.targetUrl,
|
||||
"https://www.youtube.com/results?search_query=%E8%94%A1%E5%BE%90%E5%9D%A4%20MV",
|
||||
);
|
||||
assert.match(result.executionSummary, /open_url/);
|
||||
});
|
||||
|
||||
test("browser smoke runtime can invoke configured browser automation command", async () => {
|
||||
const markerDir = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-automation-marker-"));
|
||||
const markerFile = path.join(markerDir, "automation.log");
|
||||
@@ -209,6 +244,7 @@ test("browser smoke runtime can invoke configured browser automation command", a
|
||||
BOSS_BROWSER_AUTOMATION_COMMAND: process.execPath,
|
||||
BOSS_BROWSER_AUTOMATION_ARGS_JSON: JSON.stringify([automationScript.scriptPath]),
|
||||
BOSS_BROWSER_AUTOMATION_SESSION: "boss-browser-test",
|
||||
BOSS_BROWSER_VISIBLE_OPEN_AFTER_AUTOMATION: "off",
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -226,6 +262,94 @@ test("browser smoke runtime can invoke configured browser automation command", a
|
||||
}
|
||||
});
|
||||
|
||||
test("browser smoke runtime still opens a visible browser after automation succeeds", async () => {
|
||||
const markerDir = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-visible-after-automation-"));
|
||||
const automationLog = path.join(markerDir, "automation.log");
|
||||
const openerMarker = path.join(markerDir, "visible-open.txt");
|
||||
let automationScript;
|
||||
let openerScript;
|
||||
try {
|
||||
automationScript = await writeBrowserAutomationScript(automationLog);
|
||||
openerScript = await writeOpenMarkerScript(openerMarker);
|
||||
const result = await runRuntimeWithServer(
|
||||
path.join(repoRoot, "scripts", "browser-control-smoke.mjs"),
|
||||
{
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-visible-after-automation",
|
||||
objective: "打开 https://example.com 看一下首页",
|
||||
context: {
|
||||
riskLevel: "medium",
|
||||
dryRun: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
env: {
|
||||
BOSS_BROWSER_AUTOMATION_MODE: "playwright",
|
||||
BOSS_BROWSER_AUTOMATION_COMMAND: process.execPath,
|
||||
BOSS_BROWSER_AUTOMATION_ARGS_JSON: JSON.stringify([automationScript.scriptPath]),
|
||||
BOSS_BROWSER_OPEN_COMMAND: process.execPath,
|
||||
BOSS_BROWSER_OPEN_ARGS_JSON: JSON.stringify([openerScript.scriptPath]),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.match(result.replyBody, /Boss Automated Title/);
|
||||
assert.match(result.executionSummary, /browser_automation_executed\+open_url_executed/);
|
||||
assert.equal(await fs.readFile(openerMarker, "utf8"), "https://example.com");
|
||||
} finally {
|
||||
if (automationScript?.scriptDir) {
|
||||
await fs.rm(automationScript.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
if (openerScript?.scriptDir) {
|
||||
await fs.rm(openerScript.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(markerDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("browser smoke runtime falls back to opener when browser automation fails", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-automation-fallback-"));
|
||||
const openerMarker = path.join(marker, "opened.txt");
|
||||
let openerScript;
|
||||
try {
|
||||
const failingAutomationPath = path.join(marker, "failing-automation.mjs");
|
||||
await fs.writeFile(failingAutomationPath, "process.stderr.write('automation failed'); process.exit(1);", "utf8");
|
||||
openerScript = await writeOpenMarkerScript(openerMarker);
|
||||
const result = await runRuntime(
|
||||
path.join(repoRoot, "scripts", "browser-control-smoke.mjs"),
|
||||
{
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-automation-fallback",
|
||||
objective: "打开 example.com 看一下首页",
|
||||
context: {
|
||||
riskLevel: "medium",
|
||||
dryRun: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
env: {
|
||||
BOSS_BROWSER_AUTOMATION_MODE: "playwright",
|
||||
BOSS_BROWSER_AUTOMATION_COMMAND: process.execPath,
|
||||
BOSS_BROWSER_AUTOMATION_ARGS_JSON: JSON.stringify([failingAutomationPath]),
|
||||
BOSS_BROWSER_OPEN_COMMAND: process.execPath,
|
||||
BOSS_BROWSER_OPEN_ARGS_JSON: JSON.stringify([openerScript.scriptPath]),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetUrl, "https://example.com");
|
||||
assert.match(result.executionSummary, /open_url_executed/);
|
||||
assert.equal(await fs.readFile(openerMarker, "utf8"), "https://example.com");
|
||||
} finally {
|
||||
if (openerScript?.scriptDir) {
|
||||
await fs.rm(openerScript.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(marker, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("browser smoke runtime auto-detects bundled playwright wrapper and uses request id as session", async () => {
|
||||
const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-autodetect-"));
|
||||
const logFile = path.join(tmpRoot, "wrapper.log");
|
||||
@@ -246,6 +370,7 @@ test("browser smoke runtime auto-detects bundled playwright wrapper and uses req
|
||||
{
|
||||
env: {
|
||||
CODEX_HOME: codexHome,
|
||||
BOSS_BROWSER_VISIBLE_OPEN_AFTER_AUTOMATION: "off",
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -560,6 +685,84 @@ test("browser smoke runtime can execute an injected url opener when not dry-run"
|
||||
}
|
||||
});
|
||||
|
||||
test("browser smoke runtime opens Chrome when app control text asks for Chrome", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-chrome-open-"));
|
||||
const markerFile = path.join(marker, "open-args.json");
|
||||
let openerCommand;
|
||||
try {
|
||||
openerCommand = await writeArgumentMarkerCommand(markerFile, "open");
|
||||
const result = await runRuntime(
|
||||
path.join(repoRoot, "scripts", "browser-control-smoke.mjs"),
|
||||
{
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-open-chrome",
|
||||
objective: "打开Chrome浏览器,访问 example.com,完成后回复一句任务小结。",
|
||||
context: { dryRun: false },
|
||||
},
|
||||
{
|
||||
env: {
|
||||
BOSS_BROWSER_OPEN_COMMAND: openerCommand.scriptPath,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetUrl, "https://example.com");
|
||||
assert.deepEqual(JSON.parse(await fs.readFile(markerFile, "utf8")), [
|
||||
"-a",
|
||||
"Google Chrome",
|
||||
"https://example.com",
|
||||
]);
|
||||
} finally {
|
||||
if (openerCommand?.scriptDir) {
|
||||
await fs.rm(openerCommand.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(marker, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("browser smoke runtime uses osascript for real Chrome URL opens on macOS", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-browser-chrome-osascript-"));
|
||||
const osascriptMarker = path.join(marker, "osascript-args.json");
|
||||
let osascriptCommand;
|
||||
try {
|
||||
osascriptCommand = await writeArgumentMarkerCommand(osascriptMarker, "osascript");
|
||||
const failingOpenPath = path.join(osascriptCommand.scriptDir, "open");
|
||||
await fs.writeFile(
|
||||
failingOpenPath,
|
||||
"#!/usr/bin/env node\nprocess.stderr.write('open should not be used for Chrome URL opens'); process.exit(1);\n",
|
||||
"utf8",
|
||||
);
|
||||
await fs.chmod(failingOpenPath, 0o755);
|
||||
|
||||
const result = await runRuntime(
|
||||
path.join(repoRoot, "scripts", "browser-control-smoke.mjs"),
|
||||
{
|
||||
requestKind: "browser_control",
|
||||
requestId: "browser-open-chrome-osascript",
|
||||
objective: "打开Chrome浏览器,访问 example.com,完成后回复一句任务小结。",
|
||||
context: { dryRun: false },
|
||||
},
|
||||
{
|
||||
env: {
|
||||
PATH: `${osascriptCommand.scriptDir}:${process.env.PATH}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetUrl, "https://example.com");
|
||||
const args = JSON.parse(await fs.readFile(osascriptMarker, "utf8"));
|
||||
assert.match(args.join(" "), /Google Chrome/);
|
||||
assert.match(args.join(" "), /https:\/\/example\.com/);
|
||||
} finally {
|
||||
if (osascriptCommand?.scriptDir) {
|
||||
await fs.rm(osascriptCommand.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(marker, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("computer use smoke runtime can execute an injected app opener when not dry-run", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-computer-open-"));
|
||||
let openerScript;
|
||||
@@ -687,6 +890,136 @@ test("computer use smoke runtime defaults to open -a style args for macOS opener
|
||||
}
|
||||
});
|
||||
|
||||
test("computer use smoke runtime maps Chrome to Google Chrome for macOS app opens", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-computer-open-chrome-"));
|
||||
let openerCommand;
|
||||
const markerFile = path.join(marker, "argv.json");
|
||||
try {
|
||||
openerCommand = await writeArgumentMarkerCommand(markerFile, "open");
|
||||
const result = await new Promise((resolve, reject) => {
|
||||
const child = spawn(process.execPath, [path.join(repoRoot, "scripts", "computer-use-smoke.mjs")], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
BOSS_COMPUTER_USE_MODE: "open",
|
||||
BOSS_COMPUTER_USE_OPEN_APP_COMMAND: openerCommand.scriptPath,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk) => {
|
||||
stdout += chunk;
|
||||
});
|
||||
child.stderr.on("data", (chunk) => {
|
||||
stderr += chunk;
|
||||
});
|
||||
child.on("error", reject);
|
||||
child.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(stderr.trim() || `exit code ${code}`));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
resolve(JSON.parse(stdout.trim().split(/\r?\n/).at(-1) || ""));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
child.stdin.write(
|
||||
JSON.stringify({
|
||||
requestKind: "desktop_control",
|
||||
requestId: "computer-open-chrome",
|
||||
objective: "打开Chrome浏览器",
|
||||
context: { dryRun: false },
|
||||
}),
|
||||
);
|
||||
child.stdin.end();
|
||||
});
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetApp, "Chrome");
|
||||
assert.equal(result.automationTargetApp, "Google Chrome");
|
||||
const argv = JSON.parse(await fs.readFile(markerFile, "utf8"));
|
||||
assert.deepEqual(argv, ["-a", "Google Chrome"]);
|
||||
} finally {
|
||||
if (openerCommand?.scriptDir) {
|
||||
await fs.rm(openerCommand.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(marker, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("computer use smoke runtime opens browser urls directly without keystroke automation", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-computer-open-browser-url-"));
|
||||
let openerCommand;
|
||||
const markerFile = path.join(marker, "argv.json");
|
||||
try {
|
||||
openerCommand = await writeArgumentMarkerCommand(markerFile, "open");
|
||||
const result = await new Promise((resolve, reject) => {
|
||||
const child = spawn(process.execPath, [path.join(repoRoot, "scripts", "computer-use-smoke.mjs")], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
BOSS_COMPUTER_USE_MODE: "osascript",
|
||||
BOSS_COMPUTER_USE_OPEN_APP_COMMAND: openerCommand.scriptPath,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk) => {
|
||||
stdout += chunk;
|
||||
});
|
||||
child.stderr.on("data", (chunk) => {
|
||||
stderr += chunk;
|
||||
});
|
||||
child.on("error", reject);
|
||||
child.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(stderr.trim() || `exit code ${code}`));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
resolve(JSON.parse(stdout.trim().split(/\r?\n/).at(-1) || ""));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
child.stdin.write(
|
||||
JSON.stringify({
|
||||
requestKind: "desktop_control",
|
||||
requestId: "computer-open-browser-url",
|
||||
objective: "打开软件 Chrome,输入“https://example.com”,回车",
|
||||
context: { dryRun: false },
|
||||
}),
|
||||
);
|
||||
child.stdin.end();
|
||||
});
|
||||
|
||||
assert.equal(result.status, "completed");
|
||||
assert.equal(result.targetApp, "Chrome");
|
||||
assert.equal(result.automationTargetApp, "Google Chrome");
|
||||
assert.equal(result.targetUrl, "https://example.com");
|
||||
assert.match(result.executionSummary, /open_app_url_executed/);
|
||||
const argv = JSON.parse(await fs.readFile(markerFile, "utf8"));
|
||||
assert.deepEqual(argv, ["-a", "Google Chrome", "https://example.com"]);
|
||||
} finally {
|
||||
if (openerCommand?.scriptDir) {
|
||||
await fs.rm(openerCommand.scriptDir, { recursive: true, force: true });
|
||||
}
|
||||
await fs.rm(marker, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("computer use smoke runtime can prepend configured open -a style args", async () => {
|
||||
const marker = await fs.mkdtemp(path.join(os.tmpdir(), "boss-computer-open-default-"));
|
||||
let openerCommand;
|
||||
|
||||
Reference in New Issue
Block a user