import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; const schemaUrl = new URL( "../migrations/010_device_control_resources.sql", import.meta.url, ); const commandsUrl = new URL( "../migrations/011_device_control_resource_commands.sql", import.meta.url, ); const repositoryUrl = new URL("../src/postgres-repository.mjs", import.meta.url); const appUrl = new URL("../src/app.mjs", import.meta.url); test("control resource schema separates bindings, revisions and current state", async () => { const sql = await readFile(schemaUrl, "utf8"); assert.match(sql, /create table if not exists device_resource_bindings/); assert.match(sql, /pending_external_approval/); assert.match(sql, /external_approval_digest/); assert.match(sql, /device_binding_source_scope_mismatch/); assert.match(sql, /create table if not exists device_configuration_revisions/); assert.match(sql, /create table if not exists device_configuration_state/); assert.match(sql, /device_configuration_revision_scope_mismatch/); assert.match(sql, /unique \(device_id, revision_number\)/); }); test("command ledger has honest ordered states without a transport API", async () => { const sql = await readFile(schemaUrl, "utf8"); const app = await readFile(appUrl, "utf8"); assert.match(sql, /create table if not exists device_commands/); assert.match(sql, /create table if not exists device_command_events/); for (const state of [ "draft", "planned", "awaiting_confirmation", "queued", "dispatched", "acknowledged", "verified", "failed", "expired", "unknown", ]) { assert.match(sql, new RegExp(`'${state}'`)); } assert.match(sql, /device_command_initial_event_invalid/); assert.match(sql, /device_command_event_sequence_invalid/); assert.match(sql, /device_command_event_transition_invalid/); assert.match(sql, /device_command_event_projection_mismatch/); assert.match(sql, /device_command_events_current_projection_guard/); assert.match(sql, /device_command_current_projection_mismatch/); assert.doesNotMatch(app, /device-commands:(?:plan|confirm|dispatch)/); }); test("configuration, command history and audit are append-only", async () => { const sql = await readFile(schemaUrl, "utf8"); for (const table of [ "device_configuration_revisions", "device_command_events", "device_audit_events", ]) { assert.match( sql, new RegExp(`${table}_immutable_guard[\\s\\S]*before update or delete or truncate`), ); } assert.match(sql, /device_immutable_record_mutation_forbidden/); assert.match(sql, /device_transfer_active_resource_binding/); assert.match(sql, /device_transfer_applied_configuration/); assert.match(sql, /device_transfer_nonterminal_command/); }); test("control resource schema contains no seeded device or raw secret material", async () => { const sql = await readFile(schemaUrl, "utf8"); assert.doesNotMatch(sql, /insert\s+into/i); assert.doesNotMatch(sql, /dcctouch|arusnavi|gelios|\bb2\b|imei/i); assert.doesNotMatch(sql, /password\s+text|token\s+text|secret\s+text|raw_command|raw_packet/i); }); test("commands extend receipts only after their schema", async () => { const commands = await readFile(commandsUrl, "utf8"); const repository = await readFile(repositoryUrl, "utf8"); for (const kind of [ "device_binding.ensure", "device_binding.revoke", "device_configuration_revision.create", "device_configuration_desired.set", ]) { assert.match(commands, new RegExp(`'${kind.replace(".", "\\.")}'`)); } const schemaIndex = repository.indexOf("010_device_control_resources.sql"); const commandsIndex = repository.indexOf( "011_device_control_resource_commands.sql", ); assert.notEqual(schemaIndex, -1); assert.notEqual(commandsIndex, -1); assert.ok(schemaIndex < commandsIndex); });