-- R-P5 · Apps-Engine — RLS ROLLOUT ARTIFACT (deferred, NOT in the auto-migration) -- ============================================================================= -- Companion to prisma/rls/tenant-isolation.sql (R-P2b) and the per-module RLS -- blocks (file/task/hr/crypto). The Apps-Engine tables ship in the tracked merge -- migration (created at main-merge per AD-21); this RLS block stays out of the -- auto-migration path (activation = coordinated P5 cutover, not a schema diff). -- -- IMPORTANT: `App` is a GLOBAL catalog table (no tenantId) → NO policy, NO RLS. -- Only the tenant-scoped rows are isolated: DataConnection, AppSyncRun, -- AppSyncRunLog, AppSyncItem, AppEntityBinding. -- -- WHY DEFERRED: with RLS + FORCE on, any query WITHOUT `app.tenant_id` returns -- ZERO rows. The dataConnection/appSync services always scope by -- `where: { tenantId }` and run inside withTenantRLS(), so app-level scoping -- carries isolation until the cutover (runtime role → hivegrid_app). -- -- Forward-only (DoD 28). Inverse SQL as comment. Idempotent, DO-guarded (P3018). -- -- Inverse per table: -- REVOKE SELECT, INSERT, UPDATE, DELETE ON "" FROM hivegrid_app; -- DROP POLICY IF EXISTS "_tenant_isolation" ON ""; -- ALTER TABLE "" NO FORCE ROW LEVEL SECURITY; -- ALTER TABLE "" DISABLE ROW LEVEL SECURITY; -- ============================================================================= DO $$ DECLARE tbl text; BEGIN FOREACH tbl IN ARRAY ARRAY['DataConnection', 'AppSyncRun', 'AppSyncRunLog', 'AppSyncItem', 'AppEntityBinding'] LOOP EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY;', tbl); EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY;', tbl); IF NOT EXISTS ( SELECT 1 FROM pg_policies WHERE schemaname = current_schema() AND tablename = tbl AND policyname = tbl || '_tenant_isolation' ) THEN EXECUTE format( 'CREATE POLICY %I ON %I USING ("tenantId" = current_setting(''app.tenant_id'', true)) WITH CHECK ("tenantId" = current_setting(''app.tenant_id'', true));', tbl || '_tenant_isolation', tbl ); END IF; EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON %I TO hivegrid_app;', tbl); END LOOP; -- App is global → the restricted role only ever reads the catalog. GRANT SELECT ON "App" TO hivegrid_app; END $$; -- ============================================================================= -- Verify before the cutover migration (AGENTS.md §Prisma): -- pnpm prisma validate · pnpm prisma migrate status -- CI: prisma migrate deploy against an EMPTY DB (reproducible from scratch). -- =============================================================================