"""Disable RLS on all system/auth/config/plugin tables for crm_api startup. This migration disables RLS on all tables that are accessed during startup, login, or plugin activation — before a tenant context is set. RLS remains active only on business-data tables (contacts, addresses, attachments, etc.) where tenant context is always set before access. Revision ID: 0081 Revises: 0080 """ from alembic import op from sqlalchemy import text revision = "0081" down_revision = "0080" branch_labels = None depends_on = None TABLES = [ "users", "tenants", "user_tenants", "sessions", "audit_log", "user_groups", "permissions", "password_reset_tokens", "api_tokens", "groups", "roles", "system_settings", "currencies", "tax_rates", "sequences", "saved_filters", "saved_views", "webhooks", "notification_preferences", "tenant_plugin_activation", "workspaces", "workspace_modules", "workspace_users", "workspace_widgets", "automation_cron_jobs", "automation_definitions", "automation_runs", "automation_versions", "automation_agent_definitions", "automation_agent_runs", "automation_agent_versions", "plugins", "user_preferences", "custom_field_definitions", "deletion_log", "backups", "share_links", "unified_search_index_log", "unified_search_providers", "mcp_server_configs", "plugin_test_data", "report_templates", "report_instances", "resource_bookings", "resources", "vacation_sent_log", "pgp_keys", "contact_pgp_keys", "contact_merge_history", "entity_links", "entity_history", "contact_folder_permissions", "contact_folders", "guest_users", "guest_invitations", "permission_delegations", "permission_templates", "consumer_inbox", "outbox_deliveries", "event_outbox", "entity_permissions", "entity_policies", "entity_attachments", "files", "folders", "tags", "tag_assignments", "tasks", "subtasks", ] def upgrade() -> None: conn = op.get_bind() for table in TABLES: exists = conn.execute( text(f"SELECT 1 FROM information_schema.tables WHERE table_name = '{table}'") ).fetchone() is not None if not exists: continue # Drop all RLS policies policies = conn.execute(text( f"SELECT policyname FROM pg_policies WHERE tablename = '{table}'" )).fetchall() for (policyname,) in policies: conn.execute(text(f"DROP POLICY IF EXISTS {policyname} ON {table}")) conn.execute(text(f"ALTER TABLE {table} DISABLE ROW LEVEL SECURITY")) def downgrade() -> None: pass