-- ============================================================================= -- PostgreSQL Row-Level Security (RLS) Policies -- Defense-in-depth tenant isolation for NetForge -- ============================================================================= -- -- ARCHITECTURE NOTE: -- The primary multi-tenancy enforcement is at the application layer via -- Prisma query extensions in src/lib/prisma-tenant.ts (withTenantContext). -- -- RLS policies here serve as DEFENSE-IN-DEPTH: -- - They catch bugs where application code bypasses the Prisma middleware -- - They provide an independent enforcement layer at the database level -- - They document data isolation intent in the database schema itself -- -- IMPORTANT: The Prisma client connects as the database OWNER, which by -- default bypasses RLS (PostgreSQL superusers and table owners bypass RLS -- unless FORCE ROW LEVEL SECURITY is set on the table). This means these -- policies will NOT block queries from the standard Prisma client unless -- FORCE ROW LEVEL SECURITY is enabled, or a non-owner role is used. -- -- To enforce RLS for a query, use setTenantRLS() from src/lib/prisma-tenant.ts -- within a transaction before executing queries. This sets the session variable -- app.current_tenant_id which the policy USING clause reads. -- ============================================================================= -- Enable RLS on the User table ALTER TABLE "User" ENABLE ROW LEVEL SECURITY; -- Policy: tenant_isolation_user -- Restricts access to rows matching the current tenant context. -- The app.current_tenant_id session variable is set by setTenantRLS(). -- When no tenant context is set (super-admin operations), all rows are visible. CREATE POLICY tenant_isolation_user ON "User" USING ( "tenantId" = current_setting('app.current_tenant_id', true)::text OR current_setting('app.current_tenant_id', true) IS NULL OR current_setting('app.current_tenant_id', true) = '' ) WITH CHECK ( "tenantId" = current_setting('app.current_tenant_id', true)::text );