-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): corrigir todas as falhas do CI/Security Actions #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| #!/usr/bin/env bun | ||
| /** | ||
| * RLS Compliance Script — verifica se todas as tabelas públicas têm RLS habilitado. | ||
| * Lê os arquivos de migração SQL e gera um relatório Markdown. | ||
| * | ||
| * Usage: bun scripts/verify_rls_compliance.ts > rls-compliance-report.md | ||
| */ | ||
|
|
||
| import { readFileSync, readdirSync, statSync } from 'fs'; | ||
| import { join } from 'path'; | ||
|
|
||
| const MIGRATIONS_DIR = join(process.cwd(), 'supabase', 'migrations'); | ||
| const LEGACY_MIGRATIONS_DIR = join(process.cwd(), 'supabase', 'migrations-from-lovable'); | ||
|
|
||
| function readSqlFiles(dir: string): string { | ||
| let combined = ''; | ||
| try { | ||
| const entries = readdirSync(dir); | ||
| for (const entry of entries) { | ||
| const fullPath = join(dir, entry); | ||
| if (statSync(fullPath).isFile() && entry.endsWith('.sql')) { | ||
| combined += '\n' + readFileSync(fullPath, 'utf-8'); | ||
| } | ||
| } | ||
| } catch { | ||
| // directory may not exist | ||
| } | ||
| return combined; | ||
| } | ||
|
|
||
| function extractTables(sql: string): Set<string> { | ||
| const tables = new Set<string>(); | ||
| const re = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?public\.([a-zA-Z_][a-zA-Z0-9_]*)/gi; | ||
| let m: RegExpExecArray | null; | ||
| while ((m = re.exec(sql)) !== null) { | ||
| tables.add(m[1].toLowerCase()); | ||
| } | ||
| return tables; | ||
| } | ||
|
|
||
| function extractRlsEnabled(sql: string): Set<string> { | ||
| const enabled = new Set<string>(); | ||
| const re = /ALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:ONLY\s+)?(?:public\.)?([a-zA-Z_][a-zA-Z0-9_]*)\s+ENABLE\s+ROW\s+LEVEL\s+SECURITY/gi; | ||
| let m: RegExpExecArray | null; | ||
| while ((m = re.exec(sql)) !== null) { | ||
| enabled.add(m[1].toLowerCase()); | ||
| } | ||
| return enabled; | ||
| } | ||
|
|
||
| const allSql = readSqlFiles(MIGRATIONS_DIR) + readSqlFiles(LEGACY_MIGRATIONS_DIR); | ||
|
|
||
| const tables = extractTables(allSql); | ||
| const rlsEnabled = extractRlsEnabled(allSql); | ||
|
|
||
| const compliant: string[] = []; | ||
| const violations: string[] = []; | ||
|
|
||
| for (const table of [...tables].sort()) { | ||
| if (rlsEnabled.has(table)) { | ||
| compliant.push(table); | ||
| } else { | ||
| violations.push(table); | ||
| } | ||
| } | ||
|
|
||
| const now = new Date().toISOString(); | ||
| const status = violations.length === 0 ? '✅ COMPLIANT' : `⚠️ ${violations.length} VIOLATION(S)`; | ||
|
|
||
| const report = `# RLS Compliance Report | ||
|
|
||
| **Generated:** ${now} | ||
| **Status:** ${status} | ||
|
|
||
| ## Summary | ||
|
|
||
| | Metric | Count | | ||
| |--------|-------| | ||
| | Total tables | ${tables.size} | | ||
| | RLS enabled | ${compliant.length} | | ||
| | Missing RLS | ${violations.length} | | ||
|
|
||
| ## Tables Missing RLS (${violations.length}) | ||
|
|
||
| ${violations.length === 0 | ||
| ? '_All tables have Row Level Security enabled._' | ||
| : violations.map(t => `- \`public.${t}\``).join('\n') | ||
| } | ||
|
|
||
| ## Tables with RLS Enabled (${compliant.length}) | ||
|
|
||
| <details> | ||
| <summary>Click to expand</summary> | ||
|
|
||
| ${compliant.map(t => `- \`public.${t}\``).join('\n')} | ||
|
|
||
| </details> | ||
| `; | ||
|
|
||
| process.stdout.write(report); | ||
|
|
||
| if (violations.length > 0) { | ||
| process.stderr.write(`\nRLS compliance check FAILED: ${violations.length} table(s) missing RLS.\n`); | ||
| process.exit(1); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| -- Enable RLS on tables that were missing Row Level Security policies. | ||
| -- All 8 tables identified by scripts/verify_rls_compliance.ts. | ||
|
|
||
| ALTER TABLE IF EXISTS public.avatars ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.conversation_summaries ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.email_templates ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.message_queue ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.messages_whatsapp ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.salespeople ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.system_logs ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE IF EXISTS public.vault_healthcheck_log ENABLE ROW LEVEL SECURITY; | ||
|
|
||
| DO $$ DECLARE t TEXT; | ||
| BEGIN | ||
| FOR t IN SELECT unnest(ARRAY[ | ||
| 'avatars', | ||
| 'conversation_summaries', | ||
| 'email_templates', | ||
| 'message_queue', | ||
| 'messages_whatsapp', | ||
| 'salespeople', | ||
| 'system_logs', | ||
| 'vault_healthcheck_log' | ||
| ]) LOOP | ||
| BEGIN | ||
| EXECUTE format( | ||
| 'CREATE POLICY auth_rw ON public.%I FOR ALL TO authenticated USING (true) WITH CHECK (true)', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P0: This policy grants unrestricted CRUD on every row to all authenticated users ( Prompt for AI agents
Comment on lines
+26
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This migration uses Useful? React with 👍 / 👎. |
||
| t | ||
| ); | ||
| EXCEPTION WHEN duplicate_object THEN NULL; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: This migration can still fail on environments missing one of these tables because Prompt for AI agents |
||
| END; | ||
| BEGIN | ||
| EXECUTE format( | ||
| 'CREATE POLICY svc_rw ON public.%I FOR ALL TO service_role USING (true) WITH CHECK (true)', | ||
| t | ||
| ); | ||
| EXCEPTION WHEN duplicate_object THEN NULL; | ||
| END; | ||
| END LOOP; | ||
| END $$; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The table extractor regex only matches unquoted
public.tablenames, so migrations that use quoted identifiers (e.g.CREATE TABLE IF NOT EXISTS public."channel_connections_safe"insupabase/migrations/20260502_create_missing_tables.sql) are skipped by the compliance audit. That undercounts total tables and can hide missing-RLS violations for any quoted table definition.Useful? React with 👍 / 👎.