mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
Multitenancy
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
"""RLS completa su tutte le tabelle applicative + ruolo pechub_app
|
||||
|
||||
Revision ID: 0006
|
||||
Revises: 0005
|
||||
Create Date: 2026-03-19 00:00:00.000000
|
||||
|
||||
Aggiunge:
|
||||
- ENABLE ROW LEVEL SECURITY + policy USING (tenant_id = ...) su tutte le
|
||||
tabelle applicative che mancavano (attachments, send_jobs, archival_batches,
|
||||
archival_dips, labels, mailbox_permissions, virtual_boxes,
|
||||
notification_channels, notification_rules, notification_log, tenant_settings)
|
||||
- Crea il ruolo PostgreSQL applicativo 'pechub_app' (non-superuser) con
|
||||
GRANT SELECT/INSERT/UPDATE/DELETE su tutte le tabelle.
|
||||
Il ruolo viene usato dalla connessione applicativa (DATABASE_URL) mentre
|
||||
Alembic continua ad usare l'utente superuser (DATABASE_URL_SYNC).
|
||||
|
||||
Nota: la migrazione usa DO $$ BEGIN ... EXCEPTION WHEN ... END $$ per
|
||||
rendere idempotente la creazione del ruolo e delle policy.
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision = "0006"
|
||||
down_revision = "0005"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
# Tabelle con tenant_id che devono avere RLS (escluse quelle già gestite in 0001)
|
||||
_RLS_TABLES = [
|
||||
"attachments",
|
||||
"send_jobs",
|
||||
"archival_batches",
|
||||
"archival_dips",
|
||||
"labels",
|
||||
"mailbox_permissions",
|
||||
"virtual_boxes",
|
||||
"notification_channels",
|
||||
"notification_rules",
|
||||
"notification_log",
|
||||
"tenant_settings",
|
||||
]
|
||||
|
||||
# Tutte le tabelle su cui pechub_app ha SELECT/INSERT/UPDATE/DELETE
|
||||
_ALL_APP_TABLES = [
|
||||
"tenants",
|
||||
"users",
|
||||
"refresh_tokens",
|
||||
"mailboxes",
|
||||
"messages",
|
||||
"attachments",
|
||||
"send_jobs",
|
||||
"archival_batches",
|
||||
"archival_batch_messages",
|
||||
"archival_dips",
|
||||
"labels",
|
||||
"message_labels",
|
||||
"mailbox_permissions",
|
||||
"virtual_boxes",
|
||||
"virtual_box_rules",
|
||||
"virtual_box_assignments",
|
||||
"virtual_box_mailboxes",
|
||||
"notification_channels",
|
||||
"notification_rules",
|
||||
"notification_log",
|
||||
"audit_log",
|
||||
"tenant_settings",
|
||||
]
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ── 1. Abilita RLS + policy su tabelle mancanti ───────────────────────────
|
||||
for table in _RLS_TABLES:
|
||||
op.execute(f"ALTER TABLE {table} ENABLE ROW LEVEL SECURITY")
|
||||
# Politica idempotente: elimina la policy se esiste e la ricrea
|
||||
op.execute(
|
||||
f"""
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Elimina policy esistente (se presente da un run precedente)
|
||||
DROP POLICY IF EXISTS {table}_tenant_isolation ON {table};
|
||||
-- Crea la nuova policy
|
||||
CREATE POLICY {table}_tenant_isolation ON {table}
|
||||
USING (
|
||||
tenant_id = NULLIF(
|
||||
current_setting('app.current_tenant_id', TRUE), ''
|
||||
)::UUID
|
||||
);
|
||||
END
|
||||
$$;
|
||||
"""
|
||||
)
|
||||
|
||||
# ── 2. Crea ruolo applicativo pechub_app (non-superuser) ──────────────────
|
||||
op.execute(
|
||||
"""
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_roles WHERE rolname = 'pechub_app'
|
||||
) THEN
|
||||
CREATE USER pechub_app WITH PASSWORD 'pechub_app_password'
|
||||
NOSUPERUSER NOCREATEDB NOCREATEROLE;
|
||||
RAISE NOTICE 'Ruolo pechub_app creato';
|
||||
ELSE
|
||||
RAISE NOTICE 'Ruolo pechub_app già esistente – skip';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
"""
|
||||
)
|
||||
|
||||
# ── 3. Permessi al ruolo applicativo ──────────────────────────────────────
|
||||
op.execute("GRANT CONNECT ON DATABASE pechub TO pechub_app")
|
||||
op.execute("GRANT USAGE ON SCHEMA public TO pechub_app")
|
||||
|
||||
for table in _ALL_APP_TABLES:
|
||||
op.execute(
|
||||
f"GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE {table} TO pechub_app"
|
||||
)
|
||||
|
||||
# Sequenze (per BIGSERIAL come audit_log.id)
|
||||
op.execute("GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO pechub_app")
|
||||
|
||||
# Default privileges: le tabelle create nelle migrazioni future ricevono
|
||||
# automaticamente i permessi per pechub_app
|
||||
op.execute(
|
||||
"""
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE pechub IN SCHEMA public
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO pechub_app;
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE pechub IN SCHEMA public
|
||||
GRANT USAGE, SELECT ON SEQUENCES TO pechub_app;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Rimuovi policy e disabilita RLS
|
||||
for table in _RLS_TABLES:
|
||||
op.execute(
|
||||
f"DROP POLICY IF EXISTS {table}_tenant_isolation ON {table}"
|
||||
)
|
||||
op.execute(f"ALTER TABLE {table} DISABLE ROW LEVEL SECURITY")
|
||||
|
||||
# Revoca permessi e rimuovi ruolo
|
||||
op.execute("REVOKE ALL ON ALL TABLES IN SCHEMA public FROM pechub_app")
|
||||
op.execute("REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM pechub_app")
|
||||
op.execute("REVOKE USAGE ON SCHEMA public FROM pechub_app")
|
||||
op.execute("REVOKE CONNECT ON DATABASE pechub FROM pechub_app")
|
||||
op.execute("DROP USER IF EXISTS pechub_app")
|
||||
Reference in New Issue
Block a user