feat: harden enterprise control plane
This commit is contained in:
@@ -39,8 +39,53 @@ function normalizePayload(raw) {
|
||||
}
|
||||
|
||||
function extractTargetUrl(objective) {
|
||||
const match = String(objective || "").match(/https?:\/\/[^\s,。;、))]+/i);
|
||||
return match?.[0] || undefined;
|
||||
const text = String(objective || "");
|
||||
const fullUrl = text.match(/https?:\/\/[^\s,。;、))]+/i)?.[0];
|
||||
if (fullUrl) {
|
||||
return fullUrl;
|
||||
}
|
||||
|
||||
const bareDomain = text.match(
|
||||
/(?:访问|打开|进入|看一下|visit|open)?\s*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}(?:\/[^\s,。;、))]*)?)/i,
|
||||
)?.[1];
|
||||
return bareDomain ? `https://${bareDomain}` : undefined;
|
||||
}
|
||||
|
||||
function cleanupSearchQuery(value) {
|
||||
return String(value || "")
|
||||
.replace(/打开\s*(?:youtube|油管)/gi, " ")
|
||||
.replace(/(?:youtube|油管)/gi, " ")
|
||||
.replace(/用浏览器打开/gi, " ")
|
||||
.replace(/打开浏览器/gi, " ")
|
||||
.replace(/找一个|找一下|搜索|搜一下|搜|播放/gi, " ")
|
||||
.replace(/的\s*mv/gi, " MV")
|
||||
.replace(/mv/gi, " MV")
|
||||
.replace(/[,。;;、]/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function deriveYouTubeSearchUrl(objective) {
|
||||
const text = String(objective || "").trim();
|
||||
if (!/(youtube|油管)/i.test(text)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const queryPatterns = [
|
||||
/(?:找一个|找一下|搜索|搜一下|搜|播放)\s*([^,。;;]+)/i,
|
||||
/(?:youtube|油管)\s*([^,。;;]+)/i,
|
||||
];
|
||||
for (const pattern of queryPatterns) {
|
||||
const query = cleanupSearchQuery(text.match(pattern)?.[1]);
|
||||
if (query) {
|
||||
return `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}`;
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackQuery = cleanupSearchQuery(text);
|
||||
return fallbackQuery
|
||||
? `https://www.youtube.com/results?search_query=${encodeURIComponent(fallbackQuery)}`
|
||||
: "https://www.youtube.com";
|
||||
}
|
||||
|
||||
async function writeArtifact(payload) {
|
||||
@@ -84,6 +129,55 @@ function parseArgsJson(value) {
|
||||
}
|
||||
}
|
||||
|
||||
function detectRequestedBrowserApp(objective) {
|
||||
const text = String(objective || "").toLowerCase();
|
||||
if (text.includes("chrome") || text.includes("谷歌浏览器")) {
|
||||
return "Google Chrome";
|
||||
}
|
||||
if (text.includes("safari")) {
|
||||
return "Safari";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveBrowserOpenArgs(command, objective) {
|
||||
const configured =
|
||||
parseArgsJson(process.env.BOSS_BROWSER_OPEN_ARGS_JSON) ??
|
||||
parseArgs(process.env.BOSS_BROWSER_OPEN_ARGS);
|
||||
if (configured.length > 0) {
|
||||
return configured;
|
||||
}
|
||||
|
||||
const requestedApp = detectRequestedBrowserApp(objective);
|
||||
const commandName = path.basename(command || "").toLowerCase();
|
||||
return requestedApp && commandName === "open" ? ["-a", requestedApp] : [];
|
||||
}
|
||||
|
||||
function escapeAppleScriptString(value) {
|
||||
return String(value || "").replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
async function openTargetUrl(targetUrl, objective) {
|
||||
const commandOverride = String(process.env.BOSS_BROWSER_OPEN_COMMAND || "").trim();
|
||||
const command = commandOverride || "open";
|
||||
const requestedApp = detectRequestedBrowserApp(objective);
|
||||
|
||||
if (!commandOverride && process.platform === "darwin" && requestedApp) {
|
||||
const app = escapeAppleScriptString(requestedApp);
|
||||
const url = escapeAppleScriptString(targetUrl);
|
||||
const script = [
|
||||
`tell application "${app}" to activate`,
|
||||
`tell application "${app}" to open location "${url}"`,
|
||||
].join("\n");
|
||||
await runCommand("osascript", ["-e", script]);
|
||||
return "osascript_open_url_executed";
|
||||
}
|
||||
|
||||
const prefixArgs = resolveBrowserOpenArgs(command, objective);
|
||||
await runCommand(command, [...prefixArgs, targetUrl]);
|
||||
return "open_url_executed";
|
||||
}
|
||||
|
||||
function getBrowserAutomationMode() {
|
||||
const raw = String(process.env.BOSS_BROWSER_AUTOMATION_MODE || "").trim().toLowerCase();
|
||||
if (raw === "off" || raw === "fetch" || raw === "playwright" || raw === "auto") {
|
||||
@@ -92,6 +186,11 @@ function getBrowserAutomationMode() {
|
||||
return "auto";
|
||||
}
|
||||
|
||||
function shouldOpenVisibleBrowserAfterAutomation() {
|
||||
const raw = String(process.env.BOSS_BROWSER_VISIBLE_OPEN_AFTER_AUTOMATION || "").trim().toLowerCase();
|
||||
return !["0", "false", "off", "no"].includes(raw);
|
||||
}
|
||||
|
||||
function resolveCodexHome() {
|
||||
return String(process.env.CODEX_HOME || "").trim() || path.join(process.env.HOME || "", ".codex");
|
||||
}
|
||||
@@ -195,7 +294,7 @@ const objective =
|
||||
typeof payload.objective === "string" && payload.objective.trim()
|
||||
? payload.objective.trim()
|
||||
: "浏览器控制 smoke 链路正常";
|
||||
const targetUrl = extractTargetUrl(objective);
|
||||
const targetUrl = extractTargetUrl(objective) || deriveYouTubeSearchUrl(objective);
|
||||
const riskLevel =
|
||||
typeof payload.context?.riskLevel === "string" && payload.context.riskLevel.trim()
|
||||
? payload.context.riskLevel.trim()
|
||||
@@ -209,23 +308,27 @@ const automationMode =
|
||||
? "playwright"
|
||||
: "fetch"
|
||||
: configuredAutomationMode;
|
||||
const automatedTitle =
|
||||
targetUrl && !dryRun && automationMode === "playwright"
|
||||
? await runBrowserAutomation(targetUrl, currentRequestId)
|
||||
: undefined;
|
||||
let automationError;
|
||||
let automatedTitle;
|
||||
if (targetUrl && !dryRun && automationMode === "playwright") {
|
||||
try {
|
||||
automatedTitle = await runBrowserAutomation(targetUrl, currentRequestId);
|
||||
} catch (error) {
|
||||
automationError = error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
}
|
||||
const pageTitle =
|
||||
automatedTitle ||
|
||||
(automationMode !== "off" ? await inspectPageTitle(targetUrl) : undefined);
|
||||
if (targetUrl && !dryRun) {
|
||||
if (automationMode === "playwright" && automatedTitle) {
|
||||
action = "browser_automation_executed";
|
||||
if (shouldOpenVisibleBrowserAfterAutomation()) {
|
||||
const visibleAction = await openTargetUrl(targetUrl, objective);
|
||||
action = `${action}+${visibleAction}`;
|
||||
}
|
||||
} else {
|
||||
const command = String(process.env.BOSS_BROWSER_OPEN_COMMAND || "").trim() || "open";
|
||||
const prefixArgs =
|
||||
parseArgsJson(process.env.BOSS_BROWSER_OPEN_ARGS_JSON) ??
|
||||
parseArgs(process.env.BOSS_BROWSER_OPEN_ARGS);
|
||||
await runCommand(command, [...prefixArgs, targetUrl]);
|
||||
action = "open_url_executed";
|
||||
action = await openTargetUrl(targetUrl, objective);
|
||||
}
|
||||
}
|
||||
const artifacts = await writeArtifact({
|
||||
@@ -246,8 +349,8 @@ writeJson({
|
||||
? `浏览器控制已完成:${objective}。页面标题:${pageTitle}`
|
||||
: `浏览器控制已完成:${objective}`,
|
||||
executionSummary: pageTitle
|
||||
? `${action} completed (risk=${riskLevel}, title=${pageTitle})`
|
||||
: `${action} completed (risk=${riskLevel})`,
|
||||
? `${action} completed (risk=${riskLevel}, title=${pageTitle}${automationError ? ", automationFallback=true" : ""})`
|
||||
: `${action} completed (risk=${riskLevel}${automationError ? ", automationFallback=true" : ""})`,
|
||||
targetUrl,
|
||||
artifacts,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user