import assert from "node:assert/strict"; import { execFile } from "node:child_process"; import path from "node:path"; import test from "node:test"; import { promisify } from "node:util"; import { buildDevRuntimeProvisioningReport, parseArgs } from "./dev-runtime-provisioning.mjs"; const execFileAsync = promisify(execFile); const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), "../.."); const bunCommand = process.env.HWLAB_BUN_COMMAND || (process.versions.bun ? process.execPath : "bun"); test("source check parses target role/database without leaking DB URL material", async () => { const report = await buildDevRuntimeProvisioningReport(parseArgs(["--check"]), { env: { HWLAB_CLOUD_DB_URL: fixturePostgresUrl({ password: fixtureSecret("super") }), HWLAB_CLOUD_DB_SSL_MODE: "disable" }, now: () => "2026-05-23T00:00:00.000Z" }); assert.equal(report.conclusion.status, "ready"); assert.equal(report.actions.liveDbReadAttempted, false); assert.equal(report.actions.liveDbWriteAttempted, false); assert.equal(report.db.targetRoleNamePresent, true); assert.equal(report.db.targetDatabaseNamePresent, true); assert.equal(report.db.targetPasswordPresent, true); assert.equal(report.safety.secretValuesPrinted, false); assertNoFixtureSecrets(report); }); test("cloud-api image provisioning entrypoint exposes non-secret source check", async () => { const { stdout } = await execFileAsync( bunCommand, ["cmd/hwlab-cloud-api/provision.ts", "--check"], { cwd: repoRoot, env: { ...process.env, HWLAB_CLOUD_DB_URL: fixturePostgresUrl({ password: fixtureSecret("super") }), HWLAB_CLOUD_DB_SSL_MODE: "disable" } } ); const report = JSON.parse(stdout); assert.equal(report.conclusion.status, "ready"); assert.equal(report.actions.liveDbReadAttempted, false); assert.equal(report.actions.liveDbWriteAttempted, false); assert.equal(report.db.targetRoleNamePresent, true); assert.equal(report.db.targetDatabaseNamePresent, true); assert.equal(report.db.targetPasswordPresent, true); assert.equal(report.safety.secretValuesPrinted, false); assertNoFixtureSecrets(report); }); test("source check without injected DB URL is ready and performs no live access", async () => { const report = await buildDevRuntimeProvisioningReport(parseArgs(["--check"]), { env: {}, now: () => "2026-05-23T00:00:00.000Z" }); assert.equal(report.conclusion.status, "ready"); assert.equal(report.actions.liveDbReadAttempted, false); assert.equal(report.actions.liveDbWriteAttempted, false); assert.equal(report.blockers.length, 0); assert.equal(report.db.targetUrlPresent, false); assert.equal(report.gates.role.status, "not_checked"); }); test("live dry-run classifies missing target role separately from missing database", async () => { const report = await buildDevRuntimeProvisioningReport( parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]), { env: envWithAdmin(), adminClient: createAdminClient({ roleExists: false, databaseExists: true }), queryClient: createRuntimeClient("auth"), now: () => "2026-05-23T00:00:00.000Z" } ); assert.equal(report.conclusion.status, "blocked"); assert.equal(report.actions.adminInspectionAttempted, true); assert.equal(report.actions.liveDbWriteAttempted, false); assert.equal(report.provisioning.targetRole.exists, false); assert.equal(report.provisioning.targetDatabase.exists, true); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-role"), true); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-database"), false); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-auth"), true); assert.equal( report.blockers.find((blocker) => blocker.scope === "runtime-provisioning-role").evidence.affectedRuntimeBlocker, "runtime_durable_adapter_auth_blocked" ); assert.equal( report.blockers.find((blocker) => blocker.scope === "runtime-provisioning-auth").evidence.blocker, "runtime_durable_adapter_auth_blocked" ); assertNoFixtureSecrets(report); }); test("live dry-run classifies missing target database separately from target role", async () => { const report = await buildDevRuntimeProvisioningReport( parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]), { env: envWithAdmin(), adminClient: createAdminClient({ roleExists: true, databaseExists: false }), queryClient: createRuntimeClient("auth"), now: () => "2026-05-23T00:00:00.000Z" } ); assert.equal(report.conclusion.status, "blocked"); assert.equal(report.provisioning.targetRole.exists, true); assert.equal(report.provisioning.targetDatabase.exists, false); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-role"), false); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-database"), true); assert.equal( report.blockers.find((blocker) => blocker.scope === "runtime-provisioning-database").evidence.affectedRuntimeBlocker, "runtime_durable_adapter_auth_blocked" ); }); test("live dry-run separates SSL from auth/schema/migration", async () => { const report = await buildDevRuntimeProvisioningReport( parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]), { env: envWithAdmin({ sslMode: "require" }), adminClient: createAdminClient({ roleExists: true, databaseExists: true }), queryClient: createRuntimeClient("ssl"), now: () => "2026-05-23T00:00:00.000Z" } ); assert.equal(report.conclusion.status, "blocked"); assert.equal(report.gates.ssl.status, "blocked"); assert.equal(report.gates.auth.status, "not_checked"); assert.equal(report.gates.schema.status, "not_checked"); assert.equal(report.gates.migration.status, "not_checked"); assert.equal(report.blockers.some((blocker) => blocker.scope === "runtime-provisioning-ssl"), true); assert.equal(JSON.stringify(report).includes("does not support SSL"), false); }); test("live dry-run leaves role/database ready while migration remains a downstream blocker", async () => { const report = await buildDevRuntimeProvisioningReport( parseArgs(["--dry-run", "--allow-live-db-read", "--confirm-dev"]), { env: envWithAdmin(), adminClient: createAdminClient({ roleExists: true, databaseExists: true }), queryClient: createRuntimeClient("migration"), now: () => "2026-05-23T00:00:00.000Z" } ); assert.equal(report.conclusion.status, "ready"); assert.equal(report.provisioning.ready, true); assert.equal(report.provisioning.targetRole.ready, true); assert.equal(report.provisioning.targetDatabase.ready, true); assert.equal(report.runtime.blocker, "runtime_durable_adapter_migration_blocked"); assert.equal(report.gates.migration.status, "blocked"); assert.equal(report.blockers.length, 0); }); test("apply creates missing role/database and grants target privileges without printing secrets", async () => { const adminClient = createAdminClient({ roleExists: false, databaseExists: false }); const targetAdminClient = createAdminClient({ roleExists: true, databaseExists: true }); const report = await buildDevRuntimeProvisioningReport( parseArgs(["--apply", "--confirm-dev", "--confirmed-non-production"]), { env: envWithAdmin(), adminClient, queryClient: createRuntimeClient("ready"), now: () => "2026-05-23T00:00:00.000Z", adminDbUrlOverride: null, pgModuleLoader: async () => { throw new Error("pgModuleLoader should not be used when adminClient is injected"); } } ); assert.equal(targetAdminClient.calls.length, 0); assert.equal(report.conclusion.status, "ready"); assert.equal(report.actions.roleCreated, true); assert.equal(report.actions.databaseCreated, true); assert.equal(report.actions.rolePasswordSynchronized, true); assert.equal(report.actions.databaseConnectGranted, true); assert.equal(report.actions.schemaPrivilegesGranted, true); assert.equal(report.provisioning.ready, true); assert.ok(adminClient.calls.some((call) => call.sql.startsWith("CREATE ROLE "))); assert.ok(adminClient.calls.some((call) => call.sql.startsWith("CREATE DATABASE "))); assert.ok(adminClient.calls.some((call) => call.sql.startsWith("GRANT CONNECT ON DATABASE "))); assert.ok(adminClient.calls.some((call) => call.sql.startsWith("GRANT USAGE, CREATE ON SCHEMA public "))); assertNoFixtureSecrets(report); }); function envWithAdmin({ sslMode = "disable" } = {}) { return { HWLAB_CLOUD_DB_URL: fixturePostgresUrl({ password: fixtureSecret("app") }), HWLAB_CLOUD_DB_ADMIN_URL: fixturePostgresUrl({ user: "postgres", password: fixtureSecret("admin"), database: "postgres" }), HWLAB_CLOUD_DB_SSL_MODE: sslMode }; } function fixturePostgresUrl({ user = "hwlab_app", password = fixtureSecret("app"), host = "db.example.test", database = "hwlab_runtime" } = {}) { return `${["postgresql", "://"].join("")}${user}:${password}@${host}:5432/${database}`; } function fixtureSecret(kind) { return `${kind}-${"secret"}`; } function assertNoFixtureSecrets(value) { const text = JSON.stringify(value); for (const forbidden of [ fixtureSecret("super"), fixtureSecret("app"), fixtureSecret("admin"), "db.example.test", "hwlab_app", "hwlab_runtime" ]) { assert.equal(text.includes(forbidden), false); } } function createAdminClient({ roleExists, databaseExists }) { const state = { roleExists, databaseExists, calls: [] }; return { get calls() { return state.calls; }, async query(sql, params = []) { state.calls.push({ sql, params }); if (sql.includes("pg_catalog.pg_roles")) { return { rows: state.roleExists ? [{ present: 1 }] : [] }; } if (sql.includes("pg_catalog.pg_database")) { return { rows: state.databaseExists ? [{ present: 1 }] : [] }; } if (sql.startsWith("CREATE ROLE ")) { state.roleExists = true; return { rows: [] }; } if (sql.startsWith("ALTER ROLE ")) { return { rows: [] }; } if (sql.startsWith("CREATE DATABASE ")) { state.databaseExists = true; return { rows: [] }; } if (sql.startsWith("GRANT CONNECT ON DATABASE ") || sql.startsWith("GRANT USAGE, CREATE ON SCHEMA public ")) { return { rows: [] }; } throw new Error(`unexpected admin query: ${sql}`); } }; } function createRuntimeClient(mode) { return { async query(sql) { if (sql.includes("information_schema.columns")) { if (mode === "ssl") { const error = new Error("fixture SSL blocked: server does not support SSL"); error.code = "08P01"; throw error; } if (mode === "auth") { const error = new Error("fixture auth blocked"); error.code = "28P01"; throw error; } return { rows: schemaRows() }; } if (sql.startsWith("SELECT id, schema_version FROM hwlab_schema_migrations")) { if (mode === "migration") return { rows: [] }; return { rows: [{ id: "0001_cloud_core_skeleton", schema_version: "runtime-durable-postgres-v1" }] }; } if (sql.startsWith("SELECT COUNT(*)::int AS count FROM ")) { return { rows: [{ count: 0 }] }; } throw new Error(`unexpected runtime query: ${sql}`); } }; } function schemaRows() { const schema = { gateway_sessions: ["id", "project_id", "gateway_service_id", "status", "started_at", "ended_at", "gateway_session_json"], box_resources: ["id", "project_id", "gateway_session_id", "resource_state", "labels_json", "resource_json", "updated_at"], box_capabilities: ["id", "box_resource_id", "capability_type", "capability_json", "updated_at"], hardware_operations: ["id", "project_id", "requested_by", "operation_type", "operation_json", "status", "requested_at", "updated_at"], audit_events: ["id", "request_id", "actor", "source", "operation", "target", "result", "timestamp", "event_json"], evidence_records: ["id", "project_id", "operation_id", "evidence_type", "uri", "metadata_json", "created_at"] }; return Object.entries(schema).flatMap(([table, columns]) => columns.map((column) => ({ table_name: table, column_name: column })) ); }