Files
pikasTech-HWLAB/internal/cloud/server.test.mjs
T

4907 lines
199 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { createServer as createRawHttpServer } from "node:http";
import { createServer as createRawTcpServer } from "node:net";
import { chmod, mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { createCloudApiServer as createRawCloudApiServer } from "./server.mjs";
import { validateCodeAgentChatSchema } from "./code-agent-chat.mjs";
import { createCodexStdioSessionManager } from "./codex-stdio-session.mjs";
import { createCodeAgentTraceStore } from "./code-agent-trace-store.mjs";
import { createCloudRuntimeStore } from "../db/runtime-store.mjs";
import { classifyCodexRunnerCapability } from "../../scripts/src/code-agent-response-contract.mjs";
import {
RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED,
RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED,
RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED,
RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED,
RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED
} from "../db/runtime-store.mjs";
import { HWLAB_M3_IO_CAPABILITY_LEVELS } from "../../skills/hwlab-agent-runtime/scripts/src/m3-io-skill-client.mjs";
const CODEX_STDIO_FEASIBILITY_BLOCKERS = new Set([
"codex_cli_binary_missing",
"codex_stdio_supervisor_disabled",
"codex_stdio_egress_boundary"
]);
function createHttpServer(...args) {
return trackTestServer(createRawHttpServer(...args));
}
function createTcpServer(...args) {
return trackTestServer(createRawTcpServer(...args));
}
function createCloudApiServer(...args) {
return trackTestServer(createRawCloudApiServer(...args));
}
function trackTestServer(server) {
const sockets = new Set();
server.on("connection", (socket) => {
sockets.add(socket);
socket.on("close", () => sockets.delete(socket));
});
const close = server.close.bind(server);
server.close = (callback) => {
server.closeIdleConnections?.();
for (const socket of sockets) socket.destroy();
return close(callback);
};
return server;
}
function assertCodexStdioFeasibilityBlocker(value, label = "codex stdio blocker") {
assert.equal(CODEX_STDIO_FEASIBILITY_BLOCKERS.has(value), true, `${label}: ${value}`);
}
function missingCodexCommandEnv(overrides = {}) {
return {
PATH: "",
HWLAB_CODE_AGENT_CODEX_COMMAND: path.join(os.tmpdir(), `hwlab-${process.pid}-missing-codex`),
...overrides
};
}
test("cloud api exposes /health, /health/live, and /live probes", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
delete process.env.HWLAB_CLOUD_DB_URL;
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_CODE_AGENT_PROVIDER: "codex-cli",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: "/tmp/hwlab-missing-codex"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const health = await fetch(`http://127.0.0.1:${port}/health`);
assert.equal(health.status, 200);
const healthPayload = await health.json();
assert.equal(healthPayload.serviceId, "hwlab-cloud-api");
assert.equal(healthPayload.environment, "dev");
assert.equal(healthPayload.status, "degraded");
assert.equal(healthPayload.commit.id.length > 0, true);
assert.equal(healthPayload.image.reference.length > 0, true);
assert.equal(typeof healthPayload.revision, "string");
assert.equal(typeof healthPayload.build, "object");
assert.equal(Object.hasOwn(healthPayload.build, "createdAt"), true);
assert.equal(healthPayload.service.id, "hwlab-cloud-api");
assert.equal(healthPayload.db.status, "blocked");
assert.equal(healthPayload.db.connected, false);
assert.equal(healthPayload.db.liveConnected, false);
assert.equal(healthPayload.db.liveDbEvidence, false);
assert.equal(healthPayload.db.connectionAttempted, false);
assert.equal(healthPayload.db.connectionResult, "not_attempted_missing_env");
assert.equal(healthPayload.db.endpointSource, "secret-url-host");
assert.equal(healthPayload.db.endpoint.authoritative.source, "secret-url-host");
assert.equal(healthPayload.db.endpoint.authoritative.env, "HWLAB_CLOUD_DB_URL");
assert.equal(healthPayload.db.endpoint.authoritative.usedForProbe, true);
assert.equal(healthPayload.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(healthPayload.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(healthPayload.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(healthPayload.db.redaction.valuesRedacted, true);
assert.equal(healthPayload.db.redaction.secretMaterialRead, false);
assert.equal(healthPayload.db.safety.liveDbEvidence, false);
assert.equal(healthPayload.runtime.durable, false);
assert.equal(healthPayload.runtime.status, "degraded");
assert.equal(healthPayload.runtime.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(healthPayload.runtime.durabilityContract.blockedLayer, "adapter");
assert.equal(healthPayload.readiness.contractVersion, "v3");
assert.equal(healthPayload.readiness.durability.status, "blocked");
assert.equal(healthPayload.readiness.durability.dbLiveEvidenceObserved, false);
assert.equal(healthPayload.readiness.durability.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(healthPayload.readiness.durability.blockedLayer, "adapter");
assert.equal(healthPayload.readiness.provider.status, "blocked");
assert.equal(healthPayload.readiness.provider.ready, false);
assert.equal(healthPayload.readiness.provider.blocker, "provider_config_blocked");
assert.equal(healthPayload.readiness.dbDurable.status, "blocked");
assert.equal(healthPayload.readiness.dbDurable.ready, false);
assert.equal(healthPayload.readiness.sessionRunner.status, "blocked");
assert.equal(healthPayload.readiness.sessionRunner.ready, false);
assert.equal(healthPayload.readiness.sessionRunner.codexStdio, true);
assert.equal(healthPayload.readiness.sessionRunner.durableSession, false);
assert.equal(healthPayload.readiness.sessionRunner.longLivedSession, false);
assert.equal(healthPayload.readiness.codexStdio.status, "blocked");
assert.equal(healthPayload.readiness.codexStdio.ready, false);
assertCodexStdioFeasibilityBlocker(healthPayload.readiness.codexStdio.blocker);
assert.equal(healthPayload.readiness.codeAgent.providerReady, false);
assert.equal(healthPayload.readiness.codeAgent.durableDbReady, false);
assert.equal(healthPayload.readiness.codeAgent.sessionRunnerReady, false);
assert.equal(healthPayload.readiness.codeAgent.codexStdioFeasible, false);
assert.deepEqual(healthPayload.readiness.codeAgent.currentBlockers.slice(0, 2), [
"provider_config_blocked",
"runtime_durable_adapter_missing"
]);
assertCodexStdioFeasibilityBlocker(healthPayload.readiness.codeAgent.currentBlockers[2], "readiness current blocker");
assert.equal(healthPayload.readiness.codeAgent.secretMaterialRead, false);
assert.equal(healthPayload.codeAgent.status, "blocked");
assert.equal(healthPayload.codeAgent.agentKind, "codex-stdio-blocked");
assert.equal(healthPayload.codeAgent.partialReady, false);
assert.match(healthPayload.codeAgent.blocker, /Codex CLI command/u);
assert.equal(healthPayload.codeAgent.reason, "codex_cli_binary_missing");
assert.equal(healthPayload.codeAgent.runner.kind, "codex-app-server-stdio-runner");
assert.equal(healthPayload.codeAgent.runner.ready, false);
assert.equal(healthPayload.codeAgent.capabilityLevel, "blocked");
assert.equal(healthPayload.codeAgent.sessionRegistry.status, "available");
assert.equal(healthPayload.codeAgent.longLivedSessionGate.status, "blocked");
assert.ok(healthPayload.codeAgent.longLivedSessionGate.blockers.some((blocker) => blocker.code === "codex_cli_binary_missing"));
assert.ok(healthPayload.codeAgent.longLivedSessionGate.blockers.some((blocker) => blocker.code === "provider_token_boundary"));
assert.equal(healthPayload.codeAgent.codexStdio.runtimeContract.binary.status, "missing");
assert.equal(healthPayload.codeAgent.codexStdio.runtimeContract.stdioProtocol.status, "blocked");
assert.equal(healthPayload.codeAgent.codexStdio.runtimeContract.lifecycleSupervisor.status, "present");
assert.equal(healthPayload.codeAgent.codexStdio.runtimeContract.cancelReapTraceReadiness.status, "ready");
assert.ok(healthPayload.codeAgent.codexStdio.blockerCodes.includes("codex_cli_binary_missing"));
assert.ok(healthPayload.codeAgent.codexStdio.blockerCodes.includes("stdio_protocol_not_wired"));
assert.ok(healthPayload.codeAgent.codexStdio.blockerCodes.includes("provider_token_boundary"));
assert.deepEqual(healthPayload.codeAgent.missingEnv, ["OPENAI_API_KEY"]);
assert.equal(healthPayload.codeAgent.secretRefs[0].secretName, "hwlab-code-agent-provider");
assert.equal(healthPayload.codeAgent.secretRefs[0].secretKey, "openai-api-key");
assert.equal(healthPayload.codeAgent.secretRefs[0].redacted, true);
assert.equal(healthPayload.codeAgent.egress.directPublicOpenAi, false);
assert.equal(healthPayload.codeAgent.safety.secretMaterialRead, false);
assert.equal(JSON.stringify(healthPayload.codeAgent).includes("sk-"), false);
assert.deepEqual(healthPayload.db.missingEnv, ["HWLAB_CLOUD_DB_URL", "HWLAB_CLOUD_DB_SSL_MODE"]);
assert.equal(healthPayload.db.secretRefs[0].secretName, "hwlab-cloud-api-dev-db");
assert.equal(healthPayload.db.secretRefs[0].redacted, true);
const healthLive = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(healthLive.status, 200);
const healthLivePayload = await healthLive.json();
assert.equal(healthLivePayload.serviceId, "hwlab-cloud-api");
assert.equal(healthLivePayload.status, "degraded");
assert.equal(healthLivePayload.commit.id.length > 0, true);
assert.equal(typeof healthLivePayload.build, "object");
assert.equal(healthLivePayload.db.ready, false);
assert.equal(healthLivePayload.codeAgent.status, "blocked");
assert.equal(healthLivePayload.codeAgent.ready, false);
assert.equal(healthLivePayload.codeAgent.partialReady, false);
assert.equal(healthLivePayload.codeAgent.capabilityLevel, "blocked");
const readiness = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(readiness.status, 200);
assert.equal((await readiness.json()).status, "degraded");
const live = await fetch(`http://127.0.0.1:${port}/live`);
assert.equal(live.status, 200);
assert.equal((await live.json()).status, "live");
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
}
});
test("cloud api aggregates live HWLAB build times from health and controlled deploy/catalog metadata", async () => {
const healthByPath = new Map([
["/hwlab-cloud-web/health/live", {
serviceId: "hwlab-cloud-web",
status: "ok",
revision: "webabcdef123456",
commit: { id: "webabcdef123456", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-cloud-web:webabcd",
tag: "webabcd",
digest: "sha256:" + "1".repeat(64)
},
build: {
createdAt: "2026-05-23T02:10:00.000Z",
metadataSource: "runtime-env:HWLAB_BUILD_CREATED_AT"
}
}],
["/hwlab-agent-mgr/health/live", {
serviceId: "hwlab-agent-mgr",
status: "ok",
revision: "48dfbf9",
commit: { id: "48dfbf9", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:48dfbf9",
tag: "48dfbf9",
digest: "sha256:" + "2".repeat(64)
}
}],
["/hwlab-agent-skills/health/live", {
serviceId: "hwlab-agent-skills",
status: "ok",
revision: "skillsabcdef123456",
commit: { id: "skillsabcdef123456", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
tag: "skillsabcd",
digest: "sha256:" + "5".repeat(64)
}
}],
["/external/health", {
serviceId: "postgres",
status: "ok",
image: {
reference: "postgres:16",
tag: "16"
}
}]
]);
const liveBuildMetadata = {
deployManifest: {
services: [
{
serviceId: "hwlab-cloud-web",
image: "127.0.0.1:5000/hwlab/hwlab-cloud-web:webcat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
},
{
serviceId: "hwlab-agent-mgr",
image: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:3df89fe",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
},
{
serviceId: "hwlab-agent-skills",
image: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1,
env: {
HWLAB_COMMIT_ID: "skillsabcdef123456",
HWLAB_IMAGE: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
HWLAB_IMAGE_TAG: "skillsabcd",
HWLAB_BUILD_CREATED_AT: "2026-05-23T05:30:00.000Z",
HWLAB_BUILD_SOURCE: "deploy-env-test"
}
},
{
serviceId: "hwlab-agent-worker",
image: "127.0.0.1:5000/hwlab/hwlab-agent-worker:workcat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 0
},
{
serviceId: "hwlab-edge-proxy",
image: "127.0.0.1:5000/hwlab/hwlab-edge-proxy:edgecat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health",
replicas: 1
},
{
serviceId: "hwlab-extra-lab",
image: "127.0.0.1:5000/hwlab/hwlab-extra-lab:extracat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
}
]
},
artifactCatalog: {
services: [
{
serviceId: "hwlab-agent-mgr",
commitId: "3df89fe",
image: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:3df89fe",
imageTag: "3df89fe",
digest: "sha256:" + "3".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: "2026-05-23T04:20:00.000Z",
buildSource: "artifact-catalog-test"
},
{
serviceId: "hwlab-agent-skills",
commitId: "skillsabcdef123456",
image: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
imageTag: "skillsabcd",
digest: "sha256:" + "5".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: null,
buildSource: null
},
{
serviceId: "hwlab-extra-lab",
commitId: "extracatabcdef123456",
image: "127.0.0.1:5000/hwlab/hwlab-extra-lab:extracat",
imageTag: "extracat",
digest: "sha256:" + "4".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: "2026-05-23T03:00:00.000Z",
buildSource: "artifact-catalog-test"
}
]
}
};
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_COMMIT_ID: "apiabcdef123456",
HWLAB_IMAGE: "127.0.0.1:5000/hwlab/hwlab-cloud-api:apiabcd",
HWLAB_IMAGE_TAG: "apiabcd",
HWLAB_BUILD_CREATED_AT: "2026-05-23T01:00:00.000Z",
HWLAB_CLOUD_WEB_SERVICE_URL: "http://live.test/hwlab-cloud-web",
HWLAB_AGENT_MGR_URL: "http://live.test/hwlab-agent-mgr",
HWLAB_AGENT_WORKER_URL: "http://live.test/missing-agent-worker",
HWLAB_GATEWAY_URL: "http://live.test/missing-gateway",
HWLAB_GATEWAY_SIMU_URL: "http://live.test/missing-gateway-simu",
HWLAB_BOX_SIMU_URL: "http://live.test/missing-box-simu",
HWLAB_PATCH_PANEL_URL: "http://live.test/missing-patch-panel",
HWLAB_ROUTER_URL: "http://live.test/missing-router",
HWLAB_TUNNEL_CLIENT_URL: "http://live.test/missing-tunnel-client",
HWLAB_EDGE_PROXY_URL: "http://live.test/external",
HWLAB_CLI_URL: "http://live.test/missing-cli",
HWLAB_AGENT_SKILLS_URL: "http://live.test/hwlab-agent-skills",
HWLAB_EXTRA_LAB_URL: "http://live.test/missing-extra-lab"
},
liveBuildMetadata,
fetchImpl: async (url) => {
const path = new URL(url).pathname;
const payload = healthByPath.get(path);
if (!payload) {
return {
ok: false,
status: 503,
async text() {
return JSON.stringify({ error: "offline" });
}
};
}
return {
ok: true,
status: 200,
async text() {
return JSON.stringify(payload);
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/live-builds`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.contractVersion, "live-builds-v1");
assert.equal(payload.latest.serviceId, "hwlab-agent-skills");
assert.equal(payload.latest.build.createdAt, "2026-05-23T05:30:00.000Z");
assert.equal(payload.latest.image.tag, "skillsabcd");
assert.equal(payload.latest.commit.id, "skillsabcdef123456");
assert.equal(payload.latest.build.metadataSource, "deploy-env:HWLAB_BUILD_CREATED_AT");
assert.equal(payload.latest.build.liveMetadataMatch.metadata.imageTag, "skillsabcd");
assert.match(payload.latest.build.liveHealthMissingReason, /匹配的 deploy metadata/u);
assert.equal(payload.counts.total, 15);
assert.equal(payload.counts.external, 2);
assert.equal(payload.counts.withBuildTime, 3);
const manager = payload.services.find((service) => service.serviceId === "hwlab-agent-mgr");
assert.equal(manager.build.createdAt, null);
assert.equal(manager.image.tag, "48dfbf9");
assert.equal(manager.revision, "48dfbf9");
assert.equal(manager.build.metadataSource, "live-health:controlled-metadata-mismatch");
assert.equal(manager.build.unavailableReason, "构建时间不可用:live tag 与 catalog metadata 不匹配");
assert.match(manager.build.unavailableDetail, /live tag 48dfbf9/u);
assert.match(manager.build.unavailableDetail, /metadata tag 3df89fe/u);
const extra = payload.services.find((service) => service.serviceId === "hwlab-extra-lab");
assert.equal(extra.build.createdAt, null);
assert.match(extra.build.unavailableReason, /当前 live health 不可用/u);
const worker = payload.services.find((service) => service.serviceId === "hwlab-agent-worker");
assert.equal(worker.build.createdAt, null);
assert.match(worker.build.unavailableReason, /构建时间不可用:当前 live health 不可用/u);
assert.match(worker.build.unavailableReason, /hwlab-agent-worker 当前 hwlab-dev desired replicas=0/u);
assert.ok(payload.services.some((service) => service.kind === "external" && service.serviceId === "hwlab-edge-proxy" && service.healthUrl.endsWith("/health")));
assert.ok(payload.services.some((service) => service.kind === "external" && service.serviceId === "hwlab-frpc" && service.image.tag === "v0.68.1"));
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api ignores old repository reports and keeps missing buildCreatedAt unavailable", async () => {
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "hwlab-live-builds-"));
const deployDir = path.join(tempRoot, "deploy");
const oldReportDir = path.join(tempRoot, "reports", "dev-gate");
await mkdir(deployDir, { recursive: true });
await mkdir(oldReportDir, { recursive: true });
await writeFile(path.join(deployDir, "deploy.json"), `${JSON.stringify({
services: [
{
serviceId: "hwlab-agent-mgr",
image: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:48dfbf9",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
}
]
}, null, 2)}\n`);
await writeFile(path.join(deployDir, "artifact-catalog.dev.json"), `${JSON.stringify({
services: [
{
serviceId: "hwlab-agent-mgr",
commitId: "48dfbf9abcdef",
image: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:48dfbf9",
imageTag: "48dfbf9",
digest: "sha256:" + "6".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: null,
buildSource: null
}
]
}, null, 2)}\n`);
await writeFile(path.join(oldReportDir, "dev-artifacts.json"), `${JSON.stringify({
artifactPublish: {
services: [
{
serviceId: "hwlab-agent-mgr",
sourceCommitId: "48dfbf9abcdef",
image: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:48dfbf9",
imageTag: "48dfbf9",
digest: "sha256:" + "6".repeat(64),
buildCreatedAt: "2099-01-01T00:00:00.000Z",
buildSource: "old-report-must-not-be-read"
}
]
}
}, null, 2)}\n`);
const observe = async () => {
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_AGENT_MGR_URL: "http://live.test/hwlab-agent-mgr"
},
repoRoot: tempRoot,
fetchImpl: async (url) => {
if (new URL(url).pathname === "/hwlab-agent-mgr/health/live") {
return {
ok: true,
status: 200,
async text() {
return JSON.stringify({
serviceId: "hwlab-agent-mgr",
status: "ok",
revision: "48dfbf9abcdef",
commit: { id: "48dfbf9abcdef", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:48dfbf9",
tag: "48dfbf9",
digest: "sha256:" + "6".repeat(64)
}
});
}
};
}
return {
ok: false,
status: 503,
async text() {
return JSON.stringify({ error: "offline" });
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/live-builds`);
assert.equal(response.status, 200);
return response.json();
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
};
try {
const withOldReport = await observe();
await rm(path.join(tempRoot, "reports"), { recursive: true, force: true });
const withoutOldReport = await observe();
const summarize = (payload) => {
const manager = payload.services.find((service) => service.serviceId === "hwlab-agent-mgr");
return {
latest: payload.latest,
source: payload.source,
createdAt: manager.build.createdAt,
metadataSource: manager.build.metadataSource,
unavailableReason: manager.build.unavailableReason,
unavailableDetail: manager.build.unavailableDetail,
liveMetadataMatch: manager.build.liveMetadataMatch,
counts: payload.counts
};
};
assert.deepEqual(summarize(withOldReport), summarize(withoutOldReport));
const manager = withOldReport.services.find((service) => service.serviceId === "hwlab-agent-mgr");
assert.equal(withOldReport.latest, null);
assert.equal(manager.build.createdAt, null);
assert.equal(manager.build.metadataSource, "live-health:matched-controlled-metadata-without-build-time");
assert.equal(manager.build.unavailableReason, "构建时间不可用:当前 live 镜像未提供 buildCreatedAt");
assert.match(manager.build.unavailableDetail, /catalog metadata/u);
assert.equal(Object.hasOwn(withOldReport.source, "artifactReportSource"), false);
assert.equal(JSON.stringify(withOldReport).includes("2099-01-01T00:00:00.000Z"), false);
assert.equal(JSON.stringify(withOldReport).includes("artifact-report"), false);
} finally {
await rm(tempRoot, { recursive: true, force: true });
}
});
test("cloud api health reports DB env presence and live connection classification without leaking values", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const originalAliasEnv = {
HWLAB_CLOUD_DB_SERVICE_NAME: process.env.HWLAB_CLOUD_DB_SERVICE_NAME,
HWLAB_CLOUD_DB_SERVICE_NAMESPACE: process.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE,
HWLAB_CLOUD_DB_HOST: process.env.HWLAB_CLOUD_DB_HOST,
HWLAB_CLOUD_DB_PORT: process.env.HWLAB_CLOUD_DB_PORT
};
const fakeDb = createTcpServer((socket) => socket.end());
await new Promise((resolve) => fakeDb.listen(0, "127.0.0.1", resolve));
const dbPort = fakeDb.address().port;
process.env.HWLAB_CLOUD_DB_URL = `postgres://hwlab_test@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAME;
delete process.env.HWLAB_CLOUD_DB_SERVICE_NAMESPACE;
delete process.env.HWLAB_CLOUD_DB_HOST;
delete process.env.HWLAB_CLOUD_DB_PORT;
const server = createCloudApiServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health`);
const payload = await response.json();
assert.equal(payload.status, "degraded");
assert.equal(payload.db.status, "ready");
assert.equal(payload.db.connected, true);
assert.equal(payload.db.liveConnected, true);
assert.equal(payload.db.liveDbEvidence, true);
assert.equal(payload.db.connectionChecked, true);
assert.equal(payload.db.connectionAttempted, true);
assert.equal(payload.db.connectionResult, "connected");
assert.equal(payload.db.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.endpointSource, "secret-url-host");
assert.equal(payload.db.endpoint.authoritative.source, "secret-url-host");
assert.equal(payload.db.endpoint.authoritative.env, "HWLAB_CLOUD_DB_URL");
assert.equal(payload.db.optionalPublicDnsAlias.source, "optional-public-dns-alias");
assert.equal(payload.db.optionalPublicDnsAlias.requiredForReadiness, false);
assert.equal(payload.db.optionalPublicDnsAlias.usedForProbe, false);
assert.equal(payload.db.optionalPublicDnsAlias.envPresent, false);
assert.equal(payload.db.configReady, true);
assert.equal(payload.db.ready, true);
assert.equal(payload.db.evidence, "live_db_tcp_connection_ready");
assert.equal(payload.db.safety.liveDbEvidence, true);
assert.equal(payload.db.safety.liveDbConnectedEvidence, true);
assert.equal(payload.runtime.adapter, "memory");
assert.equal(payload.runtime.durable, false);
assert.equal(payload.runtime.status, "degraded");
assert.match(payload.runtime.reason, /process-local/u);
assert.equal(payload.runtime.durabilityContract.blockedLayer, "adapter");
assert.equal(payload.runtime.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(payload.readiness.components.db, "ready");
assert.equal(payload.readiness.components.runtime, "blocked");
assert.equal(payload.readiness.durability.status, "blocked");
assert.equal(payload.readiness.durability.dbLiveEvidenceObserved, true);
assert.equal(payload.readiness.durability.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(payload.readiness.durability.blockedLayer, "adapter");
assert.equal(payload.readiness.durability.liveRuntimeEvidence, false);
assert.equal(payload.readiness.provider.status, "blocked");
assert.equal(payload.readiness.dbDurable.status, "blocked");
assert.equal(payload.readiness.dbDurable.dbLiveEvidenceObserved, true);
assert.equal(payload.readiness.dbDurable.blocker, "runtime_durable_adapter_missing");
assert.equal(payload.readiness.sessionRunner.status, "blocked");
assert.equal(payload.readiness.codexStdio.status, "blocked");
assert.equal(payload.db.redaction.valuesRedacted, true);
assert.equal(payload.db.redaction.endpointRedacted, true);
assert.equal(payload.db.redaction.secretMaterialRead, false);
assert.deepEqual(payload.db.missingEnv, []);
assert.equal(JSON.stringify(payload.db).includes("password"), false);
assert.equal(JSON.stringify(payload.db).includes("127.0.0.1"), false);
assert.equal(JSON.stringify(payload.db).includes(String(dbPort)), false);
assert.equal(JSON.stringify(payload.db).includes("cloud-api-db.hwlab-dev.svc.cluster.local"), false);
assert.equal(payload.db.fields.find((field) => field.name === "HWLAB_CLOUD_DB_URL").redacted, true);
assert.equal(payload.db.connection.endpointRedacted, true);
} finally {
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
for (const [name, value] of Object.entries(originalAliasEnv)) {
if (value === undefined) {
delete process.env[name];
} else {
process.env[name] = value;
}
}
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
fakeDb.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api health separates DB connected from durable runtime schema readiness", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const fakeDb = createTcpServer((socket) => socket.end());
await new Promise((resolve) => fakeDb.listen(0, "127.0.0.1", resolve));
const dbPort = fakeDb.address().port;
process.env.HWLAB_CLOUD_DB_URL = `postgres://hwlab_test@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
const server = createCloudApiServer({
runtimeStore: {
async readiness() {
return {
adapter: "postgres",
durable: false,
durableRequested: true,
durableCapable: false,
ready: false,
status: "blocked",
blocker: RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED,
reason: "test runtime schema is missing",
liveRuntimeEvidence: false,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult: "schema_blocked",
endpointRedacted: true,
valueRedacted: true
},
schema: {
checked: true,
ready: false,
missingTables: ["gateway_sessions"],
missingColumns: ["gateway_sessions.gateway_session_json"]
},
migration: {
checked: false,
ready: false,
missing: true
},
counts: {}
};
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.status, "degraded");
assert.equal(payload.db.connected, true);
assert.equal(payload.db.liveDbEvidence, true);
assert.equal(payload.runtime.durable, false);
assert.equal(payload.runtime.durableRequested, true);
assert.equal(payload.runtime.ready, false);
assert.equal(payload.runtime.blocker, RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED);
assert.equal(payload.readiness.components.db, "ready");
assert.equal(payload.readiness.components.runtime, "blocked");
assert.equal(payload.readiness.durability.status, "blocked");
assert.equal(payload.readiness.durability.dbLiveEvidenceObserved, true);
assert.equal(payload.readiness.durability.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(payload.readiness.durability.blockedLayer, "schema");
assert.equal(payload.readiness.durability.queryAttempted, true);
assert.equal(payload.readiness.durability.queryResult, "schema_blocked");
assert.ok(payload.blockerCodes.includes(RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED));
assert.equal(JSON.stringify(payload).includes("password"), false);
} finally {
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
fakeDb.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api health keeps DB live evidence separate when durable adapter query is blocked", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const fakeDb = createTcpServer((socket) => socket.end());
await new Promise((resolve) => fakeDb.listen(0, "127.0.0.1", resolve));
const dbPort = fakeDb.address().port;
process.env.HWLAB_CLOUD_DB_URL = `postgres://hwlab_test:password@127.0.0.1:${dbPort}/hwlab`;
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
const server = createCloudApiServer({
runtimeStore: {
async readiness() {
return {
adapter: "postgres",
durable: false,
durableRequested: true,
durableCapable: false,
ready: false,
status: "blocked",
blocker: RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED,
reason: "test runtime durable read query is blocked",
liveRuntimeEvidence: false,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult: "query_blocked",
endpointRedacted: true,
valueRedacted: true,
errorCode: "57014"
},
schema: {
checked: true,
ready: true,
missingTables: [],
missingColumns: []
},
migration: {
checked: true,
ready: true,
missing: false
},
gates: {
auth: { checked: true, ready: true, status: "ready", blocker: null },
schema: { checked: true, ready: true, status: "ready", blocker: null },
migration: { checked: true, ready: true, status: "ready", blocker: null },
durability: {
checked: true,
ready: false,
status: "blocked",
blocker: RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED
}
},
counts: {}
};
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.status, "degraded");
assert.equal(payload.db.ready, true);
assert.equal(payload.db.connected, true);
assert.equal(payload.db.liveDbEvidence, true);
assert.equal(payload.runtime.durable, false);
assert.equal(payload.runtime.ready, false);
assert.equal(payload.runtime.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
assert.equal(payload.readiness.components.db, "ready");
assert.equal(payload.readiness.components.runtime, "blocked");
assert.equal(payload.readiness.durability.status, "blocked");
assert.equal(payload.readiness.durability.dbLiveEvidenceObserved, true);
assert.equal(payload.readiness.durability.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(payload.readiness.durability.blockedLayer, "durability_query");
assert.equal(payload.readiness.durability.queryAttempted, true);
assert.equal(payload.readiness.durability.queryResult, "query_blocked");
assert.equal(payload.readiness.durability.liveRuntimeEvidence, false);
assert.ok(payload.blockerCodes.includes(RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED));
assert.equal(payload.readiness.dbDurable.status, "blocked");
assert.equal(payload.readiness.dbDurable.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
assert.equal(payload.readiness.codeAgent.currentBlockers.includes(RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED), true);
assert.equal(JSON.stringify(payload).includes("password"), false);
assert.equal(JSON.stringify(payload).includes(String(dbPort)), false);
} finally {
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
fakeDb.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api health contract distinguishes durable SSL, auth, schema, migration, and query blockers", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
process.env.HWLAB_CLOUD_DB_URL = "redacted";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "require";
const cases = [
{
blocker: RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED,
blockedLayer: "ssl",
queryResult: "ssl_negotiation_blocked",
gates: {
ssl: "blocked",
auth: "not_checked",
schema: "not_checked",
migration: "not_checked",
durability: "blocked"
}
},
{
blocker: RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED,
blockedLayer: "auth",
queryResult: "auth_blocked",
gates: {
ssl: "ready",
auth: "blocked",
schema: "not_checked",
migration: "not_checked",
durability: "blocked"
}
},
{
blocker: RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED,
blockedLayer: "schema",
queryResult: "schema_blocked",
gates: {
ssl: "ready",
auth: "ready",
schema: "blocked",
migration: "not_checked",
durability: "blocked"
}
},
{
blocker: RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED,
blockedLayer: "migration",
queryResult: "migration_blocked",
gates: {
ssl: "ready",
auth: "ready",
schema: "ready",
migration: "blocked",
durability: "blocked"
}
},
{
blocker: RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED,
blockedLayer: "durability_query",
queryResult: "query_blocked",
gates: {
ssl: "ready",
auth: "ready",
schema: "ready",
migration: "ready",
durability: "blocked"
}
}
];
try {
for (const testCase of cases) {
const server = createCloudApiServer({
dbProbe: {
probe: async ({ endpointSource, timeoutMs }) => ({
attempted: true,
networkAttempted: true,
endpointSource,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
timeoutMs,
durationMs: 0,
result: "connected",
classification: "tcp_connected",
errorCode: null,
missingEnv: []
})
},
runtimeStore: {
async readiness() {
return durableBlockedRuntime(testCase);
}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.status, "degraded");
assert.equal(payload.db.ready, true);
assert.equal(payload.db.liveDbEvidence, true);
assert.equal(payload.runtime.blocker, testCase.blocker);
assert.equal(payload.runtime.connection.queryResult, testCase.queryResult);
assert.equal(payload.runtime.gates.ssl.status, testCase.gates.ssl);
assert.equal(payload.runtime.gates.auth.status, testCase.gates.auth);
assert.equal(payload.runtime.gates.schema.status, testCase.gates.schema);
assert.equal(payload.runtime.gates.migration.status, testCase.gates.migration);
assert.equal(payload.runtime.gates.durability.status, testCase.gates.durability);
assert.equal(payload.runtime.durabilityContract.blockedLayer, testCase.blockedLayer);
assert.equal(payload.db.runtimeReadiness.blockedLayer, testCase.blockedLayer);
assert.equal(payload.db.runtimeReadiness.queryResult, testCase.queryResult);
assert.equal(payload.db.runtimeReadiness.dbLiveEvidenceIsDurabilityEvidence, false);
assert.equal(payload.db.readinessLayers.ssl.status, layerStatus(testCase.gates.ssl));
assert.equal(payload.db.readinessLayers.auth.status, layerStatus(testCase.gates.auth));
assert.equal(payload.db.readinessLayers.schema.status, layerStatus(testCase.gates.schema));
assert.equal(payload.db.readinessLayers.migration.status, layerStatus(testCase.gates.migration));
assert.equal(payload.db.readinessLayers.durability.status, layerStatus(testCase.gates.durability));
assert.equal(payload.db.readinessLayers[layerForBlockedCase(testCase.blockedLayer)].result, testCase.queryResult);
assert.equal(payload.readiness.durability.blockedLayer, testCase.blockedLayer);
assert.equal(payload.readiness.durability.queryResult, testCase.queryResult);
assert.equal(payload.readiness.durability.secretMaterialRead, false);
assert.ok(payload.blockerCodes.includes(testCase.blocker));
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
}
} finally {
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
}
});
test("cloud api health does not treat DB env presence-only as live readiness", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
const originalProbeDisabled = process.env.HWLAB_CLOUD_DB_PROBE_DISABLED;
process.env.HWLAB_CLOUD_DB_URL = "postgres://user:password@db.example.invalid:5432/hwlab";
process.env.HWLAB_CLOUD_DB_SSL_MODE = "disable";
delete process.env.HWLAB_CLOUD_DB_PROBE_DISABLED;
const server = createCloudApiServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.db.configReady, true);
assert.equal(payload.db.connected, false);
assert.equal(payload.db.liveConnected, false);
assert.equal(payload.db.liveDbEvidence, false);
assert.equal(payload.db.safety.liveDbEvidence, false);
assert.equal(payload.db.ready, false);
assert.equal(payload.db.connectionAttempted, true);
assert.equal(payload.db.connectionResult, "forbidden_runtime_host");
assert.equal(payload.db.evidence, "live_db_tcp_connection_blocked");
assert.equal(payload.db.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.endpointSource, "secret-url-host");
assert.equal(payload.db.connection.networkAttempted, false);
assert.equal(payload.db.connection.classification, "db_url_forbidden_invalid_host");
assert.equal(payload.db.readinessLayers.dns.status, "not_proven");
assert.equal(JSON.stringify(payload.db).includes("password"), false);
assert.equal(JSON.stringify(payload.db).includes("db.example.invalid"), false);
} finally {
if (originalUrl === undefined) {
delete process.env.HWLAB_CLOUD_DB_URL;
} else {
process.env.HWLAB_CLOUD_DB_URL = originalUrl;
}
if (originalSslMode === undefined) {
delete process.env.HWLAB_CLOUD_DB_SSL_MODE;
} else {
process.env.HWLAB_CLOUD_DB_SSL_MODE = originalSslMode;
}
if (originalProbeDisabled === undefined) {
delete process.env.HWLAB_CLOUD_DB_PROBE_DISABLED;
} else {
process.env.HWLAB_CLOUD_DB_PROBE_DISABLED = originalProbeDisabled;
}
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
function durableBlockedRuntime({ blocker, blockedLayer, queryResult, gates }) {
return {
adapter: "postgres",
durable: false,
durableRequested: true,
durableCapable: false,
ready: false,
status: "blocked",
blocker,
reason: `test durable runtime blocker ${blocker}`,
liveRuntimeEvidence: false,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult,
endpointRedacted: true,
valueRedacted: true,
errorCode: "TEST_BLOCKER"
},
schema: {
checked: gates.schema !== "not_checked",
ready: gates.schema === "ready",
missingTables: gates.schema === "blocked" ? ["gateway_sessions"] : [],
missingColumns: gates.schema === "blocked" ? ["gateway_sessions.gateway_session_json"] : []
},
migration: {
checked: gates.migration !== "not_checked",
ready: gates.migration === "ready",
missing: gates.migration !== "ready"
},
gates: Object.fromEntries(Object.entries(gates).map(([name, status]) => [
name,
{
checked: status !== "not_checked",
ready: status === "ready",
status,
blocker: status === "blocked" ? blocker : null
}
])),
durabilityContract: {
ready: false,
status: "blocked",
requiredEvidence: "runtime_adapter_schema_migration_read_query",
dbLiveEvidenceIsDurabilityEvidence: false,
liveRuntimeEvidence: false,
adapterQueryRequired: true,
blockedLayer,
blocker,
secretMaterialRead: false
},
safety: {
secretMaterialRead: false,
valuesRedacted: true,
endpointRedacted: true
},
counts: {}
};
}
function durableReadyRuntime() {
return {
adapter: "postgres",
durable: true,
durableRequested: true,
durableCapable: true,
ready: true,
status: "ready",
blocker: null,
reason: "test durable runtime ready",
liveRuntimeEvidence: true,
fixtureEvidence: false,
connection: {
queryAttempted: true,
queryResult: "durable_readiness_ready",
endpointRedacted: true,
valueRedacted: true
},
schema: {
checked: true,
ready: true,
missingTables: [],
missingColumns: []
},
migration: {
checked: true,
ready: true,
missing: false
},
gates: Object.fromEntries(["ssl", "auth", "schema", "migration", "durability"].map((name) => [
name,
{
checked: true,
ready: true,
status: "ready",
blocker: null
}
])),
durabilityContract: {
ready: true,
status: "ready",
requiredEvidence: "runtime_adapter_schema_migration_read_query",
dbLiveEvidenceIsDurabilityEvidence: false,
liveRuntimeEvidence: true,
adapterQueryRequired: true,
blockedLayer: null,
blocker: null,
secretMaterialRead: false
},
safety: {
secretMaterialRead: false,
valuesRedacted: true,
endpointRedacted: true
},
counts: {}
};
}
function layerStatus(gateStatus) {
if (gateStatus === "ready") return "pass";
if (gateStatus === "blocked") return "blocked";
return "not_proven";
}
function layerForBlockedCase(blockedLayer) {
if (blockedLayer === "durability_query") return "durability";
return blockedLayer;
}
async function m3ReadinessRequestJson(url, request = {}) {
const parsed = new URL(url);
const body = request.body ?? {};
if (url.startsWith("http://gateway-1") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: m3GatewayStatus({
gatewayId: "gwsimu_1",
gatewaySessionId: "gws_gwsimu_1",
boxId: "boxsimu_1",
resourceId: "res_boxsimu_1"
})
};
}
if (url.startsWith("http://gateway-1") && parsed.pathname === "/invoke") {
return {
ok: true,
status: 200,
body: {
accepted: true,
operationId: "op_m3_status_do1",
traceId: "trc_m3_status_do1",
boxId: "boxsimu_1",
resourceId: "res_boxsimu_1",
port: "DO1",
value: false,
state: {
port: "DO1",
direction: "output",
value: false,
source: "gateway-simu",
updatedAt: "2026-05-23T00:00:00.000Z"
},
auditId: "aud_m3_status_do1",
evidenceId: "evd_m3_status_do1"
}
};
}
if (url.startsWith("http://gateway-2") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: m3GatewayStatus({
gatewayId: "gwsimu_2",
gatewaySessionId: "gws_gwsimu_2",
boxId: "boxsimu_2",
resourceId: "res_boxsimu_2"
})
};
}
if (url.startsWith("http://gateway-2") && parsed.pathname === "/invoke") {
const value = request.body?.operationId?.includes("do_write") || request.body?.operationId?.includes("do-write")
? true
: false;
return {
ok: true,
status: 200,
body: {
accepted: true,
operationId: "op_m3_status_di1",
traceId: "trc_m3_status_di1",
boxId: "boxsimu_2",
resourceId: "res_boxsimu_2",
port: "DI1",
value,
state: {
port: "DI1",
direction: "input",
value,
source: "patch-panel",
sourceResourceId: "res_boxsimu_1",
sourcePort: "DO1",
propagatedBy: "hwlab-patch-panel",
updatedAt: "2026-05-23T00:00:00.000Z"
},
auditId: "aud_m3_status_di1",
evidenceId: "evd_m3_status_di1"
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/status") {
return {
ok: true,
status: 200,
body: {
serviceId: "hwlab-patch-panel",
state: "active",
activeConnections: [
{
fromResourceId: "res_boxsimu_1",
fromPort: "DO1",
toResourceId: "res_boxsimu_2",
toPort: "DI1"
}
]
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/wiring") {
return {
ok: true,
status: 200,
body: {
wiringConfigId: "wir_m3_do1_di1",
status: "active",
connections: [
{
from: {
resourceId: "res_boxsimu_1",
port: "DO1"
},
to: {
resourceId: "res_boxsimu_2",
port: "DI1"
},
mode: "exclusive"
}
]
}
};
}
if (url.startsWith("http://patch-panel") && parsed.pathname === "/sync/tick") {
return {
ok: true,
status: 200,
body: {
accepted: true,
propagatedBy: "hwlab-patch-panel",
routeCount: 1,
deliveryCount: 1,
routes: [
{
accepted: true,
deliveryCount: 1,
deliveries: [
{
resourceId: "res_boxsimu_2",
port: "DI1",
value: body.signals?.[0]?.value ?? false,
sourceResourceId: "res_boxsimu_1",
sourcePort: "DO1",
deliveryStatus: "applied"
}
]
}
]
}
};
}
throw new Error(`unexpected M3 readiness request ${url}`);
}
function m3GatewayStatus({ gatewayId, gatewaySessionId, boxId, resourceId }) {
return {
serviceId: "hwlab-gateway-simu",
gatewayId,
gatewaySessionId,
session: {
gatewayId,
gatewaySessionId
},
registry: {
gatewayId,
gatewaySessionId,
boxes: [
{
boxId,
resourceId,
state: "registered"
}
]
}
};
}
function codexStdioReadyFixture({ workspace, codexHome }) {
return {
kind: "codex-app-server-stdio-runner",
provider: "codex-stdio",
backend: "hwlab-cloud-api/codex-app-server-stdio",
status: "feasible",
ready: true,
startupReady: true,
canStartLongLivedCodexStdio: true,
command: path.join(process.cwd(), "node_modules", ".bin", "codex"),
binaryOnPath: true,
binary: {
present: true,
executable: true,
nativeDependencyPresent: true,
versionDetected: true
},
workspace,
workspaceState: { exists: true, readable: true, writable: true, writeRequired: true },
codexHome,
codexHomeState: { exists: true, readable: true, writable: true, writeRequired: true },
sandbox: "workspace-write",
enabled: true,
supervisor: { configured: true, mode: "repo-owned-node-supervisor" },
tokenBoundary: { present: true, secretMaterialRead: false, valuesRedacted: true },
egress: { configured: true, directPublicOpenAi: false, valueRedacted: true },
protocol: {
status: "wired",
wired: true,
protocolVersion: "codex-app-server-jsonrpc-stdio",
requiredMethods: ["initialize", "thread/start", "thread/resume", "turn/start"],
toolsObserved: [],
missingTools: [],
command: "codex app-server --listen stdio://"
},
commandProbe: {
status: "ready",
ready: true,
probe: "workspace.pwd",
traceId: "trc_codex_stdio_command_probe",
toolCalls: [{
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdoutSummary: "workspace path matched",
outputTruncated: false
}],
secretMaterialRead: false,
valuesRedacted: true
},
stdioProtocol: {
status: "wired",
wired: true,
protocolVersion: "codex-app-server-jsonrpc-stdio",
requiredMethods: ["initialize", "thread/start", "thread/resume", "turn/start"],
toolsObserved: [],
missingTools: [],
command: "codex app-server --listen stdio://"
},
sessionLifecycle: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
lifecycleSupervisor: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
runtimeContract: {
status: "ready",
ready: true,
binary: {
status: "present",
present: true,
executable: true,
nativeDependencyPresent: true,
versionDetected: true
},
stdioProtocol: {
status: "wired",
wired: true,
protocolVersion: "codex-app-server-jsonrpc-stdio",
requiredMethods: ["initialize", "thread/start", "thread/resume", "turn/start"],
toolsObserved: [],
missingTools: []
},
commandProbe: {
status: "ready",
ready: true,
probe: "workspace.pwd",
traceId: "trc_codex_stdio_command_probe",
toolCalls: [{
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdoutSummary: "workspace path matched",
outputTruncated: false
}],
secretMaterialRead: false,
valuesRedacted: true
},
lifecycleSupervisor: {
status: "present",
present: true,
create: true,
reuse: true,
cancel: true,
reap: true,
traceCapture: true,
idleTimeoutMs: 1800000
},
workspaceMount: {
path: workspace,
status: "ready",
mounted: true,
readable: true,
writable: true,
sandbox: "workspace-write"
},
codexHome: {
path: codexHome,
status: "ready",
exists: true,
readable: true,
writable: true
},
cancelReapTraceReadiness: {
status: "ready",
cancel: true,
reap: true,
traceCapture: true,
idleTimeout: true
}
},
blockers: [],
blockerCodes: [],
safety: { secretMaterialRead: false, valuesRedacted: true }
};
}
function codexStdioChatFixture({ workspace, codexHome, params }) {
const traceId = params.traceId;
const session = {
sessionId: "ses_server_stdio_pwd",
conversationId: params.conversationId,
status: "idle",
workspace,
sandbox: "workspace-write",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
capabilityLevel: "long-lived-codex-stdio-session",
implementationType: "repo-owned-codex-app-server-stdio-session",
createdAt: "2026-05-23T00:00:00.000Z",
updatedAt: "2026-05-23T00:00:00.000Z",
idleTimeoutMs: 1800000,
expiresAt: "2026-05-23T00:30:00.000Z",
lastTraceId: traceId,
turn: 1,
threadId: "thread_server_stdio_pwd",
reused: false,
durable: true,
longLivedSession: true,
codexStdio: true,
writeCapable: true,
secretMaterialStored: false,
valuesRedacted: true
};
const feasibility = codexStdioReadyFixture({ workspace, codexHome });
return {
provider: "codex-stdio",
model: "gpt-test",
backend: "hwlab-cloud-api/codex-app-server-stdio",
content: `stdio pwd\n${workspace}`,
workspace,
sandbox: "workspace-write",
session,
sessionMode: "codex-app-server-stdio-long-lived",
sessionReuse: {
conversationId: params.conversationId,
sessionId: session.sessionId,
threadId: session.threadId,
mapped: true,
reused: false,
turn: 1,
previousTurns: 0,
workspace,
status: "idle",
idleTimeoutMs: 1800000
},
implementationType: "repo-owned-codex-app-server-stdio-session",
runnerLimitations: ["hardware-control-via-cloud-api-only", "secret-values-redacted"],
codexStdioFeasibility: feasibility,
longLivedSessionGate: {
status: "pass",
pass: true,
provider: "codex-stdio",
runnerKind: "codex-app-server-stdio-runner",
sessionMode: "codex-app-server-stdio-long-lived",
implementationType: "repo-owned-codex-app-server-stdio-session",
blockers: []
},
toolCalls: [{
id: "tool_server_stdio_pwd",
type: "workspace-read",
name: "pwd",
status: "completed",
cwd: workspace,
command: "pwd",
exitCode: 0,
stdout: workspace,
stderrSummary: "",
outputTruncated: false,
traceId
}],
skills: {
status: "not_requested",
items: [],
count: 0,
blockers: []
},
runner: {
kind: "codex-app-server-stdio-runner",
provider: "codex-stdio",
backend: "hwlab-cloud-api/codex-app-server-stdio",
workspace,
sandbox: "workspace-write",
session: "codex-app-server-stdio-long-lived",
sessionMode: "codex-app-server-stdio-long-lived",
sessionId: session.sessionId,
implementationType: "repo-owned-codex-app-server-stdio-session",
codexStdio: true,
longLivedSession: true,
durableSession: true,
writeCapable: true,
readOnly: false,
capabilityLevel: "long-lived-codex-stdio-session"
},
runnerTrace: {
traceId,
runnerKind: "codex-app-server-stdio-runner",
workspace,
sandbox: "workspace-write",
sessionMode: "codex-app-server-stdio-long-lived",
sessionId: session.sessionId,
sessionStatus: "idle",
turn: 1,
implementationType: "repo-owned-codex-app-server-stdio-session",
events: ["stdio:acquire", "session:created", "stdio:ready", "tool:pwd:completed"],
outputTruncated: false,
valuesPrinted: false
},
capabilityLevel: "long-lived-codex-stdio-session",
providerTrace: {
transport: "stdio",
protocol: "codex-app-server-jsonrpc-stdio",
command: "codex app-server --listen stdio://",
toolName: "codex-app-server.thread/start+turn/start",
threadId: "thread_server_stdio_pwd",
valuesPrinted: false
}
};
}
test("cloud api /v1 describes Code Agent provider blocker without leaking secret values", async () => {
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: "/tmp/hwlab-missing-codex"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.codeAgent.endpoint, "POST /v1/agent/chat");
assert.equal(payload.codeAgent.provider, "codex-stdio");
assert.equal(payload.codeAgent.model, "gpt-test");
assert.equal(payload.codeAgent.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.codeAgent.mode, "codex-stdio");
assert.equal(payload.codeAgent.status, "blocked");
assert.match(payload.codeAgent.blocker, /Codex CLI command/u);
assert.equal(payload.codeAgent.reason, "codex_cli_binary_missing");
assert.equal(payload.codeAgent.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.codeAgent.runner.ready, false);
assert.equal(payload.codeAgent.capabilityLevel, "blocked");
assert.equal(payload.codeAgent.sessionRegistry.status, "available");
assert.equal(payload.codeAgent.longLivedSessionGate.status, "blocked");
assert.deepEqual(payload.codeAgent.missingEnv, []);
assert.equal(payload.codeAgent.secretRefs[0].env, "OPENAI_API_KEY");
assert.equal(payload.codeAgent.secretRefs[0].secretName, "hwlab-code-agent-provider");
assert.equal(payload.codeAgent.secretRefs[0].secretKey, "openai-api-key");
assert.equal(payload.codeAgent.secretRefs[0].redacted, true);
assert.equal(payload.codeAgent.ready, false);
assert.equal(payload.codeAgent.partialReady, false);
assert.equal(payload.codeAgent.egress.present, false);
assert.equal(payload.codeAgent.egress.valueRedacted, true);
assert.equal(payload.codeAgent.safety.secretMaterialRead, false);
assert.match(payload.codeAgent.summary, /will not use controlled-readonly-session-registry/u);
assert.match(payload.codeAgent.summary, /Codex stdio long-lived session is blocked/u);
assert.equal(JSON.stringify(payload).includes("sk-"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1 describes Code Agent egress blocker without leaking API key", async () => {
const server = createCloudApiServer({
env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "https://api.openai.com/v1/responses"
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1`);
assert.equal(response.status, 200);
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.equal(payload.codeAgent.runner.ready, false);
assert.equal(payload.codeAgent.safety.secretMaterialRead, false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api health reports provider, durable DB, and codex stdio ready when runtime contract passes", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-health-codex-stdio-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const manager = createCodexStdioSessionManager({
createRpcClient: async () => createFakeAppServerClient()
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:17680/v1/responses",
HWLAB_CLOUD_DB_URL: "postgres://hwlab_test:password@db.internal.local:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
dbProbe: {
probe: async ({ endpointSource, timeoutMs }) => ({
attempted: true,
networkAttempted: true,
endpointSource,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
timeoutMs,
durationMs: 1,
result: "connected",
classification: "tcp_connected",
errorCode: null,
missingEnv: []
})
},
runtimeStore: {
async readiness() {
return durableReadyRuntime();
}
},
codexStdioManager: manager
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "ok");
assert.equal(payload.db.ready, true);
assert.equal(payload.db.liveDbEvidence, true);
assert.equal(payload.runtime.ready, true);
assert.equal(payload.runtime.durable, true);
assert.equal(payload.readiness.provider.status, "ready");
assert.equal(payload.readiness.provider.ready, true);
assert.equal(payload.readiness.provider.blocker, null);
assert.equal(payload.readiness.dbDurable.status, "ready");
assert.equal(payload.readiness.dbDurable.ready, true);
assert.equal(payload.readiness.sessionRunner.status, "codex_stdio_ready");
assert.equal(payload.readiness.sessionRunner.ready, true);
assert.equal(payload.readiness.sessionRunner.codexStdio, true);
assert.equal(payload.readiness.sessionRunner.writeCapable, true);
assert.equal(payload.readiness.codexStdio.status, "ready");
assert.equal(payload.readiness.codexStdio.ready, true);
assert.deepEqual(payload.readiness.codeAgent.currentBlockers, []);
assert.equal(payload.readiness.codeAgent.providerReady, true);
assert.equal(payload.readiness.codeAgent.durableDbReady, true);
assert.equal(payload.readiness.codeAgent.sessionRunnerReady, true);
assert.equal(payload.readiness.codeAgent.codexStdioFeasible, true);
assert.equal(payload.codeAgent.ready, true);
assert.equal(payload.codeAgent.status, "codex-stdio-feasible");
assert.equal(payload.codeAgent.longLivedSessionGate.status, "pass");
assert.equal(payload.codeAgent.codexStdio.runtimeContract.binary.status, "present");
assert.deepEqual(payload.codeAgent.codexStdio.protocol.toolsObserved, []);
assert.deepEqual(payload.codeAgent.codexStdio.protocol.requiredMethods, ["initialize", "thread/start", "thread/resume", "turn/start"]);
assert.equal(payload.codeAgent.codexStdio.commandProbe.ready, true);
assert.equal(payload.codeAgent.codexStdio.runtimeContract.commandProbe.ready, true);
assert.equal(payload.readiness.codexStdio.commandProbeReady, true);
assert.equal(JSON.stringify(payload).includes("provider_unavailable"), false);
assert.equal(JSON.stringify(payload).includes("dns_resolution_failed"), false);
assert.equal(JSON.stringify(payload).includes("runtime_durable_adapter_auth_blocked"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
assert.equal(JSON.stringify(payload).includes("password"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api health blocks full Code Agent readiness when Codex stdio command probe fails", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-health-codex-stdio-probe-fail-"));
const codexHome = path.join(workspace, "codex-home");
const workspaceFile = path.join(workspace, "workspace-file");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
await writeFile(workspaceFile, "not a directory\n", "utf8");
const manager = createCodexStdioSessionManager({
createRpcClient: async () => createFakeAppServerClient()
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspaceFile,
HWLAB_CODE_AGENT_WORKSPACE: workspaceFile,
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:17680/v1/responses",
HWLAB_CLOUD_DB_URL: "postgres://hwlab_test:password@db.internal.local:5432/hwlab",
HWLAB_CLOUD_DB_SSL_MODE: "disable"
},
dbProbe: {
probe: async ({ endpointSource, timeoutMs }) => ({
attempted: true,
networkAttempted: true,
endpointSource,
probeType: "tcp-connect",
endpointRedacted: true,
valueRedacted: true,
timeoutMs,
durationMs: 1,
result: "connected",
classification: "tcp_connected",
errorCode: null,
missingEnv: []
})
},
runtimeStore: {
async readiness() {
return durableReadyRuntime();
}
},
codexStdioManager: manager
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "degraded");
assert.equal(payload.ready, false);
assert.equal(payload.readiness.components.codeAgent, "blocked");
assert.equal(payload.readiness.codexStdio.status, "blocked");
assert.equal(payload.readiness.codexStdio.ready, false);
assert.equal(payload.readiness.codexStdio.commandProbeReady, false);
assert.ok(payload.readiness.codexStdio.blockerCodes.includes("codex_stdio_command_probe_failed"));
assert.ok(payload.blockerCodes.includes("codex_stdio_command_probe_failed"));
assert.equal(payload.codeAgent.ready, false);
assert.equal(payload.codeAgent.codexStdio.commandProbe.ready, false);
assert.equal(payload.codeAgent.codexStdio.commandProbe.status, "blocked");
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
assert.equal(JSON.stringify(payload).includes("password"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat refuses provider stub when Codex stdio is unavailable", async () => {
let providerCalled = false;
const server = createCloudApiServer({
env: missingCodexCommandEnv(),
callCodeAgentProvider: async () => {
providerCalled = true;
throw new Error("provider stub must not be used");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-agent-chat"
},
body: JSON.stringify({
conversationId: "cnv_server-test-agent-chat",
message: "请用一句话说明当前 HWLAB 工作台可以做什么。"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.conversationId, "cnv_server-test-agent-chat");
assert.equal(payload.sessionId, "cnv_server-test-agent-chat");
assert.match(payload.messageId, /^msg_/);
assert.equal(payload.status, "failed");
assert.equal(payload.traceId, "trc_server-test-agent-chat");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.model.length > 0, true);
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(Number.isNaN(Date.parse(payload.createdAt)), false);
assert.equal(Number.isNaN(Date.parse(payload.updatedAt)), false);
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.error.layer, "runner");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(providerCalled, false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api REST JSON-RPC bridge exposes unknown serviceId reason for Code Agent internal calls", async () => {
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/rpc/hardware.invoke.shell`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-invalid-service-id",
"x-source-service-id": "hwlab-code-agent-hotfix"
},
body: JSON.stringify({
projectId: "prj_mvp_topology",
gatewaySessionId: "gws_DESKTOP-1MHOD9I",
resourceId: "res_windows_host",
capabilityId: "cap_windows_cmd_exec",
input: {
command: "cmd /c echo should-not-dispatch"
}
})
});
assert.equal(response.status, 400);
const payload = await response.json();
assert.equal(payload.error.code, -32600);
assert.equal(payload.error.message, "Invalid JSON-RPC request");
assert.match(payload.error.data.reason, /unknown serviceId "hwlab-code-agent-hotfix"/u);
assert.equal(JSON.stringify(payload).includes("should-not-dispatch"), false);
assert.equal(JSON.stringify(payload).includes("sk-"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("OpenAI fallback text chat is not used when Codex stdio is unavailable", async () => {
let providerCalled = false;
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
callCodeAgentProvider: async () => {
providerCalled = true;
throw new Error("OpenAI fallback must not be used");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_openai_fallback_not_runner",
traceId: "trc_server_openai_fallback_not_runner",
message: "请用一句话说明当前 HWLAB 工作台可以做什么。"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.runner.codexStdio, true);
assert.equal(payload.longLivedSessionGate.status, "blocked");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(providerCalled, false);
const capability = classifyCodexRunnerCapability(payload, { httpStatus: 200 });
assert.equal(capability.capabilityPass, false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api health does not pass long-lived session gate for explicit OpenAI fallback even if Codex stdio is feasible", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-openai-health-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-openai-health-codex-home-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: {
describe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async probe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async chat(params = {}) {
return codexStdioChatFixture({ workspace, codexHome, params });
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.codeAgent.provider, "openai-responses");
assert.equal(payload.codeAgent.mode, "openai");
assert.equal(payload.codeAgent.ready, false);
assert.equal(payload.codeAgent.capabilityLevel, "blocked");
assert.equal(payload.codeAgent.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.codeAgent.runner.codexStdio, true);
assert.equal(payload.codeAgent.longLivedSessionGate.status, "blocked");
assert.equal(payload.readiness.sessionRunner.status, "codex_stdio_ready");
assert.equal(payload.readiness.codeAgent.ready, false);
assert.equal(payload.readiness.codeAgent.provider.provider, "openai-responses");
assert.equal(payload.readiness.codeAgent.sessionRunner.codexStdio, true);
assert.equal(JSON.stringify(payload.codeAgent).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat parse and params errors use structured blocker envelope", async () => {
const server = createCloudApiServer({
env: {
HWLAB_CODE_AGENT_MODEL: "gpt-test"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const parse = await postAgentRaw(port, "{", { "x-trace-id": "trc_parse_error" });
assert.equal(parse.status, 400);
assert.equal(parse.body.status, "failed");
assert.equal(parse.body.error.code, "parse_error");
assert.equal(parse.body.error.layer, "api");
assert.equal(parse.body.error.retryable, true);
assert.equal(parse.body.error.traceId, "trc_parse_error");
assert.equal(parse.body.error.route, "/v1/agent/chat");
assert.match(parse.body.error.userMessage, /JSON/u);
assert.equal(Object.hasOwn(parse.body, "reply"), false);
assert.equal(JSON.stringify(parse.body).includes("sk-"), false);
const invalid = await postAgentRaw(port, JSON.stringify([]), { "x-trace-id": "trc_invalid_params" });
assert.equal(invalid.status, 400);
assert.equal(invalid.body.error.code, "invalid_params");
assert.equal(invalid.body.error.layer, "api");
assert.equal(invalid.body.error.retryable, true);
assert.equal(invalid.body.error.blocker.code, "invalid_params");
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat runs Codex stdio pwd with session and workspace evidence", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-workspace-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-codex-home-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: {
describe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async probe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async chat(params = {}) {
return codexStdioChatFixture({ workspace, codexHome, params });
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-runner-pwd"
},
body: JSON.stringify({
conversationId: "cnv_server-test-runner-pwd",
message: "用pwd列出你当前的工作目录"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.workspace, workspace);
assert.equal(payload.sandbox, "workspace-write");
assert.equal(payload.session.status, "idle");
assert.equal(payload.session.workspace, workspace);
assert.equal(payload.session.sandbox, "workspace-write");
assert.equal(payload.session.lastTraceId, "trc_server-test-runner-pwd");
assert.equal(typeof payload.session.idleTimeoutMs, "number");
assert.equal(payload.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.runner.longLivedSession, true);
assert.equal(payload.runner.codexStdio, true);
assert.equal(payload.runner.writeCapable, true);
assert.equal(payload.runner.durableSession, true);
assert.equal(payload.runner.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.implementationType, "repo-owned-codex-app-server-stdio-session");
assert.equal(payload.sessionReuse.reused, false);
assert.equal(payload.sessionReuse.turn, 1);
assert.equal(payload.sessionReuse.status, "idle");
assert.ok(payload.runnerLimitations.includes("hardware-control-via-cloud-api-only"));
assert.equal(payload.codexStdioFeasibility.ready, true);
assert.equal(payload.codexStdioFeasibility.runtimeContract.stdioProtocol.status, "wired");
assert.equal(payload.codexStdioFeasibility.runtimeContract.lifecycleSupervisor.status, "present");
assert.equal(payload.longLivedSessionGate.status, "pass");
assert.equal(payload.longLivedSessionGate.pass, true);
assert.equal(payload.toolCalls[0].name, "pwd");
assert.equal(payload.toolCalls[0].status, "completed");
assert.equal(payload.toolCalls[0].stdout, workspace);
assert.equal(payload.skills.status, "not_requested");
assert.equal(payload.runnerTrace.runnerKind, "codex-app-server-stdio-runner");
assert.equal(payload.runnerTrace.sessionMode, "codex-app-server-stdio-long-lived");
assert.match(payload.reply.content, new RegExp(workspace.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")));
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat supports short submit and result polling", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-short-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-short-codex-home-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_SANDBOX: "danger-full-access",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: {
describe() {
return {
...codexStdioReadyFixture({ workspace, codexHome }),
sandbox: "danger-full-access"
};
},
async probe() {
return {
...codexStdioReadyFixture({ workspace, codexHome }),
sandbox: "danger-full-access"
};
},
async chat(params = {}) {
return {
...codexStdioChatFixture({ workspace, codexHome, params }),
sandbox: "danger-full-access",
session: {
...codexStdioChatFixture({ workspace, codexHome, params }).session,
sandbox: "danger-full-access"
}
};
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-short-submit";
const submit = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": traceId,
"prefer": "respond-async",
"x-hwlab-short-connection": "1"
},
body: JSON.stringify({
conversationId: "cnv_server-test-short-submit",
message: "用pwd列出你当前的工作目录"
})
});
assert.equal(submit.status, 202);
const accepted = await submit.json();
assert.equal(accepted.accepted, true);
assert.equal(accepted.shortConnection, true);
assert.equal(accepted.traceId, traceId);
assert.equal(accepted.resultUrl, `/v1/agent/chat/result/${traceId}`);
const payload = await pollAgentResult(port, traceId);
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.traceId, traceId);
assert.equal(payload.sandbox, "danger-full-access");
assert.match(payload.reply.content, new RegExp(workspace.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")));
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
test("cloud api health reports Codex stdio runner facts without readonly limitations", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-health-stdio-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-health-codex-home-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: {
describe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async probe() {
return codexStdioReadyFixture({ workspace, codexHome });
},
async chat(params = {}) {
return codexStdioChatFixture({ workspace, codexHome, params });
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/health/live`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.codeAgent.status, "codex-stdio-feasible");
assert.equal(payload.codeAgent.ready, true);
assert.equal(payload.codeAgent.provider, "codex-stdio");
assert.equal(payload.codeAgent.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.codeAgent.runner.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.codeAgent.runner.codexStdio, true);
assert.equal(payload.codeAgent.runner.writeCapable, true);
assert.equal(payload.codeAgent.runner.durableSession, true);
assert.equal(payload.codeAgent.workspace, workspace);
assert.equal(payload.codeAgent.sandbox, "workspace-write");
assert.equal(payload.codeAgent.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.codeAgent.sessionRegistry.kind, "codex-stdio-session-registry");
assert.deepEqual(payload.codeAgent.sessionRegistry.statuses, ["creating", "ready", "busy", "idle", "timeout", "error", "canceled", "interrupted", "expired", "failed"]);
assert.equal(payload.codeAgent.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.codeAgent.longLivedSessionGate.status, "pass");
assert.equal(payload.readiness.sessionRunner.status, "codex_stdio_ready");
assert.equal(payload.readiness.sessionRunner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.readiness.sessionRunner.codexStdio, true);
assert.equal(payload.readiness.sessionRunner.writeCapable, true);
assert.equal(payload.readiness.sessionRunner.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.readiness.codeAgent.sessionRunner.codexStdio, true);
assert.equal(payload.readiness.codeAgent.sessionRunner.writeCapable, true);
assert.deepEqual(payload.codeAgent.runnerLimitations, [
"hardware-control-via-cloud-api-only",
"no-direct-gateway-link",
"no-direct-box-simu-link",
"no-direct-patch-panel-link",
"secret-values-redacted"
]);
const serialized = JSON.stringify(payload.codeAgent);
assert.equal(serialized.includes("not-codex-stdio"), false);
assert.equal(serialized.includes("not-write-capable"), false);
assert.equal(serialized.includes("process-local-session-registry"), false);
assert.equal(serialized.includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(codexHome, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat sends pwd prompt through real Codex stdio instead of local sidecar", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-pwd-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const codexAppServerCalls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_pwd_real",
createRpcClient: async () => createFakeAppServerClient({
calls: codexAppServerCalls,
text: `真实 Codex stdio 回复:当前工作目录是 ${workspace}`
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: manager,
callCodeAgentProvider: async () => {
throw new Error("OpenAI fallback must not handle Codex stdio pwd");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_pwd_sidecar",
traceId: "trc_server_stdio_pwd_sidecar",
message: "用pwd列出你当前的工作目录"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.workspace, workspace);
assert.equal(payload.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.longLivedSessionGate.status, "pass");
assert.equal(payload.providerTrace.sidecarOnly, undefined);
assert.equal(payload.providerTrace.toolName, "codex-app-server.thread/start+turn/start");
assert.deepEqual(codexAppServerCalls.filter((call) => call.method !== "initialize").map((call) => call.method), ["thread/start", "turn/start"]);
assert.match(codexAppServerCalls.find((call) => call.method === "turn/start")?.args?.prompt ?? "", /用pwd列出/u);
assert.ok(payload.toolCalls.some((toolCall) => toolCall.name === "codex-app-server.thread/start+turn/start" && toolCall.status === "completed"));
assert.match(payload.reply.content, /真实 Codex stdio 回复/u);
assert.ok(payload.runnerTrace.events.some((event) => event.label === "prompt:sent"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:codex-app-server.thread/start+turn/start:started"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "assistant:completed"));
assert.equal(JSON.stringify(payload).includes("openai-responses-fallback"), false);
assert.equal(JSON.stringify(payload).includes("text-chat-only"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat answers skills prompt through real Codex stdio and retains trace", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-skills-"));
const codexHome = path.join(workspace, "codex-home");
const skillsDir = path.join(workspace, "skills");
const fakeCodex = await createFakeCodexCommand();
await mkdir(path.join(skillsDir, "hwlab-test-skill"), { recursive: true });
await prepareFakeCodexHome(codexHome);
await writeFile(path.join(skillsDir, "hwlab-test-skill", "SKILL.md"), [
"---",
"name: hwlab-test-skill",
"description: Test skill mounted for Codex stdio discovery.",
"version: v-test",
"---",
"",
"# HWLAB Test Skill"
].join("\n"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_SKILLS_DIRS: skillsDir,
HWLAB_CODE_AGENT_SKILLS_STRICT: "1",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_skills",
createRpcClient: async () => createFakeAppServerClient({
text: "模型泛化回答不应成为 skills 最终回复。"
})
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_skills",
traceId: "trc_server_stdio_skills",
message: "列出你可用的skills"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.providerTrace.sidecarOnly, undefined);
assert.equal(payload.providerTrace.toolName, "codex-app-server.thread/start+turn/start");
assert.equal(payload.skills.status, "ready");
const discovered = payload.skills.items.find((skill) => skill.name === "hwlab-test-skill");
assert.ok(discovered);
assert.equal(discovered.source, path.join(skillsDir, "hwlab-test-skill", "SKILL.md"));
assert.equal(discovered.manifest.path, path.join(skillsDir, "hwlab-test-skill", "SKILL.md"));
assert.equal(discovered.version, "v-test");
assert.ok(payload.toolCalls.some((toolCall) => toolCall.name === "skills.discover" && toolCall.status === "completed"));
assert.match(payload.reply.content, /hwlab-test-skill/u);
assert.match(payload.reply.content, /真实 skill manifest 清单/u);
assert.doesNotMatch(payload.reply.content, /模型泛化回答/u);
assert.ok(payload.runnerTrace.events.some((event) => event.label === "prompt:sent"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:codex-app-server.thread/start+turn/start:started"));
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat handles GitHub access through Codex stdio controlled network check", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-network-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const codexAppServerCalls = [];
const fetchCalls = [];
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_network",
lookupImpl: async () => [{ address: "140.82.114.4", family: 4 }],
fetchImpl: async (url, init) => {
fetchCalls.push({ url: String(url), method: init?.method });
return {
status: 200,
statusText: "OK",
url: "https://github.com/"
};
},
createRpcClient: async () => createFakeAppServerClient({ calls: codexAppServerCalls })
}),
callCodeAgentProvider: async () => {
throw new Error("OpenAI fallback must not handle external network prompts");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_network",
traceId: "trc_server_stdio_network",
message: "访问一下github看看"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.providerTrace.transport, "stdio+controlled-network");
assert.equal(payload.providerTrace.toolName, "external.network.check");
assert.equal(payload.providerTrace.httpStatus, 200);
assert.equal(codexAppServerCalls.some((call) => call.method === "turn/start"), false);
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].url, "https://github.com/");
assert.equal(fetchCalls[0].method, "HEAD");
assert.ok(payload.toolCalls.some((toolCall) =>
toolCall.name === "external.network.check" &&
toolCall.status === "completed" &&
toolCall.httpStatus === 200
));
assert.match(payload.reply.content, /GitHub可以访问/u);
assert.ok(payload.runnerTrace.events.some((event) => event.label === "session:created"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "prompt:sent"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "network:started"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "network:completed"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:external.network.check:completed"));
assert.equal(JSON.stringify(payload).includes("openai-responses-fallback"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat returns structured external network blocker before 150s", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-network-blocked-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
let fetchCalled = false;
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_EXTERNAL_NETWORK: "0",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_network_blocked",
lookupImpl: async () => [{ address: "140.82.114.4", family: 4 }],
fetchImpl: async () => {
fetchCalled = true;
throw new Error("fetch must not run when policy blocks external network");
},
createRpcClient: async () => createFakeAppServerClient()
}),
callCodeAgentProvider: async () => {
throw new Error("OpenAI fallback must not handle blocked external network prompts");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const started = Date.now();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_network_blocked",
traceId: "trc_server_stdio_network_blocked",
message: "看看 github 是否能访问"
});
const elapsed = Date.now() - started;
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.error.code, "external_network_blocked");
assert.equal(payload.blocker.code, "external_network_blocked");
assert.equal(payload.blocker.traceId, "trc_server_stdio_network_blocked");
assert.equal(payload.blocker.sessionId, "ses_server_stdio_network_blocked");
assert.equal(payload.blocker.conversationId, "cnv_server_stdio_network_blocked");
assert.equal(payload.blocker.stage, "policy");
assert.equal(typeof payload.blocker.elapsedMs, "number");
assert.equal(typeof payload.blocker.lastEvent, "object");
assert.equal(payload.toolCalls[0].name, "external.network.check");
assert.equal(payload.toolCalls[0].status, "blocked");
assert.equal(payload.toolCalls[0].blocker.code, "external_network_blocked");
assert.ok(payload.runnerTrace.events.some((event) => event.label === "prompt:sent"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "network:started"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "network:blocked"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:external.network.check:blocked"));
assert.equal(fetchCalled, false);
assert.equal(elapsed < 150000, true);
assert.equal(JSON.stringify(payload).includes("openai-responses-fallback"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat returns network_timeout with preserved runner trace", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-network-timeout-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_SANDBOX: "workspace-write",
HWLAB_CODE_AGENT_EXTERNAL_NETWORK_TIMEOUT_MS: "25",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_network_timeout",
lookupImpl: async () => [{ address: "140.82.114.4", family: 4 }],
fetchImpl: async (_url, init) => new Promise((resolve, reject) => {
init?.signal?.addEventListener("abort", () => {
const error = new Error("aborted");
error.name = "AbortError";
reject(error);
});
}),
createRpcClient: async () => createFakeAppServerClient()
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const started = Date.now();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_network_timeout",
traceId: "trc_server_stdio_network_timeout",
message: "打开 https://github.com 看看"
});
const elapsed = Date.now() - started;
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "timeout");
assert.equal(payload.error.code, "network_timeout");
assert.equal(payload.blocker.code, "network_timeout");
assert.equal(payload.blocker.traceId, "trc_server_stdio_network_timeout");
assert.equal(payload.blocker.sessionId, "ses_server_stdio_network_timeout");
assert.equal(payload.blocker.stage, "http-timeout");
assert.equal(payload.toolCalls[0].status, "blocked");
assert.equal(payload.toolCalls[0].blocker.code, "network_timeout");
assert.ok(payload.runnerTrace.events.some((event) => event.label === "network:timeout"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:external.network.check:blocked"));
assert.equal(elapsed < 150000, true);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat returns structured skills blocker without local skills manifest", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-skills-missing-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_SKILLS_DIRS: path.join(workspace, "missing-skills"),
HWLAB_CODE_AGENT_SKILLS_STRICT: "1",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_skills_missing",
createRpcClient: async () => createFakeAppServerClient({
text: "模型泛化回答:alpha-skill"
})
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_skills_missing",
traceId: "trc_server_stdio_skills_missing",
message: "列出你可用的skills"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.error.code, "skills_unavailable");
assert.equal(payload.skills.status, "blocked");
assert.equal(payload.skills.blockers[0].code, "skills_unavailable");
assert.deepEqual(payload.skills.sourceIssues, ["pikasTech/HWLAB#136", "pikasTech/HWLAB#237"]);
assert.ok(payload.toolCalls.some((toolCall) => toolCall.name === "skills.discover" && toolCall.status === "blocked"));
assert.equal(payload.toolCalls.some((toolCall) => toolCall.name === "codex-app-server.thread/start+turn/start"), false);
assert.equal(payload.session.status, "idle");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(JSON.stringify(payload).includes("alpha-skill"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat routes M3 IO through Skill CLI even when Codex stdio is unavailable", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-skill-"));
const calls = [];
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667",
OPENAI_API_KEY: "must-not-be-used"
},
m3IoSkillRequestJson: async (url, request) => {
calls.push({ url, request });
return {
ok: true,
status: 200,
body: {
serviceId: "hwlab-cloud-api",
contractVersion: "m3-io-control-v1",
status: "succeeded",
accepted: true,
action: "do.write",
traceId: "trc_server-test-m3-skill",
operationId: "op_m3_do_write_server_skill",
auditId: "aud_m3_do_write_server_skill_succeeded",
evidenceId: "evd_m3_do_write_server_skill_succeeded",
auditState: {
status: "written_non_durable"
},
evidenceState: {
status: "blocked",
sourceKind: "BLOCKED",
blocker: "runtime_durable_not_green",
writeStatus: "written_non_durable"
},
durableStatus: {
status: "degraded",
durable: false,
blocker: "runtime_durable_not_green"
},
result: {
value: false,
targetReadback: {
status: "succeeded",
value: false
}
},
controlPath: {
status: "succeeded",
cloudApi: true,
gatewaySimu: true,
boxSimu: true,
patchPanel: true,
frontendBypass: false
}
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-m3-skill"
},
body: JSON.stringify({
conversationId: "cnv_server-test-m3-skill",
message: "通过 HWLAB API 把 res_boxsimu_1 的 DO1 写成 false,然后读取 res_boxsimu_2 的 DI1。"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.backend, "hwlab-cloud-api/hwlab-agent-runtime-skill-cli");
assert.equal(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.ready);
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.responseType, "m3_io_result");
assert.equal(payload.toolCalls.length, 1);
assert.equal(payload.toolCalls[0].name, "hwlab-agent-runtime.m3-io");
assert.equal(payload.toolCalls[0].route, "/v1/m3/io");
assert.equal(payload.toolCalls[0].accepted, true);
assert.equal(Object.hasOwn(payload, "reply"), true);
assert.equal(calls.length, 1);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat recognizes M3 patch-panel topology text before Codex free chat", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-topology-skill-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const calls = [];
const codexStdioCalls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_m3_topology_skill",
createRpcClient: async () => createFakeAppServerClient({
calls: codexStdioCalls,
text: "stdio session ready for controlled topology M3 skill."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667"
},
codexStdioManager: manager,
m3IoSkillRequestJson: async (url, request) => {
calls.push({ url, request });
return {
ok: true,
status: 200,
body: {
serviceId: "hwlab-cloud-api",
contractVersion: "m3-io-control-v1",
status: "succeeded",
accepted: true,
action: "do.write",
traceId: "trc_server-test-m3-topology",
operationId: "op_m3_do_write_topology_skill",
auditId: "aud_m3_do_write_topology_skill",
evidenceId: "evd_m3_do_write_topology_skill",
auditState: {
status: "written_non_durable"
},
evidenceState: {
status: "blocked",
sourceKind: "BLOCKED",
blocker: "runtime_durable_not_green",
writeStatus: "written_non_durable"
},
durableStatus: {
status: "degraded",
durable: false,
blocker: "runtime_durable_not_green"
},
result: {
value: true,
targetReadback: {
status: "succeeded",
value: true,
resourceId: "res_boxsimu_2",
port: "DI1"
}
},
controlPath: {
status: "succeeded",
cloudApi: true,
gatewaySimu: true,
boxSimu: true,
patchPanel: true,
frontendBypass: false
}
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-m3-topology",
traceId: "trc_server-test-m3-topology",
message: "执行 res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 基本闭环,把 DO1 置为 true。"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.backend, "hwlab-cloud-api/hwlab-agent-runtime-skill-cli");
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.sessionMode, "controlled-m3-io-skill-cli");
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.responseType, "m3_io_result");
assert.equal(payload.m3Io.type, "m3_io_result");
assert.equal(payload.m3Io.action, "do.write");
assert.equal(payload.m3Io.do1.targetValue, true);
assert.equal(payload.m3Io.di1.observedValue, true);
assert.equal(payload.m3Io.wiring.label, "res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1");
assert.equal(payload.m3Io.path.summary, "Code Agent -> Skill CLI -> HWLAB API /v1/m3/io");
assert.equal(payload.m3Io.operation.operationId, "op_m3_do_write_topology_skill");
assert.equal(payload.m3Io.trace.traceId, "trc_server-test-m3-topology");
assert.equal(payload.m3Io.session.sessionId, payload.session.sessionId);
assert.equal(payload.m3Io.trust.trusted, false);
assert.equal(payload.m3Io.trust.durable, false);
const skillTool = payload.toolCalls.find((toolCall) => toolCall.name === "hwlab-agent-runtime.m3-io");
assert.ok(skillTool);
assert.equal(skillTool.route, "/v1/m3/io");
assert.equal(skillTool.method, "POST");
assert.equal(skillTool.accepted, true);
assert.equal(skillTool.operationId, "op_m3_do_write_topology_skill");
assert.equal(skillTool.traceId, "trc_server-test-m3-topology");
assert.equal(skillTool.readback.value, true);
assert.equal(payload.providerTrace.fallbackUsed, false);
assert.equal(payload.providerTrace.transport, "skill-cli");
assert.ok(payload.runnerTrace.events.includes("tool:skill-cli:started"));
assert.ok(payload.runnerTrace.events.includes("route:/v1/m3/io"));
assert.match(payload.reply.content, /Code Agent -> Skill CLI -> HWLAB API \/v1\/m3\/io/u);
assert.match(payload.reply.content, /res_boxsimu_1:DO1=true/u);
assert.match(payload.reply.content, /res_boxsimu_2:DI1=true/u);
assert.equal(calls.length, 1);
assert.equal(calls[0].url, "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667/v1/m3/io");
assert.equal(calls[0].request.body.action, "do.write");
assert.equal(calls[0].request.body.value, true);
assert.deepEqual(codexStdioCalls, []);
assert.equal(/https?:\/\/[^\s"']*(?:gateway(?:-simu)?|box(?:-simu)?|patch-panel)|:7101\b|:7201\b|:7301\b|\/invoke\b|\/sync\/tick\b/iu.test(JSON.stringify(payload.toolCalls)), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat returns Skill CLI blocker for M3 topology without DO1 value", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-topology-blocker-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const calls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_m3_topology_blocker",
createRpcClient: async () => createFakeAppServerClient({
text: "stdio session ready for blocked topology M3 skill."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667"
},
codexStdioManager: manager,
m3IoSkillRequestJson: async (url, request) => {
calls.push({ url, request });
throw new Error("missing DO1 value must block before HWLAB API request");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-m3-topology-blocker",
traceId: "trc_server-test-m3-topology-blocker",
message: "执行 res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 基本闭环。"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.backend, "hwlab-cloud-api/hwlab-agent-runtime-skill-cli");
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.sessionMode, "controlled-m3-io-skill-cli");
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.blocked);
assert.equal(payload.responseType, "m3_io_blocker");
assert.equal(payload.m3Io.type, "m3_io_blocker");
assert.equal(payload.m3Io.action, "do.write");
assert.equal(payload.m3Io.do1.targetValue, null);
assert.equal(payload.m3Io.di1.observedValue, null);
assert.equal(payload.m3Io.path.summary, "Code Agent -> Skill CLI -> HWLAB API /v1/m3/io");
assert.equal(payload.m3Io.blocker.code, "invalid_boolean_value");
const skillTool = payload.toolCalls.find((toolCall) => toolCall.name === "hwlab-agent-runtime.m3-io");
assert.ok(skillTool);
assert.equal(skillTool.status, "blocked");
assert.equal(skillTool.route, "/v1/m3/io");
assert.equal(skillTool.blocker.code, "invalid_boolean_value");
assert.equal(skillTool.accepted, false);
assert.equal(skillTool.operationId, null);
assert.equal(payload.blocker.code, "invalid_boolean_value");
assert.match(payload.reply.content, /^M3 IO 阻塞:/u);
assert.match(payload.reply.content, /M3 DO1 写入需要 --value true 或 --value false/u);
assert.match(payload.reply.content, /Code Agent -> Skill CLI -> HWLAB API \/v1\/m3\/io/u);
assert.equal(payload.providerTrace.fallbackUsed, false);
assert.equal(payload.providerTrace.transport, "skill-cli");
assert.equal(calls.length, 0);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat promotes /v1/m3/io blocker into Chinese M3 IO reply", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-api-blocker-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const calls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_m3_api_blocker",
createRpcClient: async () => createFakeAppServerClient({
text: "stdio session ready for M3 API blocker fixture."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667"
},
codexStdioManager: manager,
m3IoSkillRequestJson: async (url, request) => {
calls.push({ url, request });
return {
ok: true,
status: 200,
body: {
serviceId: "hwlab-cloud-api",
contractVersion: "m3-io-control-v1",
route: "/v1/m3/io",
method: "POST",
status: "blocked",
accepted: false,
action: "do.write",
traceId: "trc_server-test-m3-api-blocker",
operationId: "op_m3_do_write_api_blocker",
auditId: "aud_m3_do_write_api_blocker_failed",
evidenceId: "evd_m3_do_write_api_blocker_failed",
blocker: {
code: "m3_wiring_missing",
layer: "hwlab-patch-panel",
zh: "hwlab-patch-panel 未确认 active res_boxsimu_1:DO1 -> res_boxsimu_2:DI1 接线"
},
auditState: {
status: "written_non_durable"
},
evidenceState: {
status: "blocked",
sourceKind: "BLOCKED",
blocker: "runtime_durable_not_green",
writeStatus: "written_non_durable"
},
durableStatus: {
status: "degraded",
durable: false,
blocker: "runtime_durable_not_green"
},
result: {
value: true,
targetReadback: null
},
controlPath: {
status: "blocked",
cloudApi: true,
gatewaySimu: true,
boxSimu: true,
patchPanel: false,
frontendBypass: false
}
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-m3-api-blocker",
traceId: "trc_server-test-m3-api-blocker",
message: "把 M3 DO1 打开,然后读取 DI1。"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.responseType, "m3_io_blocker");
assert.equal(payload.m3Io.type, "m3_io_blocker");
assert.equal(payload.m3Io.action, "do.write");
assert.equal(payload.m3Io.do1.targetValue, true);
assert.equal(payload.m3Io.di1.observedValue, null);
assert.equal(payload.m3Io.blocker.code, "m3_wiring_missing");
assert.equal(payload.blocker.code, "m3_wiring_missing");
assert.match(payload.reply.content, /^M3 IO 阻塞:/u);
assert.match(payload.reply.content, /hwlab-patch-panel 未确认 active/u);
assert.match(payload.reply.content, /res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1/u);
assert.match(payload.reply.content, /trusted=falsedurable=false/u);
assert.equal(calls.length, 1);
assert.equal(new URL(calls[0].url).pathname, "/v1/m3/io");
assert.equal(calls[0].request.body.action, "do.write");
assert.equal(calls[0].request.body.value, true);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat routes M3 Skill CLI through in-process HWLAB API handler", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-stdio-m3-skill-"));
const fakeCodex = await createFakeCodexCommand();
const gatewayCalls = [];
const codexStdioCalls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_m3_skill",
createRpcClient: async () => createFakeAppServerClient({
calls: codexStdioCalls,
text: "stdio session ready for M3 skill."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: workspace,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667",
HWLAB_M3_GATEWAY_SIMU_1_URL: "http://gateway-1",
HWLAB_M3_GATEWAY_SIMU_2_URL: "http://gateway-2",
HWLAB_M3_PATCH_PANEL_URL: "http://patch-panel"
},
codexStdioManager: manager,
m3IoRequestJson: async (url, request) => {
gatewayCalls.push({ url, request });
return m3ReadinessRequestJson(url, request);
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server_stdio_m3_skill",
traceId: "trc_server_stdio_m3_skill",
message: "通过 HWLAB API 把 res_boxsimu_1 的 DO1 写成 true,然后读取 res_boxsimu_2 的 DI1。"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.backend, "hwlab-cloud-api/hwlab-agent-runtime-skill-cli");
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.sessionMode, "controlled-m3-io-skill-cli");
assert.equal(payload.runner.codexStdio, false);
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.codexStdioFeasibility.reason, "m3_io_skill_cli_deterministic_route");
assert.equal(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.ready);
assert.equal(payload.responseType, "m3_io_result");
assert.equal(payload.m3Io.type, "m3_io_result");
assert.equal(payload.m3Io.action, "do.write");
assert.equal(payload.m3Io.do1.targetValue, true);
assert.equal(payload.m3Io.di1.observedValue, true);
assert.equal(payload.m3Io.operation.operationId.startsWith("op_m3_do_write_"), true);
assert.equal(payload.m3Io.session.sessionId, payload.session.sessionId);
assert.equal(payload.m3Io.path.summary, "Code Agent -> Skill CLI -> HWLAB API /v1/m3/io");
assert.equal(payload.m3Io.trust.trusted, false);
assert.equal(payload.m3Io.trust.durable, false);
const skillTool = payload.toolCalls.find((toolCall) => toolCall.name === "hwlab-agent-runtime.m3-io");
assert.ok(skillTool);
assert.equal(skillTool.type, "skill-cli");
assert.equal(skillTool.route, "/v1/m3/io");
assert.equal(skillTool.method, "POST");
assert.equal(skillTool.accepted, true);
assert.equal(skillTool.readback.value, true);
assert.equal(skillTool.controlReady, true);
assert.equal(skillTool.operationId.startsWith("op_m3_do_write_"), true);
assert.match(skillTool.auditId, /^aud_m3_do_write_/u);
assert.match(skillTool.evidenceId, /^evd_m3_do_write_/u);
assert.equal(payload.runnerTrace.route, "/v1/m3/io");
assert.ok(payload.runnerTrace.events.includes("tool:skill-cli:started"));
assert.ok(payload.runnerTrace.events.includes("route:/v1/m3/io"));
assert.equal(payload.providerTrace.fallbackUsed, false);
assert.equal(payload.providerTrace.codexStdio, false);
assert.equal(payload.providerTrace.transport, "skill-cli");
assert.match(payload.reply.content, /HWLAB API \/v1\/m3\/io/u);
assert.match(payload.reply.content, /res_boxsimu_1:DO1=true/u);
assert.match(payload.reply.content, /res_boxsimu_2:DI1=true/u);
assert.ok(payload.runner.toolPolicy.allowed.includes("POST /v1/m3/io"));
assert.deepEqual(gatewayCalls.map((call) => new URL(call.url).pathname), [
"/status",
"/invoke",
"/sync/tick",
"/status",
"/invoke"
]);
assert.deepEqual(codexStdioCalls, []);
assert.equal(/https?:\/\/[^\s"']*(?:gateway(?:-simu)?|box(?:-simu)?|patch-panel)|:7101\b|:7201\b|:7301\b|\/invoke\b|\/sync\/tick\b/iu.test(JSON.stringify(payload.toolCalls)), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat blocks direct M3 API base targets before Codex stdio", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-direct-target-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const calls = [];
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_m3_direct_block",
createRpcClient: async () => createFakeAppServerClient({
text: "stdio session ready for blocked M3 direct target."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_HWLAB_API_BASE_URL: "http://hwlab-gateway-simu-1.hwlab-dev.svc.cluster.local:7101"
},
codexStdioManager: manager,
m3IoSkillRequestJson: async (url, request) => {
calls.push({ url, request });
throw new Error("direct gateway target must be blocked before requestJson");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-m3-direct-target",
traceId: "trc_server-test-m3-direct-target",
message: "读取 M3 DI1"
});
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.sessionMode, "controlled-m3-io-skill-cli");
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.blocked);
assert.equal(payload.responseType, "m3_io_blocker");
assert.equal(payload.m3Io.type, "m3_io_blocker");
assert.equal(payload.m3Io.blocker.code, "direct_hardware_target_blocked");
assert.equal(payload.toolCalls.length, 1);
const skillTool = payload.toolCalls[0];
assert.equal(skillTool.name, "hwlab-agent-runtime.m3-io");
assert.equal(skillTool.status, "blocked");
assert.equal(skillTool.route, "/v1/m3/io");
assert.equal(skillTool.method, "POST");
assert.equal(skillTool.blocker.code, "direct_hardware_target_blocked");
assert.equal(skillTool.hwlabApi.redactedUrl, null);
assert.equal(payload.skills.blockers[0].code, "direct_hardware_target_blocked");
assert.equal(calls.length, 0);
assert.equal(/https?:\/\/[^\s"']*(?:gateway(?:-simu)?|box(?:-simu)?|patch-panel)|:7101\b|:7201\b|:7301\b|\/invoke\b|\/sync\/tick\b/iu.test(JSON.stringify(payload.toolCalls)), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat reports M3 Skill CLI missing API base before Codex stdio", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-m3-api-base-missing-"));
const codexHome = path.join(workspace, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_stdio_m3_api_base_missing",
createRpcClient: async () => createFakeAppServerClient({
text: "stdio session ready for missing M3 API base."
})
});
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_REQUIRE_HWLAB_API_BASE_URL: "1"
},
codexStdioManager: manager,
m3IoSkillRequestJson: async () => {
throw new Error("missing API base must not call requestJson");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-m3-api-base-missing",
traceId: "trc_server-test-m3-api-base-missing",
message: "读取 M3 DI1"
});
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "hwlab-skill-cli");
assert.equal(payload.runner.kind, "hwlab-m3-io-skill-cli");
assert.equal(payload.sessionMode, "controlled-m3-io-skill-cli");
assert.equal(payload.codexStdioFeasibility.skipped, true);
assert.equal(payload.capabilityLevel, HWLAB_M3_IO_CAPABILITY_LEVELS.blocked);
assert.equal(payload.responseType, "m3_io_blocker");
assert.equal(payload.m3Io.type, "m3_io_blocker");
assert.equal(payload.m3Io.blocker.code, "skill_cli_api_base_missing");
assert.equal(payload.skills.blockers[0].code, "skill_cli_api_base_missing");
assert.equal(payload.toolCalls.length, 1);
const skillTool = payload.toolCalls[0];
assert.equal(skillTool.name, "hwlab-agent-runtime.m3-io");
assert.equal(skillTool.blocker.code, "skill_cli_api_base_missing");
assert.deepEqual(skillTool.blocker.missingConfig, [
"HWLAB_CODE_AGENT_HWLAB_API_BASE_URL",
"HWLAB_API_BASE_URL",
"HWLAB_CLOUD_API_BASE_URL",
"contract:hwlab-agent-runtime.m3-io.apiBaseUrl"
]);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(workspace, { recursive: true, force: true });
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat refuses local file-tool shortcuts when Codex stdio is unavailable", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-file-tools-"));
await writeFile(path.join(workspace, "alpha.txt"), "alpha\nbeta\n", "utf8");
await writeFile(path.join(workspace, "package.json"), "{\"name\":\"sample\"}\n", "utf8");
await mkdir(path.join(workspace, "src"), { recursive: true });
await writeFile(path.join(workspace, "src", "main.mjs"), "export const value = 1;\n", "utf8");
const env = {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: workspace
};
const server = createCloudApiServer({ env });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const first = await postAgent(port, {
conversationId: "cnv_server-test-session-reuse",
traceId: "trc_server-test-session-reuse-ls",
message: "ls ."
});
assert.equal(first.status, "failed");
assert.equal(first.provider, "codex-stdio");
assert.equal(first.runner.kind, "codex-app-server-stdio-runner");
assert.equal(first.capabilityLevel, "blocked");
assert.equal(first.sessionMode, "codex-app-server-stdio-long-lived");
assert.deepEqual(first.toolCalls, []);
assert.equal(Object.hasOwn(first, "reply"), false);
assert.ok(first.runnerTrace.events.some((event) => event.label === "request:accepted"));
assert.ok(first.runnerLimitations.includes("no-controlled-readonly-fallback"));
const second = await postAgent(port, {
conversationId: "cnv_server-test-session-reuse",
traceId: "trc_server-test-session-reuse-cat",
message: "cat alpha.txt"
});
assert.equal(second.status, "failed");
assert.equal(second.provider, "codex-stdio");
assert.deepEqual(second.toolCalls, []);
assert.equal(Object.hasOwn(second, "reply"), false);
const third = await postAgent(port, {
conversationId: "cnv_server-test-session-reuse",
traceId: "trc_server-test-session-reuse-rg",
message: "rg --files ."
});
assert.equal(third.status, "failed");
assert.equal(third.provider, "codex-stdio");
assert.deepEqual(third.toolCalls, []);
assert.equal(Object.hasOwn(third, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat does not use read-only conversation facts as fallback", async () => {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-session-continuity-"));
const workspace = path.join(root, "workspace");
const skillsDir = path.join(root, "skills");
await mkdir(workspace, { recursive: true });
await mkdir(path.join(skillsDir, "alpha"), { recursive: true });
await mkdir(path.join(skillsDir, "beta"), { recursive: true });
await writeFile(path.join(skillsDir, "alpha", "SKILL.md"), [
"---",
"name: alpha-skill",
"description: Alpha skill summary.",
"---",
"",
"# Alpha"
].join("\n"));
await writeFile(path.join(skillsDir, "beta", "SKILL.md"), [
"---",
"name: beta-skill",
"description: Beta skill summary.",
"---",
"",
"# Beta"
].join("\n"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_PROVIDER: "codex-cli",
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "0",
HWLAB_CODE_AGENT_CODEX_COMMAND: "/tmp/hwlab-missing-codex"
},
skillsDirs: [skillsDir],
skillsDirsExact: true
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const first = await postAgent(port, {
conversationId: "cnv_server-session-continuity",
traceId: "trc_server-session-continuity-pwd",
message: "用pwd列出你当前的工作目录"
});
assert.equal(first.status, "failed");
assert.equal(first.provider, "codex-stdio");
assert.equal(first.runner.kind, "codex-app-server-stdio-runner");
assert.equal(first.capabilityLevel, "blocked");
assert.equal(first.conversationFacts.turnCount, 0);
const second = await postAgent(port, {
conversationId: "cnv_server-session-continuity",
traceId: "trc_server-session-continuity-skills",
message: "列出你能使用的所有skill"
});
assert.equal(second.status, "failed");
assert.equal(second.provider, "codex-stdio");
assert.equal(second.skills.status, "not_requested");
assert.equal(second.conversationFacts.turnCount, 0);
const third = await postAgent(port, {
conversationId: "cnv_server-session-continuity",
traceId: "trc_server-session-continuity-context",
message: "根据前两轮结果说明你现在在哪个工作目录、能使用哪些skill"
});
assert.equal(third.status, "failed");
assert.equal(third.provider, "codex-stdio");
assert.equal(third.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(third.runner.kind, "codex-app-server-stdio-runner");
assert.equal(third.capabilityLevel, "blocked");
assert.deepEqual(third.toolCalls, []);
assert.equal(third.conversationFacts.turnCount, 0);
assert.notEqual(third.provider, "openai-responses");
assert.notEqual(third.runner.kind, "openai-responses-fallback");
assert.notEqual(third.runner.kind, "codex-cli-one-shot-ephemeral");
assert.notEqual(third.sessionMode, "ephemeral-one-shot");
assert.equal(Object.hasOwn(third, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat blocks forbidden file paths without leaking values", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-file-block-"));
const server = createCloudApiServer({
env: missingCodexCommandEnv({
HWLAB_CODE_AGENT_WORKSPACE: workspace
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const payload = await postAgent(port, {
conversationId: "cnv_server-test-security-block",
traceId: "trc_server-test-security-block",
message: "cat ../outside.txt"
});
assert.equal(payload.status, "failed");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.deepEqual(payload.toolCalls, []);
assert.equal(payload.capabilityLevel, "blocked");
assert.ok(payload.runnerTrace.events.some((event) => event.label === "codex-stdio:blocked"));
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(JSON.stringify(payload).includes("sk-"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat does not answer skills from local manifest when Codex stdio is blocked", async () => {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-skills-"));
const skillsDir = path.join(root, "skills");
await mkdir(path.join(skillsDir, "alpha"), { recursive: true });
await writeFile(path.join(skillsDir, "alpha", "SKILL.md"), [
"---",
"name: alpha-skill",
"description: Alpha skill summary.",
"version: 1.2.3",
"commit: abc123def456",
"---",
"",
"# Alpha"
].join("\n"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: root
},
skillsDirs: [skillsDir],
skillsDirsExact: true
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
conversationId: "cnv_server-test-skills",
message: "列出你可用的skills"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.skills.status, "not_requested");
assert.deepEqual(payload.toolCalls, []);
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(JSON.stringify(payload).includes("alpha-skill"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat exposes prompt trace immediately while Codex stdio model call is slow", async () => {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-slow-skills-"));
const workspace = path.join(root, "workspace");
const skillsDir = path.join(root, "skills");
await mkdir(workspace, { recursive: true });
await mkdir(path.join(skillsDir, "slow-skill"), { recursive: true });
await writeFile(path.join(skillsDir, "slow-skill", "SKILL.md"), [
"---",
"name: slow-skill",
"description: Slow skill discovery summary.",
"version: 2026.05.23",
"commit: slow12345678",
"---",
"",
"# Slow"
].join("\n"));
const codexHome = path.join(root, "codex-home");
const fakeCodex = await createFakeCodexCommand();
await prepareFakeCodexHome(codexHome);
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
CODEX_HOME: codexHome,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_SKILLS_DIRS: skillsDir,
HWLAB_CODE_AGENT_SKILLS_STRICT: "1",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1:65535/v1/responses"
},
codexStdioManager: createCodexStdioSessionManager({
idFactory: () => "ses_server_test_slow_skills",
createRpcClient: async () => createFakeAppServerClient({
text: "真实 Codex stdio 回复:slow-skill",
delayMs: 120
})
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const chatPromise = fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-slow-skills"
},
body: JSON.stringify({
conversationId: "cnv_server-test-slow-skills",
message: "请列出你可用的所有 skills"
})
});
await delay(40);
const traceResponse = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/trace/trc_server-test-slow-skills`);
assert.equal(traceResponse.status, 200);
const tracePayload = await traceResponse.json();
assert.equal(tracePayload.traceId, "trc_server-test-slow-skills");
assert.equal(tracePayload.eventCount > 0, true);
assert.ok(tracePayload.events.some((event) => event.label === "request:accepted" || event.label === "prompt:sent"));
const response = await chatPromise;
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "completed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.traceId, "trc_server-test-slow-skills");
assert.equal(payload.capabilityLevel, "long-lived-codex-stdio-session");
assert.equal(payload.sessionMode, "codex-app-server-stdio-long-lived");
assert.equal(payload.skills.status, "ready");
assert.equal(payload.skills.items[0].name, "slow-skill");
assert.equal(payload.skills.items[0].traceId, "trc_server-test-slow-skills");
assert.equal(payload.runner.kind, "codex-app-server-stdio-runner");
assert.equal(payload.runnerTrace.traceId, "trc_server-test-slow-skills");
assert.ok(payload.runnerTrace.events.some((event) => event.label === "tool:codex-app-server.thread/start+turn/start:started"));
assert.ok(payload.runnerTrace.events.some((event) => event.label === "assistant:completed"));
assert.equal(Object.hasOwn(payload, "error"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat/cancel cancels in-flight Codex stdio and keeps retry trace", async () => {
const fakeCodex = await createFakeCodexCommand();
const workspace = path.join(fakeCodex.root, "workspace");
const codexHome = path.join(fakeCodex.root, "codex-home");
await mkdir(workspace, { recursive: true });
await prepareFakeCodexHome(codexHome);
const traceStore = createCodeAgentTraceStore();
let toolStartedResolve = null;
const toolStarted = new Promise((resolve) => {
toolStartedResolve = resolve;
});
const manager = createCodexStdioSessionManager({
idFactory: () => "ses_server_test_cancel",
traceStore,
createRpcClient: async () => createFakeAppServerClient({
complete: false,
onTurnStarted: () => toolStartedResolve()
})
});
const server = createCloudApiServer({
traceStore,
codexStdioManager: manager,
env: {
PATH: process.env.PATH,
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: fakeCodex.command,
HWLAB_CODE_AGENT_CODEX_WORKSPACE: workspace,
HWLAB_CODE_AGENT_WORKSPACE: workspace,
HWLAB_CODE_AGENT_CODEX_SANDBOX: "workspace-write",
HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED: "1",
HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR: "repo-owned",
CODEX_HOME: codexHome
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const chatPromise = fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-cancel"
},
body: JSON.stringify({
conversationId: "cnv_server-test-cancel",
message: "请执行一个需要等待的 Codex stdio 请求"
})
});
await toolStarted;
const cancelResponse = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/cancel`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-cancel"
},
body: JSON.stringify({
conversationId: "cnv_server-test-cancel",
sessionId: "ses_server_test_cancel",
traceId: "trc_server-test-cancel"
})
});
assert.equal(cancelResponse.status, 200);
const cancelPayload = await cancelResponse.json();
assert.equal(cancelPayload.status, "canceled");
assert.equal(cancelPayload.canceled, true);
assert.equal(cancelPayload.sessionId, "ses_server_test_cancel");
assert.equal(cancelPayload.session.status, "canceled");
assert.equal(cancelPayload.session.lifecycleStatus, "interrupted");
assert.equal(cancelPayload.sessionLifecycleStatus, "interrupted");
assert.equal(cancelPayload.sessionSummary.requiresNewSession, true);
assert.equal(cancelPayload.lastTraceEvent.label, "cancel:canceled");
const chatResponse = await chatPromise;
assert.equal(chatResponse.status, 200);
const chatPayload = await chatResponse.json();
assert.equal(chatPayload.status, "canceled");
assert.equal(chatPayload.error.code, "codex_stdio_canceled");
assert.equal(chatPayload.session.sessionId, "ses_server_test_cancel");
assert.equal(chatPayload.session.status, "canceled");
assert.equal(chatPayload.session.lifecycleStatus, "interrupted");
assert.equal(chatPayload.sessionLifecycleStatus, "interrupted");
assert.equal(chatPayload.sessionSummary.requiresNewSession, true);
assert.equal(chatPayload.runnerTrace.lastEvent.label, "cancel:canceled");
const traceResponse = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/trace/trc_server-test-cancel`);
assert.equal(traceResponse.status, 200);
const tracePayload = await traceResponse.json();
assert.equal(tracePayload.status, "canceled");
assert.equal(tracePayload.lastEvent.label, "cancel:canceled");
assert.ok(tracePayload.events.some((event) => event.label === "tool:codex-app-server.thread/start+turn/start:started"));
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await rm(fakeCodex.root, { recursive: true, force: true });
}
});
test("cloud api /v1/agent/chat/cancel reports unsupported lifecycle degradation", async () => {
const traceStore = createCodeAgentTraceStore();
traceStore.append("trc_cancel_unsupported", {
type: "request",
status: "running",
label: "request:running",
sessionId: "ses_cancel_unsupported",
sessionStatus: "busy",
sessionLifecycleStatus: "busy"
});
const server = createCloudApiServer({
traceStore,
codexStdioManager: {
get() {
return null;
}
},
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/cancel`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_cancel_unsupported"
},
body: JSON.stringify({
conversationId: "cnv_cancel_unsupported",
sessionId: "ses_cancel_unsupported",
traceId: "trc_cancel_unsupported"
})
});
assert.equal(response.status, 501);
const payload = await response.json();
assert.equal(payload.status, "degraded");
assert.equal(payload.unsupported, true);
assert.equal(payload.degraded, true);
assert.equal(payload.error.code, "cancel_unsupported");
assert.equal(payload.sessionLifecycleStatus, "failed");
assert.equal(payload.sessionSummary.unsupported, true);
assert.match(payload.sessionSummary.userMessage, /unsupported\/degraded/u);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat reports Codex stdio blocker instead of structured skills fallback", async () => {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-no-skills-"));
const skillsDir = path.join(root, "missing-skills");
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: root
},
skillsDirs: [skillsDir],
skillsDirsExact: true
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
conversationId: "cnv_server-test-skills-missing",
message: "列出你可用的skills"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.notEqual(payload.error.code, "skills_unavailable");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.skills.status, "not_requested");
assert.deepEqual(payload.toolCalls, []);
assert.ok(payload.runnerLimitations.includes("no-controlled-readonly-fallback"));
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat does not run unsupported local grep fallback", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-tool-blocked-"));
const server = createCloudApiServer({
env: {
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: workspace
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
conversationId: "cnv_server-test-tool-unavailable",
message: "请用grep搜索 package.json"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.notEqual(payload.error.code, "tool_unavailable");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.deepEqual(payload.toolCalls, []);
assert.ok(payload.runnerLimitations.includes("no-controlled-readonly-fallback"));
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat ignores OpenAI fallback and blocks when Codex stdio is unavailable", async () => {
const providerRequests = [];
const providerServer = createHttpServer((request, response) => {
const chunks = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
const bodyText = Buffer.concat(chunks).toString("utf8");
const body = JSON.parse(bodyText);
providerRequests.push({
method: request.method,
url: request.url,
authorizationPresent: Boolean(request.headers.authorization),
accept: request.headers.accept,
contentType: request.headers["content-type"],
body
});
response.writeHead(200, {
"content-type": "text/event-stream"
});
response.end([
`data: ${JSON.stringify({
type: "response.created",
response: {
id: "resp_server_test_stream",
model: body.model,
usage: null
}
})}`,
`data: ${JSON.stringify({
type: "response.output_text.delta",
response_id: "resp_server_test_stream",
delta: "HWLAB Code Agent "
})}`,
`data: ${JSON.stringify({
type: "response.output_text.delta",
response_id: "resp_server_test_stream",
delta: "streaming ready."
})}`,
`data: ${JSON.stringify({
type: "response.completed",
response: {
id: "resp_server_test_stream",
model: body.model,
usage: null
}
})}`,
"data: [DONE]",
""
].join("\n\n"));
});
});
await new Promise((resolve) => providerServer.listen(0, "127.0.0.1", resolve));
const providerPort = providerServer.address().port;
const server = createCloudApiServer({
env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-agent-chat-stream"
},
body: JSON.stringify({
conversationId: "cnv_server-test-agent-chat-stream",
message: "请用一句话说明当前 HWLAB 工作台可以做什么。"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.conversationId, "cnv_server-test-agent-chat-stream");
assert.equal(payload.traceId, "trc_server-test-agent-chat-stream");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.model, "gpt-test");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(JSON.stringify(payload).includes("test-openai-key-material"), false);
assert.equal(providerRequests.length, 0);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
providerServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat does not call delayed provider fallback beyond legacy 4500ms UI timeout", async () => {
let providerCalled = false;
const server = createCloudApiServer({
callCodeAgentProvider: async ({ providerPlan, message, traceId }) => {
providerCalled = true;
await delay(4700);
return {
provider: providerPlan.provider,
model: providerPlan.model,
backend: providerPlan.backend,
content: `延迟真实 provider stub: ${message} / ${traceId}`,
usage: null,
providerTrace: {
source: "delayed-test-provider"
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const startedAt = Date.now();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-agent-chat-delayed"
},
body: JSON.stringify({
conversationId: "cnv_server-test-agent-chat-delayed",
message: "请用一句话说明当前 HWLAB 工作台可以做什么,稍后回答"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(Date.now() - startedAt < 4500, true);
assert.equal(payload.status, "failed");
assert.equal(payload.conversationId, "cnv_server-test-agent-chat-delayed");
assert.equal(payload.traceId, "trc_server-test-agent-chat-delayed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.capabilityLevel, "blocked");
assert.equal(providerCalled, false);
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat skips delayed provider fallback when Codex stdio is unavailable", async () => {
let providerCalled = false;
const server = createCloudApiServer({
env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1/provider-fixture"
}),
callCodeAgentProvider: async ({ providerPlan }) => {
providerCalled = true;
await delay(4600);
const error = new Error("OpenAI Responses returned HTTP 503: slow upstream rejected");
error.code = "provider_unavailable";
error.provider = providerPlan.provider;
error.model = providerPlan.model;
error.backend = providerPlan.backend;
error.providerStatus = 503;
throw error;
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const startedAt = Date.now();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-agent-chat-delayed-failure"
},
body: JSON.stringify({
conversationId: "cnv_server-test-agent-chat-delayed-failure",
message: "请等待后返回 provider 失败分类"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(Date.now() - startedAt < 4500, true);
assert.equal(payload.status, "failed");
assert.equal(payload.traceId, "trc_server-test-agent-chat-delayed-failure");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.availability.fallback.backend, "hwlab-cloud-api/openai-responses");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(providerCalled, false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat reports Codex stdio blocker instead of provider timeout fallback", async () => {
const providerServer = createHttpServer((request, response) => {
request.resume();
setTimeout(() => {
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ output_text: "too late" }));
}, 250);
});
await new Promise((resolve) => providerServer.listen(0, "127.0.0.1", resolve));
const providerPort = providerServer.address().port;
const server = createCloudApiServer({
env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
}),
codeAgentTimeoutMs: 50
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_server-test-agent-chat-provider-timeout"
},
body: JSON.stringify({
conversationId: "cnv_server-test-agent-chat-provider-timeout",
message: "请等待后回答"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.traceId, "trc_server-test-agent-chat-provider-timeout");
assert.equal(payload.error.code, "codex_cli_binary_missing");
assert.equal(payload.error.layer, "runner");
assert.equal(payload.error.retryable, false);
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(payload.availability.endpoint, "POST /v1/agent/chat");
assert.equal(payload.availability.runner.kind, "codex-app-server-stdio-runner");
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
providerServer.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/agent/chat does not call OpenAI provider 502/503 fallback", async () => {
for (const status of [502, 503]) {
const providerServer = createHttpServer((request, response) => {
request.resume();
response.writeHead(status, { "content-type": "application/json" });
response.end(JSON.stringify({
error: {
message: `upstream ${status}`
}
}));
});
await new Promise((resolve) => providerServer.listen(0, "127.0.0.1", resolve));
const providerPort = providerServer.address().port;
const server = createCloudApiServer({
env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": `trc_server-test-agent-chat-provider-${status}`
},
body: JSON.stringify({
conversationId: `cnv_server-test-agent-chat-provider-${status}`,
message: `provider ${status}`
})
});
assert.equal(response.status, 200);
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.equal(payload.error.blocker.traceId, `trc_server-test-agent-chat-provider-${status}`);
assert.equal(payload.error.blocker.retryable, false);
assert.equal(payload.error.blocker.capabilityLevel, "blocked");
assert.equal(payload.provider, "codex-stdio");
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
await new Promise((resolve, reject) => {
providerServer.close((error) => (error ? reject(error) : resolve()));
});
}
}
});
test("cloud api /v1/agent/chat reports provider gaps without faking a reply", async () => {
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_CODE_AGENT_PROVIDER: "codex-cli",
HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_CODEX_COMMAND: "/tmp/hwlab-missing-codex"
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
message: "你好"
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.match(payload.conversationId, /^cnv_/);
assert.match(payload.messageId, /^msg_/);
assert.equal(payload.status, "failed");
assert.equal(payload.provider, "codex-stdio");
assert.equal(payload.model, "gpt-test");
assert.equal(payload.backend, "hwlab-cloud-api/codex-app-server-stdio");
assert.equal(Number.isNaN(Date.parse(payload.createdAt)), false);
assert.equal(Number.isNaN(Date.parse(payload.updatedAt)), false);
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.userMessage, /Codex CLI binary/u);
assert.match(payload.error.message, /Codex stdio long-lived session is unavailable/u);
assert.equal(payload.availability.status, "blocked");
assert.match(payload.availability.blocker, /Codex CLI command/u);
assert.equal(payload.availability.reason, "codex_cli_binary_missing");
assert.equal(payload.availability.runner.ready, false);
assert.equal(payload.availability.codexStdio.runtimeContract.binary.status, "missing");
assert.equal(payload.availability.codexStdio.runtimeContract.stdioProtocol.status, "blocked");
assert.ok(payload.availability.codexStdio.blockerCodes.includes("codex_cli_binary_missing"));
assert.equal(payload.availability.secretRefs[0].secretName, "hwlab-code-agent-provider");
assert.equal(payload.availability.secretRefs[0].secretKey, "openai-api-key");
assert.equal(payload.availability.secretRefs[0].redacted, true);
assert.match(payload.availability.summary, /will not use controlled-readonly-session-registry/u);
assert.equal(JSON.stringify(payload).includes("sk-"), false);
assert.equal(Object.hasOwn(payload, "reply"), false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
test("cloud api /v1/agent/chat does not call empty provider text fallback", async () => {
let providerCalled = false;
const server = createCloudApiServer({
env: missingCodexCommandEnv(),
callCodeAgentProvider: async () => {
providerCalled = true;
throw new Error("empty provider fallback must not be used");
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json"
},
body: JSON.stringify({
conversationId: "cnv_empty-provider-text",
message: "你好"
})
});
assert.equal(response.status, 200);
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.equal(payload.provider, "codex-stdio");
assert.equal(Object.hasOwn(payload, "reply"), false);
assert.equal(providerCalled, false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1 exposes M3 IO control contract without generic frontend hardware RPC", async () => {
const server = createCloudApiServer({
env: {
HWLAB_M3_IO_CONTROL_ENABLED: "true",
HWLAB_M3_GATEWAY_SIMU_1_URL: "http://gateway-1",
HWLAB_M3_GATEWAY_SIMU_2_URL: "http://gateway-2",
HWLAB_M3_PATCH_PANEL_URL: "http://patch-panel"
},
m3IoRequestJson: m3ReadinessRequestJson
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const index = await fetch(`http://127.0.0.1:${port}/v1`);
assert.equal(index.status, 200);
const indexPayload = await index.json();
assert.equal(indexPayload.m3IoControl.route, "/v1/m3/io");
assert.equal(indexPayload.m3IoControl.boundaries.directFrontendGatewayOrBoxAccess, false);
assert.ok(indexPayload.methods.includes("m3.io.do.write"));
assert.ok(indexPayload.methods.includes("m3.io.di.read"));
const contract = await fetch(`http://127.0.0.1:${port}/v1/m3/io`);
assert.equal(contract.status, 200);
const payload = await contract.json();
assert.equal(payload.status, "available");
assert.equal(payload.controlReady, true);
assert.equal(payload.readiness.status, "ready");
assert.equal(payload.chain.sourceResourceId, "res_boxsimu_1");
assert.equal(payload.chain.targetResourceId, "res_boxsimu_2");
assert.equal(payload.boundaries.frontendCallsOnly, "/v1/m3/io");
assert.equal(payload.boundaries.patchPanelOwnsPropagation, true);
assert.equal(payload.boundaries.genericHardwareRpcExposedToFrontend, false);
const statusResponse = await fetch(`http://127.0.0.1:${port}/v1/m3/status`);
assert.equal(statusResponse.status, 200);
const statusPayload = await statusResponse.json();
assert.equal(statusPayload.route, "/v1/m3/status");
assert.equal(statusPayload.chain.sourceResourceId, "res_boxsimu_1");
assert.equal(statusPayload.chain.targetResourceId, "res_boxsimu_2");
assert.equal(statusPayload.gateways.length, 2);
assert.equal(statusPayload.gateways.every((gateway) => gateway.online === true), true);
assert.equal(statusPayload.boxes.find((box) => box.resourceId === "res_boxsimu_1").ports.DO1.value, false);
assert.equal(statusPayload.boxes.find((box) => box.resourceId === "res_boxsimu_2").ports.DI1.value, false);
assert.equal(statusPayload.patchPanel.connectionActive, true);
assert.equal(statusPayload.io.status, "live");
assert.equal(statusPayload.io.do1.resourceId, "res_boxsimu_1");
assert.equal(statusPayload.io.do1.port, "DO1");
assert.equal(statusPayload.io.do1.value, false);
assert.equal(statusPayload.io.do1.sourceKind, "DEV-LIVE");
assert.equal(statusPayload.io.di1.resourceId, "res_boxsimu_2");
assert.equal(statusPayload.io.di1.port, "DI1");
assert.equal(statusPayload.io.di1.value, false);
assert.equal(statusPayload.io.di1.sourceKind, "DEV-LIVE");
assert.equal(statusPayload.io.patchPanel.serviceId, "hwlab-patch-panel");
assert.equal(statusPayload.io.patchPanel.connectionActive, true);
assert.equal(statusPayload.operation.status, "blocked");
assert.equal(statusPayload.operation.operationId, null);
assert.equal(statusPayload.operation.blocker, "runtime_durable_adapter_missing");
assert.equal(statusPayload.trace.status, "blocked");
assert.equal(statusPayload.trace.traceId, null);
assert.equal(statusPayload.trace.blocker, "runtime_durable_adapter_missing");
assert.equal(statusPayload.audit.status, "blocked");
assert.equal(statusPayload.audit.auditId, null);
assert.equal(statusPayload.audit.blocker, "runtime_durable_adapter_missing");
assert.equal(statusPayload.runtimeDurable.status, "blocked");
assert.equal(statusPayload.runtimeDurable.green, false);
assert.equal(statusPayload.runtimeDurable.blocker, "runtime_durable_adapter_missing");
assert.equal(statusPayload.runtimeDurable.readStatus.audit, "read");
assert.equal(statusPayload.runtimeDurable.readStatus.evidence, "read");
assert.equal(statusPayload.runtimeDurable.auditReady, true);
assert.equal(statusPayload.runtimeDurable.evidenceReady, true);
assert.equal(statusPayload.trust.durableStatus, "blocked");
assert.notEqual(statusPayload.trust.durableStatus, "green");
assert.equal(statusPayload.trust.runtime.blocker, "runtime_durable_adapter_missing");
assert.equal(statusPayload.boundaries.frontendCallsOnly, "/v1/m3/status");
assert.equal(statusPayload.boundaries.directFrontendGatewayOrBoxAccess, false);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/m3/status clears nested runtime blocker when trusted durable evidence is green", async () => {
const server = createCloudApiServer({
runtimeStore: createGreenM3StatusRuntimeStore({ blocker: "runtime_durable_not_green" }),
env: {
HWLAB_M3_GATEWAY_SIMU_1_URL: "http://gateway-1",
HWLAB_M3_GATEWAY_SIMU_2_URL: "http://gateway-2",
HWLAB_M3_PATCH_PANEL_URL: "http://patch-panel"
},
m3IoRequestJson: m3ReadinessRequestJson
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const statusResponse = await fetch(`http://127.0.0.1:${port}/v1/m3/status`);
assert.equal(statusResponse.status, 200);
const statusPayload = await statusResponse.json();
assert.equal(statusPayload.contractVersion, "m3-status-v1");
assert.equal(statusPayload.status, "live");
assert.equal(statusPayload.sourceKind, "DEV-LIVE");
assert.equal(statusPayload.patchPanel.connectionActive, true);
assert.equal(statusPayload.trust.durableStatus, "green");
assert.equal(statusPayload.trust.blocker, null);
assert.equal(statusPayload.trust.runtime.status, "ready");
assert.equal(statusPayload.trust.runtime.blocker, null);
assert.equal(statusPayload.trust.operationId, "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f");
assert.equal(statusPayload.trust.traceId, "trc_hotfix_307_verify_1779527747043_read_false");
assert.equal(statusPayload.trust.auditId, "aud_m3_di_read_d5afd84b-3a9d-475f-894f-dff8ea5f49ff_succeeded");
assert.equal(statusPayload.trust.evidenceId, "evd_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f_succeeded");
assert.equal(statusPayload.operation.status, "read");
assert.equal(statusPayload.operation.operationId, "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f");
assert.equal(statusPayload.operation.blocker, null);
assert.equal(statusPayload.trace.status, "read");
assert.equal(statusPayload.trace.traceId, "trc_hotfix_307_verify_1779527747043_read_false");
assert.equal(statusPayload.trace.blocker, null);
assert.equal(statusPayload.audit.status, "read");
assert.equal(statusPayload.audit.auditId, "aud_m3_di_read_d5afd84b-3a9d-475f-894f-dff8ea5f49ff_succeeded");
assert.equal(statusPayload.audit.blocker, null);
assert.equal(statusPayload.runtimeDurable.status, "green");
assert.equal(statusPayload.runtimeDurable.green, true);
assert.equal(statusPayload.runtimeDurable.blocker, null);
assert.equal(statusPayload.runtimeDurable.auditReady, true);
assert.equal(statusPayload.runtimeDurable.evidenceReady, true);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/diagnostics/gate exposes Chinese single-table rows from live backend aggregation", async () => {
const runtimeStore = createCloudRuntimeStore({
now: () => "2026-05-23T00:00:00.000Z"
});
const server = createCloudApiServer({
runtimeStore,
env: {
HWLAB_M3_GATEWAY_SIMU_1_URL: "http://gateway-1",
HWLAB_M3_GATEWAY_SIMU_2_URL: "http://gateway-2",
HWLAB_M3_PATCH_PANEL_URL: "http://patch-panel",
HWLAB_COMMIT_ID: "abc123456789",
HWLAB_IMAGE_TAG: "abc1234"
},
m3IoRequestJson: async () => ({
ok: false,
status: 503,
body: {
error: {
message: "gateway offline"
}
}
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/diagnostics/gate`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.route, "/v1/diagnostics/gate");
assert.equal(payload.contractVersion, "gate-diagnostics-table-v1");
assert.equal(payload.sourceKind, "LIVE-BACKEND");
assert.equal(payload.liveBackend, true);
assert.deepEqual(payload.columns, ["类别", "检查项", "状态", "归因对象", "关键细节", "证据/trace", "更新时间", "下一步"]);
assert.equal(payload.safety.frontendHardcodedRows, false);
assert.equal(payload.safety.sourceFixturePromoted, false);
assert.equal(payload.safety.blockedIsGreen, false);
assert.equal(payload.safety.hardwareControlSurface, false);
assert.equal(payload.safety.codeAgentConversationSurface, false);
assert.ok(payload.rows.length >= 6);
assert.ok(payload.rows.every((row) => row.sourceKind === "LIVE-BACKEND"));
assert.ok(payload.rows.every((row) => ["通过", "阻塞", "失败", "待验证", "信息"].includes(row.status)));
assert.ok(payload.rows.some((row) => row.category === "M3" && row.status === "阻塞"));
assert.ok(payload.rows.some((row) => row.check === "/health/live readiness"));
assert.ok(payload.rows.some((row) => row.check === "audit.event.query"));
assert.ok(payload.rows.some((row) => row.check === "evidence.record.query"));
assert.ok(payload.rows.some((row) => row.check === "Cloud API 实况身份" && row.status === "通过"));
assert.equal(
payload.rows.some((row) => row.status === "阻塞" && row.statusKey === "pass"),
false,
"blocked rows must not be mapped to pass"
);
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api /v1/m3/io returns structured blocked payload when gateway is unavailable", async () => {
const runtimeStore = createCloudRuntimeStore({
now: () => "2026-05-23T00:00:00.000Z"
});
const server = createCloudApiServer({
runtimeStore,
env: {
HWLAB_M3_GATEWAY_SIMU_1_URL: "http://gateway-1",
HWLAB_M3_GATEWAY_SIMU_2_URL: "http://gateway-2",
HWLAB_M3_PATCH_PANEL_URL: "http://patch-panel"
},
m3IoRequestJson: async () => ({
ok: false,
status: 503,
body: {
error: {
message: "gateway offline"
}
}
})
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/m3/io`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_http_m3_gateway_missing",
"x-actor-id": "usr_http_m3"
},
body: JSON.stringify({
action: "do.write",
value: true
})
});
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.status, "blocked");
assert.equal(payload.accepted, false);
assert.equal(payload.route, "/v1/m3/io");
assert.equal(payload.method, "POST");
assert.equal(payload.traceId, "trc_http_m3_gateway_missing");
assert.equal(payload.operationId, null);
assert.equal(payload.auditId, null);
assert.equal(payload.evidenceId, null);
assert.equal(payload.audit.status, "not_written");
assert.equal(payload.evidence.status, "blocked");
assert.equal(payload.readback, null);
assert.match(payload.blocker.zh, /gateway 未注册\/不可用/u);
assert.equal(payload.controlPath.cloudApi, true);
assert.equal(payload.controlPath.frontendBypass, false);
assert.equal(payload.evidenceState.sourceKind, "BLOCKED");
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
async function postAgent(port, body) {
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
...(body.traceId ? { "x-trace-id": body.traceId } : {})
},
body: JSON.stringify(body)
});
assert.equal(response.status, 200);
return response.json();
}
async function pollAgentResult(port, traceId) {
let last = null;
for (let attempt = 0; attempt < 20; attempt += 1) {
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat/result/${encodeURIComponent(traceId)}`);
last = {
status: response.status,
body: await response.json()
};
if (response.status === 200) return last.body;
await delay(10);
}
throw new Error(`Code Agent result did not complete: ${JSON.stringify(last)}`);
}
async function createFakeCodexCommand() {
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-fake-codex-"));
const packageRoot = path.join(root, "node_modules", "@openai", "codex");
const command = path.join(packageRoot, "bin", "codex.js");
const native = path.join(root, "node_modules", "@openai", "codex-linux-x64", "vendor", "x86_64-unknown-linux-musl", "codex", "codex");
await mkdir(path.dirname(command), { recursive: true });
await mkdir(path.dirname(native), { recursive: true });
await writeFile(path.join(packageRoot, "package.json"), JSON.stringify({ name: "@openai/codex", version: "0.128.0" }), "utf8");
await writeFile(command, "#!/usr/bin/env node\nconsole.log('codex 0.128.0');\n", "utf8");
await writeFile(native, "#!/bin/sh\nexit 0\n", "utf8");
await chmod(command, 0o755);
await chmod(native, 0o755);
return { root, command };
}
async function prepareFakeCodexHome(codexHome) {
await mkdir(codexHome, { recursive: true });
await writeFile(path.join(codexHome, "config.toml"), "model = \"gpt-test\"\n", "utf8");
await writeFile(path.join(codexHome, "auth.json"), "{\"auth\":\"redacted-test-placeholder\"}\n", "utf8");
return codexHome;
}
function createFakeAppServerClient({ text = "真实 Codex stdio 回复", delayMs = 0, calls = null, complete = true, onTurnStarted = null } = {}) {
let notificationHandler = null;
let turn = 0;
let closed = false;
let closeResolve;
const closedPromise = new Promise((resolve) => {
closeResolve = resolve;
});
return {
closedPromise,
async initialize() {
calls?.push({ method: "initialize" });
return { initialized: true };
},
setNotificationHandler(handler) {
notificationHandler = typeof handler === "function" ? handler : null;
},
async startThread(args) {
calls?.push({ method: "thread/start", args });
const threadId = "thread_server_test_stdio";
notificationHandler?.({ method: "thread/started", params: { thread: { id: threadId } } });
return { threadId };
},
async resumeThread(args) {
calls?.push({ method: "thread/resume", args });
notificationHandler?.({ method: "thread/started", params: { thread: { id: args.threadId } } });
return { threadId: args.threadId };
},
async startTurn(args) {
calls?.push({ method: "turn/start", args });
turn += 1;
const turnId = `turn_server_test_stdio_${turn}`;
notificationHandler?.({ method: "turn/started", params: { turn: { id: turnId } } });
onTurnStarted?.({ args, turnId });
if (!complete) return { turnId };
if (delayMs > 0) await delay(delayMs);
notificationHandler?.({ method: "item/agentMessage/delta", params: { itemId: `item_server_test_stdio_${turn}`, delta: text } });
notificationHandler?.({ method: "item/completed", params: { item: { id: `item_server_test_stdio_${turn}`, type: "agentMessage", text } } });
notificationHandler?.({ method: "turn/completed", params: { turn: { id: turnId, status: "completed" } } });
return { turnId };
},
close() {
if (closed) return;
closed = true;
closeResolve?.({ code: null, signal: "SIGTERM" });
}
};
}
async function postAgentRaw(port, body, headers = {}) {
const response = await fetch(`http://127.0.0.1:${port}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
...headers
},
body
});
return {
status: response.status,
body: await response.json()
};
}
function escapeRegExp(value) {
return String(value).replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
}
function createGreenM3StatusRuntimeStore({ blocker = null } = {}) {
return {
async readiness() {
return {
adapter: "postgres",
durable: true,
durableRequested: true,
durableCapable: true,
ready: true,
status: "ready",
blocker,
reason: "Postgres durable runtime adapter completed live schema, migration, and read readiness queries",
liveRuntimeEvidence: true,
fixtureEvidence: false
};
},
async queryAuditEvents() {
return {
events: [
{
auditId: "aud_m3_di_read_d5afd84b-3a9d-475f-894f-dff8ea5f49ff_succeeded",
traceId: "trc_hotfix_307_verify_1779527747043_read_false",
actorType: "user",
actorId: "usr_m3_operator",
action: "m3.io.di.read",
targetType: "hardware_operation",
targetId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
projectId: "prj_mvp_topology",
gatewaySessionId: "gws_gwsimu_2",
operationId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
serviceId: "hwlab-cloud-api",
outcome: "succeeded",
metadata: {
route: "res_boxsimu_1:DO1->hwlab-patch-panel->res_boxsimu_2:DI1"
},
environment: "dev",
occurredAt: "2026-05-23T00:00:00.000Z"
}
],
count: 1
};
},
async queryEvidenceRecords() {
return {
records: [
{
evidenceId: "evd_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f_succeeded",
projectId: "prj_mvp_topology",
operationId: "op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f",
kind: "trace",
uri: "memory://hwlab-cloud-api/op_m3_di_read_75fc664f-e94f-41e8-816e-aff9fdb3666f/m3-io-control.json",
sha256: "0".repeat(64),
serviceId: "hwlab-cloud-api",
environment: "dev",
metadata: {
traceId: "trc_hotfix_307_verify_1779527747043_read_false",
route: "res_boxsimu_1:DO1->hwlab-patch-panel->res_boxsimu_2:DI1"
},
createdAt: "2026-05-23T00:00:00.000Z"
}
],
count: 1
};
}
};
}