import { readFileSync } from 'node:fs'; import { describe, expect, it } from 'vitest'; describe('tenant isolation migration', () => { const sql = readFileSync('migrations/0001_infrastructure.up.sql', 'utf8'); const tables = ['staff_outbox', 'staff_inbox', 'staff_idempotency_keys', 'staff_audit_log']; it.each(tables)('%s is tenant scoped and protected by RLS', (table) => { const create = sql.slice( sql.indexOf(`CREATE TABLE IF NOT EXISTS ${table}`), sql.indexOf(';', sql.indexOf(`CREATE TABLE IF NOT EXISTS ${table}`)), ); expect(create).toContain('tenant_id VARCHAR(26) NOT NULL'); expect(sql).toContain(`ALTER TABLE ${table} ENABLE ROW LEVEL SECURITY`); expect(sql).toContain(`ALTER TABLE ${table} FORCE ROW LEVEL SECURITY`); expect(sql).toMatch(new RegExp(`CREATE POLICY [a-z_]+ ON ${table} `)); }); it('sets tenant and actor locally inside each transaction', () => { const source = readFileSync('src/infrastructure/database.ts', 'utf8'); expect(source).toContain("set_config('app.tenant_id', $1, true)"); expect(source).toContain("set_config('app.user_id', $2, true)"); }); }); describe('attendance portal migrations', () => { const sql = readFileSync('migrations/0005_attendance_portal.up.sql', 'utf8'); const tables = ['staff_employees', 'staff_attendance_events', 'staff_timesheet_entries']; it.each(tables)('%s is tenant scoped and forces RLS', (table) => { expect(sql).toContain(`ALTER TABLE ${table} ENABLE ROW LEVEL SECURITY`); expect(sql).toContain(`ALTER TABLE ${table} FORCE ROW LEVEL SECURITY`); expect(sql).toMatch(new RegExp(`CREATE POLICY ${table}_[a-z_]+ ON ${table}`)); }); it('keeps raw attendance immutable for the runtime role', () => { expect(sql).toContain('GRANT SELECT, INSERT ON staff_attendance_events TO krona_staff_app'); expect(sql).toContain( 'REVOKE UPDATE, DELETE, TRUNCATE ON staff_attendance_events FROM krona_staff_app', ); }); }); describe('payroll foundation migration', () => { const sql = readFileSync('migrations/0006_payroll_foundation.up.sql', 'utf8'); const tables = [ 'staff_org_units', 'staff_org_unit_terms', 'staff_metric_definitions', 'staff_daily_metrics', 'staff_work_items', 'staff_pay_rules', 'staff_pay_assignments', 'staff_work_sessions', 'staff_payroll_runs', 'staff_payroll_lines', 'staff_payouts', ]; it.each(tables)('%s is tenant scoped and included in the RLS setup', (table) => { expect(sql).toContain(`CREATE TABLE ${table}`); expect(sql).toContain(`'${table}'`); }); it('enables and forces RLS with a tenant policy for every listed payroll table', () => { expect(sql).toContain( "EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', target_table)", ); expect(sql).toContain( "EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', target_table)", ); expect(sql).toContain("target_table || '_tenant_isolation', target_table"); }); it('uses tenant-scoped foreign keys for payroll ownership', () => { expect(sql).toContain( 'FOREIGN KEY (tenant_id, employee_id) REFERENCES staff_employees (tenant_id, id)', ); expect(sql).toContain( 'FOREIGN KEY (tenant_id, org_unit_id) REFERENCES staff_org_units (tenant_id, id)', ); expect(sql).toContain( 'FOREIGN KEY (tenant_id, pay_rule_id) REFERENCES staff_pay_rules (tenant_id, id)', ); }); const payrollTables = [ 'staff_pay_rules', 'staff_pay_assignments', 'staff_payroll_runs', 'staff_payroll_lines', 'staff_payroll_ledger', ]; it.each(payrollTables)('verifies %s has tenant_id column', (table) => { const create = sql.slice( sql.indexOf(`CREATE TABLE ${table}`), sql.indexOf(';', sql.indexOf(`CREATE TABLE ${table}`)), ); expect(create).toContain('tenant_id VARCHAR(26) NOT NULL'); }); it('enforces tenant isolation and RLS on staff_payroll_ledger with select and insert policies', () => { expect(sql).toContain('ALTER TABLE staff_payroll_ledger ENABLE ROW LEVEL SECURITY'); expect(sql).toContain('ALTER TABLE staff_payroll_ledger FORCE ROW LEVEL SECURITY'); expect(sql).toContain( 'CREATE POLICY staff_payroll_ledger_tenant_select ON staff_payroll_ledger', ); expect(sql).toContain("FOR SELECT USING (tenant_id = current_setting('app.tenant_id', true))"); expect(sql).toContain( 'CREATE POLICY staff_payroll_ledger_tenant_insert ON staff_payroll_ledger', ); expect(sql).toContain("tenant_id = current_setting('app.tenant_id', true)"); expect(sql).toContain("created_by = current_setting('app.user_id', true)"); }); it('keeps the money ledger append-only for the runtime role', () => { expect(sql).toContain('CREATE TABLE staff_payroll_ledger'); expect(sql).toContain('ALTER TABLE staff_payroll_ledger ENABLE ROW LEVEL SECURITY'); expect(sql).toContain('ALTER TABLE staff_payroll_ledger FORCE ROW LEVEL SECURITY'); expect(sql).toContain('GRANT SELECT, INSERT ON staff_payroll_ledger TO krona_staff_app'); expect(sql).toContain( 'REVOKE UPDATE, DELETE, TRUNCATE ON staff_payroll_ledger FROM krona_staff_app', ); }); }); describe('employee access migration', () => { const sql = readFileSync('migrations/0008_employee_access.up.sql', 'utf8'); it('declares external_key and staff_payroll_ledger_external_key_idx index on staff_payroll_ledger', () => { expect(sql).toContain('ALTER TABLE staff_payroll_ledger ADD COLUMN external_key TEXT;'); expect(sql).toContain('CREATE UNIQUE INDEX staff_payroll_ledger_external_key_idx'); expect(sql).toContain( 'ON staff_payroll_ledger (tenant_id, external_key) WHERE external_key IS NOT NULL;', ); }); it('protects standalone employee access with tenant isolation and RLS', () => { const create = sql.slice( sql.indexOf('CREATE TABLE staff_standalone_employee_access'), sql.indexOf(';', sql.indexOf('CREATE TABLE staff_standalone_employee_access')), ); expect(create).toContain('tenant_id VARCHAR(26) NOT NULL'); expect(sql).toContain('ALTER TABLE staff_standalone_employee_access ENABLE ROW LEVEL SECURITY'); expect(sql).toContain('ALTER TABLE staff_standalone_employee_access FORCE ROW LEVEL SECURITY'); expect(sql).toContain('CREATE POLICY staff_standalone_employee_access_tenant_isolation'); expect(sql).toContain("tenant_id = current_setting('app.tenant_id', true)"); }); }); describe('employee push notifications migration', () => { const sql = readFileSync('migrations/0010_employee_push_notifications.up.sql', 'utf8'); const tables = ['staff_push_subscriptions', 'staff_notification_deliveries']; it.each(tables)('%s is tenant scoped and forces RLS', (table) => { const create = sql.slice( sql.indexOf(`CREATE TABLE ${table}`), sql.indexOf(';', sql.indexOf(`CREATE TABLE ${table}`)), ); expect(create).toContain('tenant_id VARCHAR(26) NOT NULL'); expect(sql).toContain(`ALTER TABLE ${table} ENABLE ROW LEVEL SECURITY`); expect(sql).toContain(`ALTER TABLE ${table} FORCE ROW LEVEL SECURITY`); expect(sql).toContain(`CREATE POLICY ${table}_tenant_isolation`); expect(sql).toContain(`tenant_id = current_setting('app.tenant_id', true)`); }); it('declares uniqueness and idempotency constraints with tenant scope', () => { expect(sql).toContain('UNIQUE (tenant_id, id)'); expect(sql).toContain('UNIQUE (tenant_id, endpoint)'); expect(sql).toContain('UNIQUE (tenant_id, outbox_id, endpoint)'); }); it('uses tenant-scoped foreign keys to staff_employees and staff_outbox', () => { expect(sql).toContain( 'FOREIGN KEY (tenant_id, employee_id) REFERENCES staff_employees (tenant_id, id) ON DELETE CASCADE', ); expect(sql).toContain('FOREIGN KEY (outbox_id) REFERENCES staff_outbox (id) ON DELETE CASCADE'); }); it('grants required operations on both push tables to krona_staff_app', () => { expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_push_subscriptions TO krona_staff_app;', ); expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_notification_deliveries TO krona_staff_app;', ); }); }); describe('offline sync backend migration', () => { const sql = readFileSync('migrations/0011_offline_sync_backend.up.sql', 'utf8'); const tables = [ 'staff_sync_devices', 'staff_sync_change_log', 'staff_sync_command_inbox', 'staff_sync_device_checkpoints', ]; it.each(tables)('%s is tenant scoped and forces RLS', (table) => { const create = sql.slice( sql.indexOf(`CREATE TABLE ${table}`), sql.indexOf(';', sql.indexOf(`CREATE TABLE ${table}`)), ); expect(create).toContain('tenant_id VARCHAR(26) NOT NULL'); expect(sql).toContain(`ALTER TABLE ${table} ENABLE ROW LEVEL SECURITY;`); expect(sql).toContain(`ALTER TABLE ${table} FORCE ROW LEVEL SECURITY;`); expect(sql).toContain(`CREATE POLICY ${table}_tenant_isolation`); expect(sql).toContain("tenant_id = current_setting('app.tenant_id', true)"); }); it('declares uniqueness, cursor sequencing and idempotency constraints with tenant scope', () => { expect(sql).toContain('UNIQUE (tenant_id, id)'); expect(sql).toContain('UNIQUE (tenant_id, device_code)'); expect(sql).toContain('UNIQUE (tenant_id, token_hash)'); expect(sql).toContain('UNIQUE (tenant_id, device_id, idempotency_key)'); expect(sql).toContain('PRIMARY KEY (tenant_id, device_id)'); expect(sql).toContain('cursor_seq BIGSERIAL NOT NULL'); }); it('declares foreign key cascades for device ownership', () => { expect(sql).toContain( 'FOREIGN KEY (tenant_id, device_id) REFERENCES staff_sync_devices (tenant_id, id) ON DELETE CASCADE', ); }); it('grants required operations on all sync tables and sequence to krona_staff_app', () => { expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_sync_devices TO krona_staff_app;', ); expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_sync_change_log TO krona_staff_app;', ); expect(sql).toContain( 'GRANT USAGE, SELECT ON SEQUENCE staff_sync_change_log_cursor_seq_seq TO krona_staff_app;', ); expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_sync_command_inbox TO krona_staff_app;', ); expect(sql).toContain( 'GRANT SELECT, INSERT, UPDATE, DELETE ON staff_sync_device_checkpoints TO krona_staff_app;', ); }); it('declares and grants retention cleanup function', () => { expect(sql).toContain('CREATE OR REPLACE FUNCTION staff_sync_cleanup_retention'); expect(sql).toContain( 'GRANT EXECUTE ON FUNCTION staff_sync_cleanup_retention(INTEGER) TO krona_staff_app;', ); }); });