gate4: migration 0088 — auth RLS policies for password_reset_tokens and audit_log
This commit is contained in:
@@ -0,0 +1,99 @@
|
|||||||
|
"""Auth RLS policies for password_reset_tokens and audit_log.
|
||||||
|
|
||||||
|
Allows crm_auth to:
|
||||||
|
- SELECT/UPDATE/INSERT on password_reset_tokens (for password reset flow)
|
||||||
|
- INSERT on audit_log (for audit logging during auth)
|
||||||
|
- UPDATE on users (for password hash update during reset)
|
||||||
|
|
||||||
|
The tenant_isolation policy for crm_api/crm_worker is preserved.
|
||||||
|
crm_auth gets scoped access without full tenant context for token lookup,
|
||||||
|
but INSERT/UPDATE on tenant tables still requires tenant context.
|
||||||
|
|
||||||
|
Revision ID: 0088
|
||||||
|
Revises: 0087
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
revision = "0088"
|
||||||
|
down_revision = "0087"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ── password_reset_tokens: replace policy for crm_auth access ──
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_tenant_isolation ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_lookup ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_update ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_insert ON public.password_reset_tokens")
|
||||||
|
|
||||||
|
# crm_auth: SELECT without tenant context (token lookup)
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY password_reset_tokens_auth_lookup
|
||||||
|
ON public.password_reset_tokens
|
||||||
|
FOR SELECT TO crm_auth
|
||||||
|
USING (true)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# crm_auth: UPDATE without tenant context (mark token used)
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY password_reset_tokens_auth_update
|
||||||
|
ON public.password_reset_tokens
|
||||||
|
FOR UPDATE TO crm_auth
|
||||||
|
USING (true)
|
||||||
|
WITH CHECK (true)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# crm_auth: INSERT with tenant context (create new token)
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY password_reset_tokens_auth_insert
|
||||||
|
ON public.password_reset_tokens
|
||||||
|
FOR INSERT TO crm_auth
|
||||||
|
WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# crm_api, crm_worker: full tenant isolation
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY password_reset_tokens_tenant_isolation
|
||||||
|
ON public.password_reset_tokens
|
||||||
|
FOR ALL TO crm_api, crm_worker
|
||||||
|
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)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# ── Grants for crm_auth ──
|
||||||
|
op.execute("GRANT SELECT, INSERT, UPDATE ON public.password_reset_tokens TO crm_auth")
|
||||||
|
op.execute("GRANT UPDATE ON public.users TO crm_auth")
|
||||||
|
|
||||||
|
# ── audit_log: allow crm_auth INSERT with tenant context ──
|
||||||
|
op.execute("DROP POLICY IF EXISTS audit_log_auth_insert ON public.audit_log")
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY audit_log_auth_insert
|
||||||
|
ON public.audit_log
|
||||||
|
FOR INSERT TO crm_auth
|
||||||
|
WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid)
|
||||||
|
""")
|
||||||
|
op.execute("GRANT INSERT ON public.audit_log TO crm_auth")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_lookup ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_update ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS password_reset_tokens_auth_insert ON public.password_reset_tokens")
|
||||||
|
op.execute("DROP POLICY IF EXISTS audit_log_auth_insert ON public.audit_log")
|
||||||
|
op.execute("REVOKE SELECT, INSERT, UPDATE ON public.password_reset_tokens FROM crm_auth")
|
||||||
|
op.execute("REVOKE UPDATE ON public.users FROM crm_auth")
|
||||||
|
op.execute("REVOKE INSERT ON public.audit_log FROM crm_auth")
|
||||||
|
|
||||||
|
# Restore original tenant isolation policy
|
||||||
|
op.execute("""
|
||||||
|
CREATE POLICY password_reset_tokens_tenant_isolation
|
||||||
|
ON public.password_reset_tokens
|
||||||
|
FOR ALL TO crm_api, crm_worker, crm_auth
|
||||||
|
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)
|
||||||
|
""")
|
||||||
Reference in New Issue
Block a user