import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; const migrationUrl = new URL( "../migrations/002_device_project_access.sql", import.meta.url, ); const repositoryUrl = new URL("../src/postgres-repository.mjs", import.meta.url); test("project access migration defines owner, project, collection and grant boundaries", async () => { const sql = await readFile(migrationUrl, "utf8"); for (const table of [ "device_owner_scopes", "device_projects", "device_collections", "device_collection_members", "device_project_grants", ]) { assert.match(sql, new RegExp(`create table if not exists ${table}`)); } assert.match(sql, /scope_kind in \('company', 'personal'\)/); assert.match(sql, /principal_kind in \('user', 'group'\)/); assert.match( sql, /project_role in \('viewer', 'operator', 'engineer', 'admin', 'owner'\)/, ); assert.match(sql, /unique \(scope_kind, owner_ref\)/); assert.match(sql, /unique \(owner_scope_id, project_key\)/); assert.match(sql, /unique \(project_id, principal_kind, principal_ref\)/); assert.match(sql, /not \(capability_allow && capability_deny\)/); assert.match( sql, /foreign key \(collection_id, project_id\)\s+references device_collections\(id, project_id\)/, ); assert.match( sql, /foreign key \(device_id, project_id\)\s+references device_instances\(id, project_id\)/, ); }); test("project access migration contains 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|token|credential_ref/i); }); test("repository applies project access migration after the foundation", async () => { const source = await readFile(repositoryUrl, "utf8"); const foundationIndex = source.indexOf("001_device_plane_foundation.sql"); const projectAccessIndex = source.indexOf("002_device_project_access.sql"); assert.notEqual(foundationIndex, -1); assert.notEqual(projectAccessIndex, -1); assert.ok(foundationIndex < projectAccessIndex); });