Files
pikasTech-HWLAB/internal/cloud/server.test.mjs
T
2026-05-25 22:10:07 +08:00

2834 lines
106 KiB
JavaScript

import assert from "node:assert/strict";
import { createServer as createHttpServer } from "node:http";
import { createServer as createTcpServer } 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 } 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 assertCodexStdioFeasibilityBlocker(value, label = "codex stdio blocker") {
assert.equal(CODEX_STDIO_FEASIBILITY_BLOCKERS.has(value), true, `${label}: ${value}`);
}
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.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);
} 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,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
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,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
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,
requiredTools: ["codex", "codex-reply"],
toolsObserved: ["codex", "codex-reply"],
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: ["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",
threadId: "thread_server_stdio_pwd",
valuesPrinted: false
}
};
}
test("cloud api /v1 describes Code Agent egress blocker without leaking API key", async () => {
const server = createCloudApiServer({
env: {
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 () => ({
async initialize() {
return { tools: ["codex", "codex-reply"] };
},
async listTools() {
return ["codex", "codex-reply"];
},
close() {}
})
});
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.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 () => ({
async initialize() {
return { tools: ["codex", "codex-reply"] };
},
async listTools() {
return ["codex", "codex-reply"];
},
close() {}
})
});
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 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("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 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 result polling compacts large runnerTrace while preserving providerTrace", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-result-compact-"));
const codexHome = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-result-compact-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",
HWLAB_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT: "32",
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 = {}) {
const base = codexStdioChatFixture({ workspace, codexHome, params });
const events = Array.from({ length: 160 }, (_, index) => ({
seq: index + 1,
traceId: params.traceId,
type: "assistant_message",
status: "chunk",
label: index === 159 ? "assistant:completed" : "assistant:chunk",
createdAt: "2026-05-23T00:00:00.000Z",
waitingFor: index === 159 ? null : "turn/completed",
valuesPrinted: false
}));
return {
...base,
sandbox: "danger-full-access",
session: {
...base.session,
sandbox: "danger-full-access"
},
runnerTrace: {
...base.runnerTrace,
events,
eventLabels: events.map((event) => event.label),
eventCount: events.length,
lastEvent: events.at(-1)
}
};
},
cancel() {},
reapIdle() {}
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const traceId = "trc_server-test-result-compact";
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-result-compact",
message: "生成大量 trace 后返回"
})
});
assert.equal(submit.status, 202);
const payload = await pollAgentResult(port, traceId);
validateCodeAgentChatSchema(payload);
assert.equal(payload.status, "completed");
assert.equal(payload.traceId, traceId);
assert.equal(payload.providerTrace.protocol, "codex-app-server-jsonrpc-stdio");
assert.equal(payload.providerTrace.command, "codex app-server --listen stdio://");
assert.equal(payload.runnerTrace.eventCount, 160);
assert.equal(payload.runnerTrace.eventsCompacted, true);
assert.equal(payload.runnerTrace.events.length, 32);
assert.equal(payload.runnerTrace.events.some((event) => event.label === "trace:compacted"), true);
assert.equal(payload.runnerTrace.lastEvent.label, "assistant:completed");
assert.equal(payload.runnerTrace.eventLabels.includes("trace:compacted"), true);
} 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 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 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 blocks forbidden file paths without leaking values", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-file-block-"));
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 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/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 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 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: {
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()));
});
}
}
});
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({
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 } = {}) {
let notificationHandler = null;
return {
async initialize() {
return { initialized: true };
},
setNotificationHandler(handler) {
notificationHandler = typeof handler === "function" ? handler : null;
},
async startThread() {
notificationHandler?.({ method: "thread/started", params: { thread: { id: "thread_server_test_stdio" } } });
return { threadId: "thread_server_test_stdio" };
},
async resumeThread(args) {
notificationHandler?.({ method: "thread/started", params: { thread: { id: args.threadId } } });
return { threadId: args.threadId };
},
async startTurn() {
const turnId = "turn_server_test_stdio";
notificationHandler?.({ method: "turn/started", params: { turn: { id: turnId } } });
if (delayMs > 0) await delay(delayMs);
notificationHandler?.({ method: "item/agentMessage/delta", params: { itemId: "item_server_test_stdio", delta: text } });
notificationHandler?.({ method: "item/completed", params: { item: { id: "item_server_test_stdio", type: "agentMessage", text } } });
notificationHandler?.({ method: "turn/completed", params: { turn: { id: turnId, status: "completed" } } });
return { turnId };
},
close() {}
};
}
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
};
}
};
}