From d43407ca77116f6826f340a4f67ff43381f1da7b Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 3 Aug 2026 23:06:01 +0200 Subject: [PATCH] Fix: Disable RLS on auth tables, correct policy syntax --- .../0101_enable_rls_critical_tables.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/alembic/versions/0101_enable_rls_critical_tables.py b/alembic/versions/0101_enable_rls_critical_tables.py index a91eea7..3a8f2c4 100644 --- a/alembic/versions/0101_enable_rls_critical_tables.py +++ b/alembic/versions/0101_enable_rls_critical_tables.py @@ -1,9 +1,12 @@ """Enable RLS on critical tables missing it. -Tables: api_tokens, sequences, sessions, tenant_plugin_activation, -user_tenants, password_reset_tokens. +Tables: api_tokens, sequences, tenant_plugin_activation, user_tenants. Also adds tenant_id to guest_invitations and enables RLS. +NOTE: sessions and password_reset_tokens are EXCLUDED from RLS because +crm_auth accesses them without a tenant context (during login/reset). +Instead, their security is enforced via GRANT restrictions in migration 0100. + Revision ID: 0101 """ @@ -15,25 +18,30 @@ down_revision = "0100" branch_labels = None depends_on = None -# Tables that have tenant_id but no RLS +# Tables that have tenant_id and can safely get RLS +# (accessed only by crm_api/crm_worker which always set tenant context) RLS_TABLES = [ "api_tokens", "sequences", - "sessions", "tenant_plugin_activation", "user_tenants", - "password_reset_tokens", ] def upgrade() -> None: + # Undo any manual RLS changes on auth tables (safety measure) + op.execute("ALTER TABLE password_reset_tokens DISABLE ROW LEVEL SECURITY;") + op.execute("ALTER TABLE sessions DISABLE ROW LEVEL SECURITY;") + op.execute("DROP POLICY IF EXISTS password_reset_tokens_tenant_isolation ON password_reset_tokens;") + op.execute("DROP POLICY IF EXISTS sessions_tenant_isolation ON sessions;") + # Enable RLS + create tenant isolation policy for each table for table in RLS_TABLES: op.execute(f"ALTER TABLE {table} ENABLE ROW LEVEL SECURITY;") op.execute( f"CREATE POLICY {table}_tenant_isolation ON {table} " - f"FOR ALL USING (tenant_id = current_setting('app.current_tenant_id')::uuid) " - f"WITH CHECK (tenant_id = current_setting('app.current_tenant_id')::uuid);" + f"FOR ALL USING (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid) " + f"WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid);" ) # guest_invitations: add tenant_id + enable RLS @@ -42,8 +50,8 @@ def upgrade() -> None: op.execute("ALTER TABLE guest_invitations ENABLE ROW LEVEL SECURITY;") op.execute( "CREATE POLICY guest_invitations_tenant_isolation ON guest_invitations " - "FOR ALL USING (tenant_id = current_setting('app.current_tenant_id')::uuid) " - "WITH CHECK (tenant_id = current_setting('app.current_tenant_id')::uuid);" + "FOR ALL USING (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid) " + "WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid);" )