import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { startPostgresFixture } from "./helpers/postgres-fixture.ts"; const runnerPath = fileURLToPath(new URL("../scripts/db-migrate.mjs", import.meta.url)); const recoveryMigration = readFileSync( new URL("../db/migrations/20260807010000_recover_initial_admin_owner.sql", import.meta.url), "utf8", ); const ids = { first: "30000000-0000-4000-8000-000000000001", second: "30000000-0000-4000-8000-000000000002", third: "30000000-0000-4000-8000-000000000003", blocked: "30000000-0000-4000-8000-000000000004", unsynced: "30000000-0000-4000-8000-000000000005", }; const ownerCountSql = ` select count(*) from public.admin_users au join public.admin_user_roles aur on aur.admin_user_id = au.user_id join public.admin_roles ar on ar.id = aur.role_id where au.revoked_at is null and ar.code = 'owner' `; test("Owner recovery grants only one currently loginable synced identity admin", () => { const fixture = startPostgresFixture(); const schemaSql = (sql: string) => fixture.psqlAs( "schema_owner", "schema-owner-test-password", sql, ); try { const migration = spawnSync(process.execPath, [runnerPath], { encoding: "utf8", env: { ...process.env, SCHEMA_DATABASE_URL: fixture.connectionUrl( "schema_owner", "schema-owner-test-password", ), }, }); assert.equal(migration.status, 0, migration.stderr); assert.match(migration.stdout, /applied 20260807010000_recover_initial_admin_owner\.sql/); assert.equal(fixture.psql(ownerCountSql), "0", "a truly empty database stays empty"); schemaSql(` alter table identity.users disable trigger identity_user_business_auth_sync; insert into identity.users (id, name, email, email_verified, email_verified_at, role) values ('${ids.unsynced}', 'Unsynced Admin', 'unsynced-admin@example.com', true, now(), 'admin'); alter table identity.users enable trigger identity_user_business_auth_sync; `); assert.equal( fixture.psql(`select count(*) from auth.users where id = '${ids.unsynced}'`), "0", ); assert.throws( () => schemaSql(recoveryMigration), /admin_owner_recovery_requires_exactly_one_active_identity_admin: found 0/, "an unsynced identity account is not a truly empty database", ); fixture.psqlAs("identity_runtime", "identity-runtime-test-password", ` insert into identity.users (id, name, email, email_verified, email_verified_at, role, banned, ban_expires) values ('${ids.first}', 'First Admin', 'first-admin@example.com', true, now(), ' user , admin ', true, now() - interval '1 hour'), ('${ids.blocked}', 'Blocked Admin', 'blocked-admin@example.com', true, now(), 'admin', true, null) `); schemaSql(recoveryMigration); assert.equal( fixture.psql(` select count(*) from public.admin_users au join public.admin_user_roles aur on aur.admin_user_id = au.user_id join public.admin_roles ar on ar.id = aur.role_id where au.user_id = '${ids.first}' and au.revoked_at is null and ar.code = 'owner' `), "1", ); assert.equal(fixture.psql(ownerCountSql), "1"); fixture.psqlAs("identity_runtime", "identity-runtime-test-password", ` insert into identity.users (id, name, email, email_verified, email_verified_at, role) values ('${ids.second}', 'Second Admin', 'second-admin@example.com', true, now(), 'admin') `); schemaSql(recoveryMigration); assert.equal( fixture.psql(` select string_agg(aur.admin_user_id::text, ',' order by aur.admin_user_id) from public.admin_users au join public.admin_user_roles aur on aur.admin_user_id = au.user_id join public.admin_roles ar on ar.id = aur.role_id where au.revoked_at is null and ar.code = 'owner' `), ids.first, "an existing active Owner makes recovery a no-op", ); schemaSql(` alter table public.admin_users disable trigger admin_users_require_active_owner; update public.admin_users set revoked_at = timestamptz '2026-08-07 01:23:45+00', revoked_by = '${ids.first}' where user_id = '${ids.first}'; alter table public.admin_users enable trigger admin_users_require_active_owner; `); schemaSql(recoveryMigration); assert.equal( fixture.psql(` select string_agg(aur.admin_user_id::text, ',' order by aur.admin_user_id) from public.admin_users au join public.admin_user_roles aur on aur.admin_user_id = au.user_id join public.admin_roles ar on ar.id = aur.role_id where au.revoked_at is null and ar.code = 'owner' `), ids.second, "a revoked historical admin is excluded instead of being restored", ); assert.equal( fixture.psql(` select count(*) from public.admin_users where user_id = '${ids.first}' and revoked_at = timestamptz '2026-08-07 01:23:45+00' and revoked_by = '${ids.first}' `), "1", "recovery preserves the historical revocation fields", ); fixture.psqlAs("identity_runtime", "identity-runtime-test-password", ` insert into identity.users (id, name, email, email_verified, email_verified_at, role) values ('${ids.third}', 'Third Admin', 'third-admin@example.com', true, now(), 'admin') `); schemaSql(` alter table public.admin_user_roles disable trigger admin_user_roles_require_active_owner; delete from public.admin_user_roles where role_id = (select id from public.admin_roles where code = 'owner'); alter table public.admin_user_roles enable trigger admin_user_roles_require_active_owner; `); assert.throws( () => schemaSql(recoveryMigration), /admin_owner_recovery_requires_exactly_one_active_identity_admin: found 2/, ); assert.equal(fixture.psql(ownerCountSql), "0"); fixture.psqlAs("identity_runtime", "identity-runtime-test-password", ` update identity.users set role = 'user' where id in ('${ids.second}', '${ids.third}') `); assert.throws( () => schemaSql(recoveryMigration), /admin_owner_recovery_requires_exactly_one_active_identity_admin: found 0/, "a revoked identity admin remains ineligible even when it is the only admin role", ); } finally { fixture.stop(); } });