feat: updated saas platform

This commit is contained in:
Furqan-14
2026-08-31 20:04:12 -04:00
parent 7ab9cc3bee
commit b923b3ed15
223 changed files with 37287 additions and 492 deletions
@@ -0,0 +1,82 @@
"""Enforce workspace isolation in the database rather than in every query.
Until now isolation was a convention: each query had to remember to filter by
`tenant_id`. Finding S-5 was one that forgot, and forgetting was possible because
nothing outside the developer's memory was checking.
**This migration is inert until the application connects as a non-owner role.**
A PostgreSQL superuser bypasses row-level security unconditionally, and the table
owner does too — which is why every table here is FORCEd, and why
`scripts/create_app_role.py` exists. Applying this while still connecting as the
owner turns the policies on for that connection as well, so the code that sets
`app.tenant_id` has to be in place first. It ships in the same change.
Two settings drive the policies:
app.tenant_id the workspace, or '' when none is set
app.bypass_rls 'on' for deliberate cross-workspace work
Unset means '' means no rows. A code path that forgets to establish context
therefore fails loudly rather than quietly reading everyone's data.
Revision ID: c3d5e7f9a801
Revises: b2e1d4f5a602
"""
from typing import Sequence, Union
from alembic import op
revision: str = "c3d5e7f9a801"
down_revision: Union[str, Sequence[str], None] = "b2e1d4f5a602"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
BYPASS = "current_setting('app.bypass_rls', true) = 'on'"
CURRENT = "NULLIF(current_setting('app.tenant_id', true), '')::uuid"
# Tables whose rows belong strictly to one workspace. A NULL tenant_id here means
# a platform-level row — a superadmin account — which a workspace must not see.
STRICT = ("users", "tenant_modules")
# Tables where a NULL tenant_id means "shared across workspaces" and is meant to
# be readable. `roles` is the real case: `UserService.update_user` deliberately
# permits assigning a role with no tenant, so a workspace user can hold one, and
# loading `user.role` has to be able to see it.
SHARED_NULLS = ("roles", "sso_grants")
def upgrade() -> None:
for table in STRICT:
op.execute(f"ALTER TABLE {table} ENABLE ROW LEVEL SECURITY")
op.execute(f"ALTER TABLE {table} FORCE ROW LEVEL SECURITY")
op.execute(
f"""
CREATE POLICY tenant_isolation ON {table}
USING ({BYPASS} OR tenant_id = {CURRENT})
WITH CHECK ({BYPASS} OR tenant_id = {CURRENT})
"""
)
for table in SHARED_NULLS:
op.execute(f"ALTER TABLE {table} ENABLE ROW LEVEL SECURITY")
op.execute(f"ALTER TABLE {table} FORCE ROW LEVEL SECURITY")
# Asymmetric on purpose. Reading a shared row is fine; *creating* one is
# not — without that asymmetry a workspace could insert a role with no
# tenant and hand it to anybody, which is an escalation rather than a
# convenience.
op.execute(
f"""
CREATE POLICY tenant_isolation ON {table}
USING ({BYPASS} OR tenant_id IS NULL OR tenant_id = {CURRENT})
WITH CHECK ({BYPASS} OR tenant_id = {CURRENT})
"""
)
def downgrade() -> None:
for table in (*STRICT, *SHARED_NULLS):
op.execute(f"DROP POLICY IF EXISTS tenant_isolation ON {table}")
op.execute(f"ALTER TABLE {table} NO FORCE ROW LEVEL SECURITY")
op.execute(f"ALTER TABLE {table} DISABLE ROW LEVEL SECURITY")