import { describe, it, expect } from 'vitest'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const currentDir = path.dirname(fileURLToPath(import.meta.url)); const migrationPath = path.resolve( currentDir, '../../src/infra/database/migrations/054_grant-system-database-backups-select.sql' ); function readMigration(): string { return fs.readFileSync(migrationPath, 'utf8'); } describe('054_grant-system-database-backups-select migration', () => { it('migration file exists', () => { expect(fs.existsSync(migrationPath)).toBe(true); }); it('UP migration grants SELECT on system.database_backups to project_admin only if table and role exist', () => { const sql = readMigration(); const upBlock = sql.match(/-- UP migration\s+DO \$\$([\s\S]*?)END \$\$;/); expect(upBlock).not.toBeNull(); const upBody = upBlock![1]; const grantPattern = /IF EXISTS\s*\(\s*SELECT 1 FROM pg_tables WHERE schemaname = 'system' AND tablename = 'database_backups'\s*\)\s*AND EXISTS\s*\(\s*SELECT 1 FROM pg_roles WHERE rolname = 'project_admin'\s*\)\s*THEN\s*EXECUTE 'GRANT SELECT ON TABLE system\.database_backups TO project_admin';/i; expect(upBody).toMatch(grantPattern); }); it('sets default privileges for future system tables (no FOR ROLE)', () => { const sql = readMigration(); expect(sql).toMatch( /ALTER DEFAULT PRIVILEGES IN SCHEMA system GRANT SELECT ON TABLES TO project_admin/ ); expect(sql).not.toMatch(/FOR ROLE postgres/); expect(sql).not.toMatch(/format\('ALTER DEFAULT PRIVILEGES FOR ROLE %I/); }); it('DOWN migration has conditional REVOKE guards and revokes default privileges', () => { const sql = readMigration(); const downSection = sql.split('-- DOWN migration')[1]; expect(downSection).toBeDefined(); expect(downSection).toMatch( /DO \$\$\s*BEGIN[\s\S]*IF EXISTS[\s\S]*REVOKE SELECT ON TABLE system\.database_backups FROM project_admin[\s\S]*END IF;[\s\S]*END \$\$/s ); expect(downSection).toContain( 'ALTER DEFAULT PRIVILEGES IN SCHEMA system REVOKE SELECT ON TABLES FROM project_admin' ); expect(downSection).not.toMatch(/FOR ROLE postgres/); }); it('should run after migration 045 which creates project_admin', () => { const migrationsDir = path.join(currentDir, '../../src/infra/database/migrations'); const files = fs .readdirSync(migrationsDir) .filter((f) => f.endsWith('.sql')) .sort(); const idx045 = files.findIndex((f) => f.startsWith('045_')); const idx054 = files.findIndex((f) => f.startsWith('054_grant-system-database-backups-select')); expect(idx045).toBeGreaterThanOrEqual(0); expect(idx054).toBeGreaterThan(idx045); }); });