Back to Discover

#row level security

1 prompt found

PostgreSQL Row Level Security Policy Writer for Multi Tenant SaaS: Tenant Context with set_config, USING vs WITH CHECK, FORCE ROW LEVEL SECURITY, Roles Without BYPASSRLS, Pooler Safety, and Isolation Tests
๐Ÿ’ป Coding

PostgreSQL Row Level Security Policy Writer for Multi Tenant SaaS: Tenant Context with set_config, USING vs WITH CHECK, FORCE ROW LEVEL SECURITY, Roles Without BYPASSRLS, Pooler Safety, and Isolation Tests

PpromptstudioยทOct 6, 2026
No rating

Add tenant isolation to a shared schema Postgres database: a safe tenant context function, ENABLE and FORCE row level security, USING and WITH CHECK policies per table, an application role that cannot bypass them, transaction scoped settings that survive PgBouncer, composite foreign keys, view settings, and SQL tests that prove one tenant cannot see another.

Act as a PostgreSQL database engineer who retrofits row level security onto multi tenant SaaS schemas, and who has seen every leak: the app connecting as the table owner, a session setting that survives into the next pooled request, and views that run as their owner. Inputs: - Table definitions (CREATE TABLE statements) and which column identifies the tenant on each: [SchemaDDL] - Roles today: which role owns the tables, which role the app connects as, and their attributes: [CurrentRoles] - How the app connects (driver, ORM, PgBouncer or another pooler and its pool mode): [ConnectionSetup] - Access rules beyond tenant isolation (admins, read only support staff, cross tenant reporting jobs): [AccessRules] - PostgreSQL major version: [PgVersion] - Views and functions that read tenant tables: [ViewsAndFunctions] - Output format: [Format] Generate: 1. A role plan: a migration or owner role, an application role that is not the owner, not superuser, and NOBYPASSRLS, and a separate role for any cross tenant job in AccessRules. Include the GRANT statements. 2. A tenant context function that reads current_setting with missing_ok true and turns an empty string into NULL, so an unset context returns no rows instead of an error or every row. 3. For each tenant table: ALTER TABLE ... ENABLE ROW LEVEL SECURITY and FORCE ROW LEVEL SECURITY, then CREATE POLICY statements. Explain USING (which existing rows are visible or changeable) versus WITH CHECK (which new or updated rows are allowed), and write both. 4. Child tables: composite foreign keys on (parent_id, tenant_id) so a child row cannot point at another tenant's parent, plus the indexes that make policies fast. 5. Application code for ConnectionSetup: set the tenant per transaction with set_config(name, value, true) or SET LOCAL, never a session level SET under transaction pooling, with a short example in the user's driver. 6. Views and functions: security_invoker on views for PgVersion 15 and later, or the workaround for older versions, and review of SECURITY DEFINER functions. 7. Isolation tests in plain SQL inside transactions that roll back: visible row counts per tenant, a blocked cross tenant insert, a blocked update that moves a row to another tenant, and no rows with no context set. 8. A verification query on pg_class and pg_roles showing RLS enabled and forced, and that the app role cannot bypass it. Constraints: - Use only tables and columns from SchemaDDL; flag any table without a tenant column. - Note that foreign key checks and unique constraints are not filtered by RLS and can reveal that a value exists. - No destructive statements; wrap changes in a migration the user can review. No em dashes.