919 lines
37 KiB
TypeScript
919 lines
37 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "bun:test";
|
|
|
|
import { handleJsonRpcRequest } from "../cloud/json-rpc.ts";
|
|
import { ERROR_CODES, validateResponse } from "../protocol/index.mjs";
|
|
import {
|
|
RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED,
|
|
RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED,
|
|
RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED,
|
|
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
|
RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED,
|
|
RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED,
|
|
RUNTIME_STORE_KIND_POSTGRES,
|
|
buildPostgresPoolConfig,
|
|
createCloudRuntimeStore,
|
|
createConfiguredCloudRuntimeStore
|
|
} from "./runtime-store.ts";
|
|
import {
|
|
CLOUD_CORE_MIGRATION_ID,
|
|
CLOUD_RUNTIME_DURABLE_ADAPTER_SCHEMA_VERSION,
|
|
CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS
|
|
} from "./schema.ts";
|
|
|
|
test("memory runtime store is never marked durable", () => {
|
|
const store = createCloudRuntimeStore();
|
|
const summary = store.summary();
|
|
|
|
assert.equal(summary.adapter, "memory");
|
|
assert.equal(summary.durable, false);
|
|
assert.equal(summary.status, "degraded");
|
|
assert.equal(summary.ready, undefined);
|
|
assert.equal(summary.adapterContract.secretMaterialRequiredInSource, false);
|
|
assert.equal(summary.durabilityContract.ready, false);
|
|
assert.equal(summary.durabilityContract.status, "blocked");
|
|
assert.equal(summary.durabilityContract.blockedLayer, "adapter");
|
|
assert.equal(summary.durabilityContract.adapterQueryRequired, true);
|
|
assert.equal(summary.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
assert.equal(summary.durabilityContract.secretMaterialRead, false);
|
|
});
|
|
|
|
test("configured postgres runtime classifies auth blocker before schema and migration", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient: {
|
|
async query(sql) {
|
|
assert.match(sql, /information_schema\.columns/u);
|
|
const error = new Error("auth failed");
|
|
error.code = "28P01";
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.adapter, RUNTIME_STORE_KIND_POSTGRES);
|
|
assert.equal(readiness.durable, false);
|
|
assert.equal(readiness.ready, false);
|
|
assert.equal(readiness.status, "blocked");
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED);
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "auth_blocked");
|
|
assert.equal(readiness.gates.auth.status, "blocked");
|
|
assert.equal(readiness.gates.schema.status, "not_checked");
|
|
assert.equal(readiness.gates.migration.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.ready, false);
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "auth");
|
|
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
});
|
|
|
|
test("configured postgres runtime classifies schema driver errors separately from query failures", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
queryClient: {
|
|
async query(sql) {
|
|
assert.match(sql, /information_schema\.columns/u);
|
|
const error = new Error("schema missing");
|
|
error.code = "3F000";
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED);
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "schema_blocked");
|
|
assert.equal(readiness.gates.ssl.status, "ready");
|
|
assert.equal(readiness.gates.auth.status, "ready");
|
|
assert.equal(readiness.gates.schema.status, "blocked");
|
|
assert.equal(readiness.gates.migration.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "schema");
|
|
});
|
|
|
|
test("configured postgres runtime classifies SSL negotiation blocker separately from auth", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
queryClient: {
|
|
async query(sql) {
|
|
assert.match(sql, /information_schema\.columns/u);
|
|
const error = new Error("The server does not support SSL connections");
|
|
error.code = "08P01";
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.adapter, RUNTIME_STORE_KIND_POSTGRES);
|
|
assert.equal(readiness.durable, false);
|
|
assert.equal(readiness.ready, false);
|
|
assert.equal(readiness.status, "blocked");
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED);
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "ssl_negotiation_blocked");
|
|
assert.equal(readiness.connection.errorCode, "08P01");
|
|
assert.equal(readiness.gates.ssl.status, "blocked");
|
|
assert.equal(readiness.gates.auth.status, "not_checked");
|
|
assert.equal(readiness.gates.schema.status, "not_checked");
|
|
assert.equal(readiness.gates.migration.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.ready, false);
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "ssl");
|
|
assert.equal(readiness.durabilityContract.secretMaterialRead, false);
|
|
assert.equal(JSON.stringify(readiness).includes("The server does not support SSL connections"), false);
|
|
});
|
|
|
|
test("postgres pool config makes HWLAB_CLOUD_DB_SSL_MODE authoritative over URL sslmode", () => {
|
|
const disabled = buildPostgresPoolConfig({
|
|
dbUrl: "postgres://hwlab_user:fixture-pass@db.example.test:5432/hwlab?sslmode=require&application_name=hwlab",
|
|
sslMode: "disable",
|
|
timeoutMs: "2500",
|
|
poolMax: "20"
|
|
});
|
|
|
|
assert.equal(disabled.ssl, false);
|
|
assert.equal(disabled.connectionTimeoutMillis, 2500);
|
|
assert.equal(disabled.max, 20);
|
|
const disabledUrl = new URL(disabled.connectionString);
|
|
assert.equal(disabledUrl.searchParams.get("sslmode"), null);
|
|
assert.equal(disabledUrl.searchParams.get("ssl"), null);
|
|
assert.equal(disabledUrl.searchParams.get("application_name"), "hwlab");
|
|
|
|
const required = buildPostgresPoolConfig({
|
|
dbUrl: "postgres://hwlab_user:fixture-pass@db.example.test:5432/hwlab?sslmode=disable",
|
|
sslMode: "require"
|
|
});
|
|
|
|
assert.deepEqual(required.ssl, { rejectUnauthorized: false });
|
|
assert.equal(new URL(required.connectionString).searchParams.get("sslmode"), "require");
|
|
assert.equal(new URL(required.connectionString).searchParams.get("uselibpqcompat"), "true");
|
|
});
|
|
|
|
test("configured postgres runtime passes normalized pool config to pg", async () => {
|
|
const pools = [];
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true",
|
|
HWLAB_CLOUD_DB_PROBE_TIMEOUT_MS: "1800",
|
|
HWLAB_CLOUD_DB_POOL_MAX: "20"
|
|
},
|
|
dbUrl: "postgres://hwlab_user:fixture-pass@db.example.test:5432/hwlab?sslmode=require",
|
|
sslMode: "disable",
|
|
pgModuleLoader: async () => ({
|
|
Pool: class FakePool {
|
|
constructor(config) {
|
|
this.config = config;
|
|
pools.push(this);
|
|
}
|
|
|
|
async query() {
|
|
return { rows: [] };
|
|
}
|
|
}
|
|
})
|
|
});
|
|
|
|
await store.readiness();
|
|
|
|
assert.equal(pools.length, 1);
|
|
assert.equal(pools[0].config.ssl, false);
|
|
assert.equal(pools[0].config.connectionTimeoutMillis, 1800);
|
|
assert.equal(pools[0].config.max, 20);
|
|
assert.equal(new URL(pools[0].config.connectionString).searchParams.get("sslmode"), null);
|
|
assert.equal(store.summary().blocker, RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED);
|
|
assert.equal(store.summary().durabilityContract.blockedLayer, "schema");
|
|
});
|
|
|
|
test("configured postgres runtime classifies pg_hba no-encryption rejection as SSL before auth", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
sslMode: "disable",
|
|
queryClient: {
|
|
async query(sql) {
|
|
assert.match(sql, /information_schema\.columns/u);
|
|
const error = new Error('no pg_hba.conf entry for host "[redacted]", user "[redacted]", database "[redacted]", no encryption');
|
|
error.code = "28000";
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED);
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "ssl_negotiation_blocked");
|
|
assert.equal(readiness.connection.errorCode, "28000");
|
|
assert.equal(readiness.gates.ssl.status, "blocked");
|
|
assert.equal(readiness.gates.auth.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "ssl");
|
|
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
assert.equal(JSON.stringify(readiness).includes("pg_hba.conf"), false);
|
|
});
|
|
|
|
test("configured postgres runtime reports schema blocker without green readiness", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient: {
|
|
async query(sql) {
|
|
assert.match(sql, /information_schema\.columns/u);
|
|
return { rows: [] };
|
|
}
|
|
}
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.adapter, RUNTIME_STORE_KIND_POSTGRES);
|
|
assert.equal(readiness.durable, false);
|
|
assert.equal(readiness.durableRequested, true);
|
|
assert.equal(readiness.ready, false);
|
|
assert.equal(readiness.status, "blocked");
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED);
|
|
assert.equal(readiness.liveRuntimeEvidence, false);
|
|
assert.equal(readiness.fixtureEvidence, false);
|
|
assert.equal(readiness.schema.checked, true);
|
|
assert.ok(readiness.schema.missingTables.includes("gateway_sessions"));
|
|
assert.equal(readiness.migration.checked, false);
|
|
assert.equal(readiness.gates.schema.status, "blocked");
|
|
assert.equal(readiness.gates.migration.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.ready, false);
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "schema");
|
|
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
assert.equal(JSON.stringify(readiness).includes("redacted@db.example"), false);
|
|
});
|
|
|
|
test("configured postgres runtime keeps durable false when migration ledger is missing", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient: createFakePostgresClient({ migrationReady: false })
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.adapter, RUNTIME_STORE_KIND_POSTGRES);
|
|
assert.equal(readiness.durable, false);
|
|
assert.equal(readiness.durableRequested, true);
|
|
assert.equal(readiness.ready, false);
|
|
assert.equal(readiness.status, "blocked");
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED);
|
|
assert.equal(readiness.schema.ready, true);
|
|
assert.equal(readiness.migration.checked, true);
|
|
assert.equal(readiness.migration.ready, false);
|
|
assert.equal(readiness.migration.missing, true);
|
|
assert.equal(readiness.gates.schema.status, "ready");
|
|
assert.equal(readiness.gates.migration.status, "blocked");
|
|
assert.equal(readiness.liveRuntimeEvidence, false);
|
|
assert.equal(readiness.durabilityContract.ready, false);
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "migration");
|
|
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
});
|
|
|
|
test("configured postgres runtime classifies migration query failures separately from generic readiness queries", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
queryClient: createFakePostgresClient({ migrationErrorCode: "57014" })
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED);
|
|
assert.equal(readiness.schema.ready, true);
|
|
assert.equal(readiness.migration.checked, true);
|
|
assert.equal(readiness.migration.errorCode, "57014");
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "migration_blocked");
|
|
assert.equal(readiness.gates.ssl.status, "ready");
|
|
assert.equal(readiness.gates.auth.status, "ready");
|
|
assert.equal(readiness.gates.schema.status, "ready");
|
|
assert.equal(readiness.gates.migration.status, "blocked");
|
|
assert.equal(readiness.gates.durability.status, "not_checked");
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "migration");
|
|
});
|
|
|
|
test("configured postgres runtime classifies durable read query blocker after schema and migration", async () => {
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient: createFakePostgresClient({ migrationReady: true, countErrorCode: "57014" })
|
|
});
|
|
|
|
const readiness = await store.readiness();
|
|
assert.equal(readiness.adapter, RUNTIME_STORE_KIND_POSTGRES);
|
|
assert.equal(readiness.durable, false);
|
|
assert.equal(readiness.ready, false);
|
|
assert.equal(readiness.status, "blocked");
|
|
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
|
|
assert.equal(readiness.schema.ready, true);
|
|
assert.equal(readiness.migration.ready, true);
|
|
assert.equal(readiness.connection.queryAttempted, true);
|
|
assert.equal(readiness.connection.queryResult, "query_blocked");
|
|
assert.equal(readiness.gates.auth.status, "ready");
|
|
assert.equal(readiness.gates.schema.status, "ready");
|
|
assert.equal(readiness.gates.migration.status, "ready");
|
|
assert.equal(readiness.gates.durability.status, "blocked");
|
|
assert.equal(readiness.durabilityContract.ready, false);
|
|
assert.equal(readiness.durabilityContract.blockedLayer, "durability_query");
|
|
assert.equal(readiness.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
});
|
|
|
|
test("JSON-RPC audit/evidence durable queries return blocked errors instead of empty success", async () => {
|
|
const secretDbUrl = "postgres://hwlab_user:super-secret-password@db.example.invalid:5432/hwlab";
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: secretDbUrl,
|
|
queryClient: createFakePostgresClient({ migrationReady: true, countErrorCode: "57014" })
|
|
});
|
|
const context = { runtimeStore: store, dbProbe: { probe: false } };
|
|
const meta = {
|
|
traceId: "trc_01J00000000000000000002000",
|
|
actorId: "usr_01J00000000000000000002000",
|
|
serviceId: "hwlab-cloud-web",
|
|
environment: "dev"
|
|
};
|
|
|
|
for (const [id, method] of [
|
|
["req_01J00000000000000000002001", "audit.event.query"],
|
|
["req_01J00000000000000000002002", "evidence.record.query"]
|
|
]) {
|
|
const response = await handleJsonRpcRequest(
|
|
{
|
|
jsonrpc: "2.0",
|
|
id,
|
|
method,
|
|
params: {
|
|
projectId: "prj_01J00000000000000000002000"
|
|
},
|
|
meta
|
|
},
|
|
context
|
|
);
|
|
|
|
validateResponse(response);
|
|
assert.equal(Object.hasOwn(response, "result"), false);
|
|
assert.equal(response.error.code, ERROR_CODES.internalError);
|
|
assert.equal(response.error.data.method, method);
|
|
assert.equal(response.error.data.adapter, "postgres");
|
|
assert.equal(response.error.data.status, "blocked");
|
|
assert.equal(response.error.data.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
|
|
assert.equal(response.error.data.durable, false);
|
|
assert.equal(response.error.data.durableRequested, true);
|
|
assert.equal(response.error.data.liveRuntimeEvidence, false);
|
|
assert.equal(response.error.data.queryResult, "query_blocked");
|
|
assert.equal(response.error.data.blockedLayer, "durability_query");
|
|
assert.equal(response.error.data.requiredEvidence, RUNTIME_DURABILITY_REQUIRED_EVIDENCE);
|
|
assert.equal(response.error.data.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
assert.equal(response.error.data.secretMaterialRead, false);
|
|
assert.equal(response.error.data.valueRedacted, true);
|
|
assert.equal(response.error.data.endpointRedacted, true);
|
|
assert.equal(Object.hasOwn(response.error.data, "events"), false);
|
|
assert.equal(Object.hasOwn(response.error.data, "records"), false);
|
|
assert.equal(Object.hasOwn(response.error.data, "count"), false);
|
|
|
|
const serialized = JSON.stringify(response);
|
|
assert.equal(serialized.includes("super-secret-password"), false);
|
|
assert.equal(serialized.includes(secretDbUrl), false);
|
|
}
|
|
});
|
|
|
|
test("JSON-RPC audit/evidence table read failures return blocked errors", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true, readErrorCode: "57014" });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_user:another-secret@db.example.invalid:5432/hwlab",
|
|
queryClient
|
|
});
|
|
const context = { runtimeStore: store, dbProbe: { probe: false } };
|
|
const meta = {
|
|
traceId: "trc_01J00000000000000000002200",
|
|
actorId: "usr_01J00000000000000000002200",
|
|
serviceId: "hwlab-cloud-web",
|
|
environment: "dev"
|
|
};
|
|
|
|
for (const [id, method] of [
|
|
["req_01J00000000000000000002201", "audit.event.query"],
|
|
["req_01J00000000000000000002202", "evidence.record.query"]
|
|
]) {
|
|
const response = await handleJsonRpcRequest(
|
|
{
|
|
jsonrpc: "2.0",
|
|
id,
|
|
method,
|
|
params: {
|
|
projectId: "prj_01J00000000000000000002200"
|
|
},
|
|
meta
|
|
},
|
|
context
|
|
);
|
|
|
|
validateResponse(response);
|
|
assert.equal(Object.hasOwn(response, "result"), false);
|
|
assert.equal(response.error.code, ERROR_CODES.internalError);
|
|
assert.equal(response.error.data.method, method);
|
|
assert.equal(response.error.data.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
|
|
assert.equal(response.error.data.queryResult, "query_blocked");
|
|
assert.equal(response.error.data.blockedLayer, "durability_query");
|
|
|
|
const serialized = JSON.stringify(response);
|
|
assert.equal(serialized.includes("another-secret"), false);
|
|
assert.equal(serialized.includes("events"), false);
|
|
assert.equal(serialized.includes("records"), false);
|
|
assert.equal(serialized.includes("\"count\":0"), false);
|
|
}
|
|
});
|
|
|
|
test("JSON-RPC durable queries return successful empty result sets for true empty tables", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient
|
|
});
|
|
const context = { runtimeStore: store, dbProbe: { probe: false } };
|
|
const meta = {
|
|
traceId: "trc_01J00000000000000000002100",
|
|
actorId: "usr_01J00000000000000000002100",
|
|
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 audit = await rpc("req_01J00000000000000000002101", "audit.event.query", {
|
|
projectId: "prj_01J00000000000000000002100"
|
|
});
|
|
assert.deepEqual(audit.events, []);
|
|
assert.equal(audit.count, 0);
|
|
assert.equal(audit.persistence.adapter, "postgres");
|
|
assert.equal(audit.persistence.durable, true);
|
|
assert.equal(audit.persistence.ready, true);
|
|
|
|
const evidence = await rpc("req_01J00000000000000000002102", "evidence.record.query", {
|
|
projectId: "prj_01J00000000000000000002100"
|
|
});
|
|
assert.deepEqual(evidence.records, []);
|
|
assert.equal(evidence.count, 0);
|
|
assert.equal(evidence.persistence.adapter, "postgres");
|
|
assert.equal(evidence.persistence.durable, true);
|
|
assert.equal(evidence.persistence.ready, true);
|
|
});
|
|
|
|
test("configured postgres runtime persists and queries records through query client", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient,
|
|
now: () => "2026-05-22T00:00:00.000Z"
|
|
});
|
|
const context = { runtimeStore: store, dbProbe: { probe: false } };
|
|
const meta = {
|
|
traceId: "trc_01J00000000000000000001000",
|
|
actorId: "usr_01J00000000000000000001000",
|
|
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 health = await rpc("req_01J00000000000000000001000", "system.health");
|
|
assert.equal(health.runtime.adapter, "postgres");
|
|
assert.equal(health.runtime.durable, true);
|
|
assert.equal(health.runtime.durableRequested, true);
|
|
assert.equal(health.runtime.durableCapable, true);
|
|
assert.equal(health.runtime.ready, true);
|
|
assert.equal(health.runtime.liveRuntimeEvidence, true);
|
|
assert.equal(health.runtime.fixtureEvidence, false);
|
|
assert.equal(health.runtime.schema.ready, true);
|
|
assert.equal(health.runtime.migration.ready, true);
|
|
assert.equal(health.runtime.gates.migration.status, "ready");
|
|
assert.equal(health.runtime.gates.durability.status, "ready");
|
|
assert.equal(health.runtime.durabilityContract.ready, true);
|
|
assert.equal(health.runtime.durabilityContract.blockedLayer, null);
|
|
assert.equal(health.runtime.durabilityContract.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
assert.equal(health.readiness.components.runtime, "ready");
|
|
assert.equal(health.readiness.durability.status, "ready");
|
|
assert.equal(health.readiness.durability.dbLiveEvidenceIsDurabilityEvidence, false);
|
|
|
|
await rpc("req_01J00000000000000000001001", "gateway.session.register", {
|
|
projectId: "prj_01J00000000000000000001000",
|
|
gatewaySessionId: "gws_01J00000000000000000001000",
|
|
gatewayId: "gtw_01J00000000000000000001000",
|
|
serviceId: "hwlab-gateway",
|
|
endpoint: "http://127.0.0.1:7101"
|
|
});
|
|
await rpc("req_01J00000000000000000001002", "box.resource.register", {
|
|
projectId: "prj_01J00000000000000000001000",
|
|
gatewaySessionId: "gws_01J00000000000000000001000",
|
|
resourceId: "res_01J00000000000000000001000",
|
|
boxId: "box_01J00000000000000000001000",
|
|
resourceType: "board",
|
|
state: "available"
|
|
});
|
|
await rpc("req_01J00000000000000000001003", "box.capability.report", {
|
|
capabilityId: "cap_01J00000000000000000001000",
|
|
resourceId: "res_01J00000000000000000001000",
|
|
projectId: "prj_01J00000000000000000001000",
|
|
name: "shell.exec",
|
|
direction: "bidirectional",
|
|
valueType: "object",
|
|
mutatesState: true
|
|
});
|
|
const invoke = await rpc("req_01J00000000000000000001004", "hardware.invoke.shell", {
|
|
projectId: "prj_01J00000000000000000001000",
|
|
gatewaySessionId: "gws_01J00000000000000000001000",
|
|
resourceId: "res_01J00000000000000000001000",
|
|
capabilityId: "cap_01J00000000000000000001000",
|
|
input: {
|
|
command: "echo durable"
|
|
}
|
|
});
|
|
|
|
const audit = await rpc("req_01J00000000000000000001005", "audit.event.query", {
|
|
projectId: "prj_01J00000000000000000001000"
|
|
});
|
|
const evidence = await rpc("req_01J00000000000000000001006", "evidence.record.query", {
|
|
projectId: "prj_01J00000000000000000001000"
|
|
});
|
|
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("INSERT INTO gateway_sessions")));
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("INSERT INTO evidence_records")));
|
|
assert.ok(audit.events.some((event) => event.action === "hardware.invoke.shell"));
|
|
assert.equal(evidence.count, 1);
|
|
assert.equal(evidence.records[0].operationId, invoke.operationId);
|
|
});
|
|
|
|
test("configured postgres runtime persists and queries Code Agent trace events", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient,
|
|
now: () => "2026-06-17T03:50:00.000Z"
|
|
});
|
|
|
|
const traceId = "trc_01J00000000000000000002000";
|
|
const write = await store.writeAgentTraceEvent({
|
|
event: {
|
|
traceId,
|
|
seq: 1,
|
|
type: "runner",
|
|
status: "completed",
|
|
label: "runner:completed",
|
|
sessionId: "ses_01J00000000000000000002000",
|
|
message: "turn completed",
|
|
terminal: true,
|
|
createdAt: "2026-06-17T03:50:01.000Z",
|
|
valuesPrinted: false
|
|
}
|
|
});
|
|
const events = await store.queryAgentTraceEvents({ traceId });
|
|
const readiness = await store.readiness();
|
|
|
|
assert.equal(write.written, true);
|
|
assert.equal(write.traceEvent.traceId, traceId);
|
|
assert.equal(write.traceEvent.agentSessionId, "ses_01J00000000000000000002000");
|
|
assert.equal(events.count, 1);
|
|
assert.equal(events.events[0].traceId, traceId);
|
|
assert.equal(events.events[0].terminal, true);
|
|
assert.equal(readiness.counts.agentTraceEvents, 1);
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("CREATE INDEX IF NOT EXISTS idx_agent_trace_events_trace_order")));
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("INSERT INTO agent_trace_events")));
|
|
});
|
|
|
|
test("configured postgres runtime persists and queries Workbench projection state", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient,
|
|
now: () => "2026-06-19T13:05:00.000Z"
|
|
});
|
|
|
|
const write = await store.writeWorkbenchProjectionState({
|
|
projectionState: {
|
|
traceId: "trc_projection_state",
|
|
sessionId: "ses_projection_state",
|
|
conversationId: "cnv_projection_state",
|
|
threadId: "thread-projection-state",
|
|
runId: "run_projection_state",
|
|
commandId: "cmd_projection_state",
|
|
lastSourceSeq: 3700,
|
|
lastProjectedSeq: 129,
|
|
sourceLatestSeq: 3701,
|
|
projectionStatus: "projecting",
|
|
resultSyncState: "pending",
|
|
updatedAt: "2026-06-19T13:05:00.000Z"
|
|
}
|
|
});
|
|
const loaded = await store.getWorkbenchProjectionState({ traceId: "trc_projection_state" });
|
|
const due = await store.queryWorkbenchProjectionStates({ projectionStatuses: ["projecting"], dueAt: "2026-06-19T13:06:00.000Z", limit: 10 });
|
|
const readiness = await store.readiness();
|
|
|
|
assert.equal(write.written, true);
|
|
assert.equal(write.projectionState.lastSourceSeq, 3700);
|
|
assert.equal(write.projectionState.lastAgentRunSeq, 3700);
|
|
assert.equal(loaded.found, true);
|
|
assert.equal(loaded.projectionState.commandId, "cmd_projection_state");
|
|
assert.equal(due.count, 1);
|
|
assert.equal(due.states[0].resultSyncState, "pending");
|
|
assert.equal(readiness.counts.workbenchProjectionStates, 1);
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("CREATE INDEX IF NOT EXISTS idx_workbench_projection_state_status_retry_updated")));
|
|
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("INSERT INTO workbench_projection_state")));
|
|
});
|
|
|
|
test("configured postgres runtime pushes trace event query filters into SQL", async () => {
|
|
const queryClient = createFakePostgresClient({ migrationReady: true });
|
|
const store = createConfiguredCloudRuntimeStore({
|
|
env: {
|
|
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
|
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
|
},
|
|
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
|
queryClient,
|
|
now: () => "2026-06-17T03:50:00.000Z"
|
|
});
|
|
|
|
await store.writeAgentTraceEvent({ event: { traceId: "trc_sql_filter_a", sessionId: "ses_filter_a", seq: 1, level: "info", label: "a", createdAt: "2026-06-17T03:50:01.000Z" } });
|
|
await store.writeAgentTraceEvent({ event: { traceId: "trc_sql_filter_b", sessionId: "ses_filter_b", seq: 1, level: "info", label: "b", createdAt: "2026-06-17T03:50:02.000Z" } });
|
|
|
|
const events = await store.queryAgentTraceEvents({ sessionId: "ses_filter_b" });
|
|
|
|
assert.equal(events.count, 1);
|
|
assert.equal(events.events[0].traceId, "trc_sql_filter_b");
|
|
const select = queryClient.calls.findLast((call) => call.sql.startsWith("SELECT event_json FROM agent_trace_events"));
|
|
assert.match(select.sql, /WHERE agent_session_id = \$1/u);
|
|
assert.deepEqual(select.params, ["ses_filter_b"]);
|
|
});
|
|
|
|
function createFakePostgresClient({
|
|
migrationReady = true,
|
|
migrationErrorCode = null,
|
|
countErrorCode = null,
|
|
readErrorCode = null
|
|
} = {}) {
|
|
const state = {
|
|
gateway_sessions: new Map(),
|
|
box_resources: new Map(),
|
|
box_capabilities: new Map(),
|
|
hardware_operations: new Map(),
|
|
audit_events: new Map(),
|
|
evidence_records: new Map(),
|
|
worker_sessions: new Map(),
|
|
agent_trace_events: new Map(),
|
|
workbench_projection_state: new Map(),
|
|
hwlab_schema_migrations: new Map()
|
|
};
|
|
if (migrationReady) {
|
|
state.hwlab_schema_migrations.set(CLOUD_CORE_MIGRATION_ID, {
|
|
id: CLOUD_CORE_MIGRATION_ID,
|
|
schema_version: CLOUD_RUNTIME_DURABLE_ADAPTER_SCHEMA_VERSION
|
|
});
|
|
}
|
|
const calls = [];
|
|
|
|
return {
|
|
calls,
|
|
async query(sql, params = []) {
|
|
calls.push({ sql, params });
|
|
if (sql.includes("information_schema.columns")) {
|
|
return { rows: schemaRows() };
|
|
}
|
|
if (sql.startsWith("SELECT COUNT(*)::int AS count FROM ")) {
|
|
if (countErrorCode) {
|
|
const error = new Error("count query failed");
|
|
error.code = countErrorCode;
|
|
throw error;
|
|
}
|
|
const table = sql.match(/FROM ([a-z_]+)/u)?.[1];
|
|
return { rows: [{ count: state[table]?.size ?? 0 }] };
|
|
}
|
|
if (sql.startsWith("SELECT id, schema_version FROM hwlab_schema_migrations")) {
|
|
if (migrationErrorCode) {
|
|
const error = new Error("migration query failed");
|
|
error.code = migrationErrorCode;
|
|
throw error;
|
|
}
|
|
const row = state.hwlab_schema_migrations.get(params[0]);
|
|
return { rows: row ? [row] : [] };
|
|
}
|
|
if (sql.startsWith("CREATE INDEX IF NOT EXISTS idx_agent_trace_events_")) {
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("CREATE INDEX IF NOT EXISTS idx_workbench_projection_state_")) {
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("SELECT gateway_session_json FROM gateway_sessions")) {
|
|
return jsonSelect(state.gateway_sessions, params[0], "gateway_session_json");
|
|
}
|
|
if (sql.startsWith("SELECT resource_json FROM box_resources")) {
|
|
return jsonSelect(state.box_resources, params[0], "resource_json");
|
|
}
|
|
if (sql.startsWith("SELECT capability_json FROM box_capabilities")) {
|
|
return jsonSelect(state.box_capabilities, params[0], "capability_json");
|
|
}
|
|
if (sql.startsWith("SELECT event_json FROM audit_events")) {
|
|
if (readErrorCode) {
|
|
const error = new Error("audit read query failed");
|
|
error.code = readErrorCode;
|
|
throw error;
|
|
}
|
|
return { rows: [...state.audit_events.values()].map((record) => ({ event_json: record.event_json })) };
|
|
}
|
|
if (sql.startsWith("SELECT event_json FROM agent_trace_events")) {
|
|
if (readErrorCode) {
|
|
const error = new Error("agent trace event read query failed");
|
|
error.code = readErrorCode;
|
|
throw error;
|
|
}
|
|
const traceId = sql.includes("trace_id = $1") ? params[0] : null;
|
|
const sessionId = sql.includes("agent_session_id = $1") ? params[0] : null;
|
|
const workerSessionId = sql.includes("worker_session_id = $1") ? params[0] : null;
|
|
const level = sql.includes("level = $1") ? params[0] : null;
|
|
const rows = [...state.agent_trace_events.values()]
|
|
.filter((record) => !traceId || record.trace_id === traceId)
|
|
.filter((record) => !sessionId || record.agent_session_id === sessionId)
|
|
.filter((record) => !workerSessionId || record.worker_session_id === workerSessionId)
|
|
.filter((record) => !level || record.level === level)
|
|
.sort((left, right) => String(left.occurred_at).localeCompare(String(right.occurred_at)) || String(left.id).localeCompare(String(right.id)))
|
|
.map((record) => ({ event_json: record.event_json }));
|
|
return { rows };
|
|
}
|
|
if (sql.startsWith("SELECT projection_json FROM workbench_projection_state")) {
|
|
if (readErrorCode) {
|
|
const error = new Error("workbench projection state read query failed");
|
|
error.code = readErrorCode;
|
|
throw error;
|
|
}
|
|
let rows = [...state.workbench_projection_state.values()];
|
|
if (sql.includes("trace_id = $1")) rows = rows.filter((record) => record.trace_id === params[0]);
|
|
if (sql.includes("projection_status = ANY")) {
|
|
const statuses = params.find((param) => Array.isArray(param)) ?? [];
|
|
rows = rows.filter((record) => statuses.includes(record.projection_status));
|
|
}
|
|
if (sql.includes("next_retry_at IS NULL")) {
|
|
const dueAt = params.find((param) => typeof param === "string" && /^\d{4}-\d{2}-\d{2}T/u.test(param));
|
|
rows = rows.filter((record) => !record.next_retry_at || !dueAt || record.next_retry_at <= dueAt);
|
|
}
|
|
rows.sort((left, right) => String(left.updated_at).localeCompare(String(right.updated_at)) || String(left.trace_id).localeCompare(String(right.trace_id)));
|
|
return { rows: rows.map((record) => ({ projection_json: record.projection_json })) };
|
|
}
|
|
if (sql.startsWith("SELECT metadata_json FROM evidence_records")) {
|
|
if (readErrorCode) {
|
|
const error = new Error("evidence read query failed");
|
|
error.code = readErrorCode;
|
|
throw error;
|
|
}
|
|
return { rows: [...state.evidence_records.values()].map((record) => ({ metadata_json: record.metadata_json })) };
|
|
}
|
|
if (sql.startsWith("INSERT INTO gateway_sessions")) {
|
|
state.gateway_sessions.set(params[0], { gateway_session_json: params[6] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO box_resources")) {
|
|
state.box_resources.set(params[0], { resource_json: params[5] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO box_capabilities")) {
|
|
state.box_capabilities.set(params[0], { capability_json: params[3] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO hardware_operations")) {
|
|
state.hardware_operations.set(params[0], { operation_json: params[4] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO audit_events")) {
|
|
state.audit_events.set(params[0], { event_json: params[8] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO evidence_records")) {
|
|
state.evidence_records.set(params[0], { metadata_json: params[5] });
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO agent_trace_events")) {
|
|
state.agent_trace_events.set(params[0], {
|
|
id: params[0],
|
|
trace_id: params[1],
|
|
agent_session_id: params[2],
|
|
worker_session_id: params[3],
|
|
level: params[4],
|
|
message: params[5],
|
|
event_json: params[6],
|
|
occurred_at: params[7]
|
|
});
|
|
return { rows: [] };
|
|
}
|
|
if (sql.startsWith("INSERT INTO workbench_projection_state")) {
|
|
state.workbench_projection_state.set(params[0], {
|
|
trace_id: params[0],
|
|
session_id: params[1],
|
|
conversation_id: params[2],
|
|
thread_id: params[3],
|
|
run_id: params[4],
|
|
command_id: params[5],
|
|
last_agentrun_seq: params[6],
|
|
last_projected_seq: params[7],
|
|
upstream_latest_seq: params[8],
|
|
projection_status: params[9],
|
|
projection_health: params[10],
|
|
result_sync_state: params[11],
|
|
next_retry_at: params[17],
|
|
projection_json: params[18],
|
|
created_at: params[19],
|
|
updated_at: params[20]
|
|
});
|
|
return { rows: [] };
|
|
}
|
|
throw new Error(`unexpected sql: ${sql}`);
|
|
}
|
|
};
|
|
}
|
|
|
|
function schemaRows() {
|
|
return Object.entries(CLOUD_RUNTIME_DURABLE_TABLE_COLUMNS).flatMap(([table, columns]) =>
|
|
columns.map((column) => ({
|
|
table_name: table,
|
|
column_name: column
|
|
}))
|
|
);
|
|
}
|
|
|
|
function jsonSelect(map, id, column) {
|
|
const row = map.get(id);
|
|
return {
|
|
rows: row ? [{ [column]: row[column] }] : []
|
|
};
|
|
}
|