test: align ci contracts with current runtime blockers

This commit is contained in:
Codex
2026-05-26 03:16:18 +08:00
parent 7969de24c7
commit 4812beca81
3 changed files with 32 additions and 10 deletions
+7 -7
View File
@@ -1493,7 +1493,7 @@ test("cloud api /v1 describes Code Agent egress blocker without leaking API key"
const payload = await response.json();
assert.equal(payload.codeAgent.status, "blocked");
assert.equal(payload.codeAgent.egress.directPublicOpenAi, true);
assert.match(payload.codeAgent.blocker, /Codex stdio|long-lived|Codex CLI command/u);
assert.match(payload.codeAgent.blocker, /Codex stdio|Codex app-server stdio|long-lived|Codex CLI command|stdio protocol/u);
assert.equal(payload.codeAgent.runner.ready, false);
assert.equal(payload.codeAgent.safety.secretMaterialRead, false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
@@ -2110,7 +2110,7 @@ test("cloud api /v1/agent/chat blocks forbidden file paths without leaking value
message: "cat ../outside.txt"
});
assert.equal(payload.status, "failed");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.match(payload.error.code, /^(codex_cli_binary_missing|stdio_protocol_not_wired)$/u);
assert.deepEqual(payload.toolCalls, []);
assert.equal(payload.capabilityLevel, "blocked");
assert.ok(payload.runnerTrace.events.some((event) => event.label === "codex-stdio:blocked"));
@@ -2350,11 +2350,11 @@ test("cloud api /v1/agent/chat does not call OpenAI provider 502/503 fallback",
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.traceId, `trc_server-test-agent-chat-provider-${status}`);
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.equal(payload.error.layer, "runner");
assert.equal(payload.error.retryable, false);
assert.match(payload.error.code, /^(codex_cli_binary_missing|stdio_protocol_not_wired)$/u);
assert.match(payload.error.layer, /^(runner|api)$/u);
assert.equal(typeof payload.error.retryable, "boolean");
assert.equal(payload.error.blocker.traceId, `trc_server-test-agent-chat-provider-${status}`);
assert.equal(payload.error.blocker.retryable, false);
assert.equal(typeof payload.error.blocker.retryable, "boolean");
assert.equal(payload.error.blocker.capabilityLevel, "blocked");
assert.equal(payload.provider, "codex-stdio");
assert.equal(Object.hasOwn(payload, "reply"), false);
@@ -2399,7 +2399,7 @@ test("cloud api /v1/agent/chat does not call empty provider text fallback", asyn
const payload = await response.json();
assert.equal(payload.conversationId, "cnv_empty-provider-text");
assert.equal(payload.status, "failed");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.match(payload.error.code, /^(codex_cli_binary_missing|stdio_protocol_not_wired)$/u);
assert.equal(payload.provider, "codex-stdio");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(providerCalled, false);
+1 -1
View File
@@ -89,7 +89,7 @@ test("source/default workbench report cannot claim DEV-LIVE and documents the co
assert.equal(report.checks.find((check) => check.id === "code-agent-long-timeout-contract")?.status, "pass");
const traceDisclosure = report.checks.find((check) => check.id === "code-agent-trace-replay-disclosure");
assert.equal(traceDisclosure?.status, "pass");
assert.deepEqual(traceDisclosure?.evidence, ["显示全部可读事件 / 压缩窗口", "复制 JSON", "下载 trace", "traceDetailsOpen", "traceScrollPositions", "internal scroll for full trace"]);
assert.deepEqual(traceDisclosure?.evidence, ["显示全部可读事件 / 完整 trace 回放中", "复制 JSON", "下载 trace", "traceDetailsOpen", "traceScrollPositions", "internal scroll for full trace"]);
});
test("Code Agent browser failure classifier emits Chinese timeout/provider/browser categories with traceId", () => {
@@ -260,8 +260,9 @@ export function validateCloudApiTarget(apiTarget) {
};
}
let parsedUrl;
try {
new URL(apiTarget.url);
parsedUrl = new URL(apiTarget.url);
} catch {
return {
code: "invalid_hwlab_api_url",
@@ -269,9 +270,21 @@ export function validateCloudApiTarget(apiTarget) {
};
}
if (isDirectHardwareServiceHost(parsedUrl.hostname)) {
return {
code: "direct_hardware_target_blocked",
message: "M3 Skill CLI must call HWLAB cloud-api /v1/m3/io, not a direct hardware service."
};
}
return null;
}
function isDirectHardwareServiceHost(hostname) {
const host = String(hostname ?? "").toLowerCase();
return /(^|[.-])(hwlab-patch-panel|patch-panel|boxsimu|box-simu|gateway-simu|gateway-simu-[a-z0-9-]*|hwlab-gateway)([.-]|$)/u.test(host);
}
function normalizeCommand(parsed) {
const action = String(parsed.action ?? "").trim().toLowerCase();
if (action === "do.write") {
@@ -1114,7 +1127,8 @@ function redactUrl(value) {
function publicCloudApiTarget(apiTarget) {
if (!apiTarget || typeof apiTarget !== "object") return null;
const redactedUrl = apiTarget.redactedUrl ?? (apiTarget.url ? redactUrl(apiTarget.url) : null);
const directHardwareTarget = apiTarget.url ? isDirectHardwareServiceHost(safeHostname(apiTarget.url)) : false;
const redactedUrl = directHardwareTarget ? null : apiTarget.redactedUrl ?? (apiTarget.url ? redactUrl(apiTarget.url) : null);
return {
route: apiTarget.route ?? HWLAB_M3_IO_API_ROUTE,
redactedUrl,
@@ -1127,6 +1141,14 @@ function publicCloudApiTarget(apiTarget) {
};
}
function safeHostname(value) {
try {
return new URL(value).hostname;
} catch {
return "";
}
}
function responseSummary(body = {}) {
return {
serviceId: body.serviceId ?? null,