import assert from "node:assert/strict"; import test from "node:test"; import { AUDIT_FIELD_NAMES } from "../audit/index.mjs"; import { ERROR_CODES, validateResponse } from "../protocol/index.mjs"; import { createCloudRuntimeStore } from "../db/runtime-store.mjs"; import { handleJsonRpcRequest } from "./json-rpc.mjs"; test("unknown JSON-RPC method returns an error envelope with audit fields", async () => { const response = await handleJsonRpcRequest({ jsonrpc: "2.0", id: "req_01J00000000000000000000000", method: "hardware.operation.cancel", params: { operationId: "op_01J00000000000000000000000" }, meta: { traceId: "trc_01J00000000000000000000000", actorId: "usr_01J00000000000000000000000", serviceId: "hwlab-cloud-web", environment: "dev" } }); validateResponse(response); assert.equal(response.error.code, ERROR_CODES.methodNotFound); assert.equal(Object.hasOwn(response, "result"), false); const audit = response.error.data.audit; for (const field of AUDIT_FIELD_NAMES) { assert.ok(Object.hasOwn(audit, field), `expected audit.${field}`); } assert.equal(audit.requestId, "req_01J00000000000000000000000"); assert.equal(audit.actor.id, "usr_01J00000000000000000000000"); assert.equal(audit.operation, "hardware.operation.cancel"); assert.equal(audit.target.type, "rpc_method"); assert.equal(audit.result, "rejected"); }); test("system.health includes the redacted DEV DB env contract", async () => { const originalUrl = process.env.HWLAB_CLOUD_DB_URL; const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE; delete process.env.HWLAB_CLOUD_DB_URL; delete process.env.HWLAB_CLOUD_DB_SSL_MODE; try { const response = await handleJsonRpcRequest({ jsonrpc: "2.0", id: "req_01J00000000000000000000002", method: "system.health", params: {}, meta: { traceId: "trc_01J00000000000000000000002", serviceId: "hwlab-cloud-web", environment: "dev" } }); validateResponse(response); assert.equal(response.result.status, "degraded"); assert.equal(response.result.db.status, "blocked"); assert.equal(response.result.db.connected, false); assert.equal(response.result.runtime.durable, false); assert.ok(response.result.db.missingEnv.includes("HWLAB_CLOUD_DB_URL")); assert.equal(response.result.db.secretRefs[0].secretName, "hwlab-cloud-api-dev-db"); assert.equal(response.result.db.secretRefs[0].secretKey, "database-url"); assert.equal(response.result.db.secretRefs[0].redacted, 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; } } }); test("cloud-api runtime accepts register/report/invoke and exposes audit/evidence records", async () => { const runtimeStore = createCloudRuntimeStore({ now: () => "2026-05-21T00:00:00.000Z" }); const context = { runtimeStore }; const meta = { traceId: "trc_01J00000000000000000000010", actorId: "usr_01J00000000000000000000010", serviceId: "hwlab-cloud-web", environment: "dev" }; async function rpc(id, method, params = {}) { const response = await handleJsonRpcRequest( { jsonrpc: "2.0", id, method, params, meta }, context ); validateResponse(response); assert.equal(Object.hasOwn(response, "error"), false, response.error?.message); return response.result; } const gateway = await rpc("req_01J00000000000000000000010", "gateway.session.register", { projectId: "prj_01J00000000000000000000010", gatewaySessionId: "gws_01J00000000000000000000010", gatewayId: "gtw_01J00000000000000000000010", serviceId: "hwlab-gateway-simu", endpoint: "http://127.0.0.1:7101" }); assert.equal(gateway.registered, true); assert.equal(gateway.gatewaySession.status, "connected"); assert.equal(gateway.auditEvent.action, "gateway.session.register"); const resource = await rpc("req_01J00000000000000000000011", "box.resource.register", { projectId: "prj_01J00000000000000000000010", gatewaySessionId: "gws_01J00000000000000000000010", resourceId: "res_01J00000000000000000000010", boxId: "box_01J00000000000000000000010", resourceType: "board", state: "available" }); assert.equal(resource.registered, true); assert.equal(resource.resource.environment, "dev"); const capability = await rpc("req_01J00000000000000000000012", "box.capability.report", { capabilityId: "cap_01J00000000000000000000010", resourceId: "res_01J00000000000000000000010", projectId: "prj_01J00000000000000000000010", name: "shell.exec", direction: "bidirectional", valueType: "object", mutatesState: true }); assert.equal(capability.reported, true); assert.equal(capability.capabilities[0].name, "shell.exec"); const invoke = await rpc("req_01J00000000000000000000013", "hardware.invoke.shell", { projectId: "prj_01J00000000000000000000010", gatewaySessionId: "gws_01J00000000000000000000010", resourceId: "res_01J00000000000000000000010", capabilityId: "cap_01J00000000000000000000010", input: { command: "echo hwlab" } }); assert.equal(invoke.accepted, true); assert.equal(invoke.operation.status, "accepted"); assert.equal(invoke.dispatch.shellExecuted, false); assert.equal(invoke.dispatch.dispatchStatus, "not_connected"); assert.equal(invoke.auditEvent.action, "hardware.invoke.shell"); assert.equal(invoke.evidenceRecord.kind, "trace"); assert.match(invoke.evidenceRecord.sha256, /^[a-f0-9]{64}$/); const audit = await rpc("req_01J00000000000000000000014", "audit.event.query", { projectId: "prj_01J00000000000000000000010" }); assert.equal(audit.count, 5); assert.ok(audit.events.some((event) => event.action === "hardware.operation.request")); assert.ok(audit.events.some((event) => event.action === "hardware.invoke.shell")); const evidence = await rpc("req_01J00000000000000000000015", "evidence.record.query", { projectId: "prj_01J00000000000000000000010" }); assert.equal(evidence.count, 1); assert.equal(evidence.records[0].operationId, invoke.operationId); assert.equal(evidence.records[0].serviceId, "hwlab-cloud-api"); }); test("hardware.operation.request rejects missing registration instead of faking dispatch", async () => { const response = await handleJsonRpcRequest({ jsonrpc: "2.0", id: "req_01J00000000000000000000020", method: "hardware.operation.request", params: { projectId: "prj_01J00000000000000000000020", gatewaySessionId: "gws_01J00000000000000000000020", resourceId: "res_01J00000000000000000000020", capabilityId: "cap_01J00000000000000000000020" }, meta: { traceId: "trc_01J00000000000000000000020", actorId: "usr_01J00000000000000000000020", serviceId: "hwlab-cloud-web", environment: "dev" } }); validateResponse(response); assert.equal(response.error.code, ERROR_CODES.sessionNotFound); assert.equal(response.error.data.audit.operation, "hardware.operation.request"); assert.equal(response.error.data.audit.result, "rejected"); });