60 lines
2.7 KiB
SQL
60 lines
2.7 KiB
SQL
-- 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 "<tbl>" FROM hivegrid_app;
|
|
-- DROP POLICY IF EXISTS "<tbl>_tenant_isolation" ON "<tbl>";
|
|
-- ALTER TABLE "<tbl>" NO FORCE ROW LEVEL SECURITY;
|
|
-- ALTER TABLE "<tbl>" 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).
|
|
-- =============================================================================
|