import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; const replayedIntermediateConstraintMigrations = Object.freeze([ "005_device_registry_commands.sql", "007_device_lifecycle_commands.sql", "009_device_sensitive_reference_commands.sql", "011_device_control_resource_commands.sql", "014_device_registry_profile_commands.sql", ]); const finalCommandKindMigration = "016_device_asset_infrastructure_ontology.sql"; const finalCommandKinds = Object.freeze([ "owner_scope.ensure", "project.ensure", "collection.ensure", "project_grant.upsert", "adapter_package.ensure", "adapter_version.register", "model_profile.register", "edge.ensure", "route.ensure", "enrollment_intent.ensure", "device.claim", "device.update", "device.transfer", "discovery.reject", "discovery.expire", "device_credential_binding.upsert", "device_credential_binding.revoke", "device_binding.ensure", "device_binding.revoke", "device_configuration_revision.create", "device_configuration_desired.set", "asset.ensure", "asset_binding.ensure", "asset_binding.close", "infrastructure_host.ensure", "infrastructure_endpoint.ensure", "infrastructure_deployment.ensure", "infrastructure_service_instance.ensure", "health_observation.record", ]); const migrationUrl = new URL( "../migrations/003_device_management_commands.sql", import.meta.url, ); const repositoryUrl = new URL("../src/postgres-repository.mjs", import.meta.url); test("management migration pins idempotency, audit and owner invariants", async () => { const sql = await readFile(migrationUrl, "utf8"); assert.match(sql, /device_project_grants_owner_user_only/); assert.match(sql, /project_role <> 'owner' or principal_kind = 'user'/); assert.match(sql, /add column if not exists project_id uuid references device_projects\(id\)/); assert.match(sql, /create table if not exists device_management_command_receipts/); assert.match(sql, /unique \(actor_ref, command_kind, idempotency_key\)/); assert.match(sql, /request_digest ~ '\^sha256:\[a-f0-9\]\{64\}\$'/); assert.match(sql, /lifecycle_state in \('pending', 'completed'\)/); }); test("management migration stores no tenant, device or credential seed", async () => { const sql = await readFile(migrationUrl, "utf8"); assert.doesNotMatch(sql, /insert\s+into/i); assert.doesNotMatch(sql, /dcctouch|arusnavi|b2|imei/i); assert.doesNotMatch(sql, /password|secret|credential_ref/i); }); test("repository applies management migration after project access", async () => { const source = await readFile(repositoryUrl, "utf8"); const projectAccessIndex = source.indexOf("002_device_project_access.sql"); const managementIndex = source.indexOf("003_device_management_commands.sql"); assert.notEqual(projectAccessIndex, -1); assert.notEqual(managementIndex, -1); assert.ok(projectAccessIndex < managementIndex); }); test("replayed intermediate command constraints do not revalidate historical receipts", async () => { for (const migrationFile of replayedIntermediateConstraintMigrations) { const sql = await readFile( new URL(`../migrations/${migrationFile}`, import.meta.url), "utf8", ); assert.match( sql, /add constraint device_management_command_receipts_command_kind_check[\s\S]+not valid;/, `${migrationFile} must not reject receipts introduced by a later migration`, ); } }); test("final replayed command constraint validates every current command kind", async () => { const sql = await readFile( new URL(`../migrations/${finalCommandKindMigration}`, import.meta.url), "utf8", ); assert.doesNotMatch(sql, /not valid;/); for (const commandKind of finalCommandKinds) { assert.ok( sql.includes(`'${commandKind}'`), `${finalCommandKindMigration} must validate ${commandKind}`, ); } });