import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; import { mkdtemp, readFile, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { connect, type Database } from '@tursodatabase/database'; const run = promisify(execFile); let directory: string; let database: Database; let databasePath: string; async function invoke() { try { const result = await run( process.execPath, ['scripts/admin-bootstrap.mjs', 'admin@example.com'], { cwd: process.cwd(), env: { ...process.env, TDR_DATABASE_PATH: databasePath, NODE_ENV: 'test', }, }, ); return { status: 0, stdout: result.stdout, stderr: result.stderr }; } catch (error) { const failure = error as { code?: number; stdout?: string; stderr?: string; }; return { status: Number(failure.code ?? 1), stdout: failure.stdout ?? '', stderr: failure.stderr ?? '', }; } } describe('administrator bootstrap preconditions', () => { beforeEach(async () => { directory = await mkdtemp(join(tmpdir(), 'shd-admin-bootstrap-')); databasePath = join(directory, 'database.db'); database = await connect(databasePath); await database.exec(` CREATE TABLE users (id TEXT PRIMARY KEY, username TEXT, role TEXT, created_at TEXT); CREATE TABLE user_emails (user_id TEXT, email TEXT, verified_at TEXT); CREATE TABLE user_status (user_id TEXT PRIMARY KEY, blocked_at TEXT, banned_until TEXT); CREATE TABLE deleted_accounts (user_id TEXT PRIMARY KEY); CREATE TABLE roles (id TEXT PRIMARY KEY, name TEXT); CREATE TABLE permissions (id TEXT PRIMARY KEY, name TEXT); CREATE TABLE role_permissions (role_id TEXT, permission_id TEXT); CREATE TABLE user_roles (user_id TEXT, role_id TEXT, PRIMARY KEY(user_id,role_id)); CREATE TABLE mfa_totp_factors (id TEXT PRIMARY KEY, user_id TEXT, state TEXT); CREATE TABLE mfa_recovery_codes (id TEXT PRIMARY KEY, user_id TEXT, consumed_at TEXT, revoked_at TEXT); CREATE TABLE sessions (id TEXT PRIMARY KEY, user_id TEXT); CREATE TABLE login_events (id TEXT PRIMARY KEY, session_id TEXT, session_ended_at TEXT, session_end_reason TEXT); CREATE TABLE audit_log (id TEXT PRIMARY KEY, actor_id TEXT, entity_type TEXT, entity_id TEXT, action TEXT, before_json TEXT, after_json TEXT, created_at TEXT); INSERT INTO users VALUES ('user-1','agent','user','2026-08-07T00:00:00.000Z'); INSERT INTO user_emails VALUES ('user-1','admin@example.com','2026-08-07T00:00:00.000Z'); INSERT INTO roles VALUES ('role-admin','Admin'); INSERT INTO permissions VALUES ('permission-system-admin','system.admin'); INSERT INTO role_permissions VALUES ('role-admin','permission-system-admin'); `); }); afterEach(async () => { await database.close(); await rm(directory, { recursive: true, force: true }); }); it('rejects accounts without both active TOTP and unused recovery code', async () => { await database.close(); const result = await invoke(); expect(result.status).toBe(1); expect(result.stderr).toContain('active TOTP factor'); database = await connect(databasePath); const user = await (await database.prepare('SELECT role FROM users')).get(); expect(user.role).toBe('user'); }); it('grants only after MFA readiness and records sanitized bootstrap evidence', async () => { await database.exec(` INSERT INTO mfa_totp_factors VALUES ('factor-1','user-1','active'); INSERT INTO mfa_recovery_codes VALUES ('code-1','user-1',NULL,NULL); INSERT INTO sessions VALUES ('session-1','user-1'); `); await database.close(); const result = await invoke(); expect(result.status).toBe(0); database = await connect(databasePath); const user = await (await database.prepare('SELECT role FROM users')).get(); const role = await ( await database.prepare('SELECT role_id FROM user_roles WHERE user_id=?') ).get('user-1'); const sessions = await ( await database.prepare('SELECT COUNT(*) AS count FROM sessions') ).get(); const audit = await ( await database.prepare( 'SELECT entity_type,action,after_json FROM audit_log', ) ).get(); expect(user.role).toBe('user'); expect(role.role_id).toBe('role-admin'); expect(Number(sessions.count)).toBe(0); expect(audit).toMatchObject({ entity_type: 'role_management', action: 'administrator.bootstrapped', }); expect(String(audit.after_json)).not.toContain('factor-1'); expect(String(audit.after_json)).not.toContain('code-1'); }); it('is idempotent for an already canonical administrator', async () => { await database.exec(` INSERT INTO mfa_totp_factors VALUES ('factor-1','user-1','active'); INSERT INTO mfa_recovery_codes VALUES ('code-1','user-1',NULL,NULL); `); await database.close(); expect((await invoke()).status).toBe(0); database = await connect(databasePath); const firstAuditCount = await ( await database.prepare( "SELECT COUNT(*) AS count FROM audit_log WHERE action='administrator.bootstrapped'", ) ).get(); await database.close(); expect((await invoke()).status).toBe(0); database = await connect(databasePath); const secondAuditCount = await ( await database.prepare( "SELECT COUNT(*) AS count FROM audit_log WHERE action='administrator.bootstrapped'", ) ).get(); expect(Number(firstAuditCount.count)).toBe(1); expect(Number(secondAuditCount.count)).toBe(1); }); it('keeps only the local development bootstrap command', async () => { const packageJson = JSON.parse(await readFile('package.json', 'utf8')) as { scripts: Record; }; expect(packageJson.scripts['admin:bootstrap']).toBeTruthy(); expect(packageJson.scripts['admin:bootstrap:staging']).toBeUndefined(); expect(packageJson.scripts['admin:bootstrap:production']).toBeUndefined(); }); });