161 lines
5.7 KiB
PL/PgSQL
161 lines
5.7 KiB
PL/PgSQL
-- 007_enable_rls.sql
|
|
-- Enable Row-Level Security for Findings Ledger tenant isolation (LEDGER-TEN-48-001-DEV)
|
|
-- Based on Evidence Locker pattern per CONTRACT-FINDINGS-LEDGER-RLS-011
|
|
|
|
BEGIN;
|
|
|
|
-- ============================================
|
|
-- 1. Create app schema and tenant function
|
|
-- ============================================
|
|
|
|
CREATE SCHEMA IF NOT EXISTS findings_ledger_app;
|
|
|
|
CREATE OR REPLACE FUNCTION findings_ledger_app.require_current_tenant()
|
|
RETURNS TEXT
|
|
LANGUAGE plpgsql
|
|
STABLE
|
|
AS $$
|
|
DECLARE
|
|
tenant_text TEXT;
|
|
BEGIN
|
|
tenant_text := current_setting('app.current_tenant', true);
|
|
IF tenant_text IS NULL OR length(trim(tenant_text)) = 0 THEN
|
|
RAISE EXCEPTION 'app.current_tenant is not set for the current session'
|
|
USING ERRCODE = 'P0001';
|
|
END IF;
|
|
RETURN tenant_text;
|
|
END;
|
|
$$;
|
|
|
|
COMMENT ON FUNCTION findings_ledger_app.require_current_tenant() IS
|
|
'Returns the current tenant ID from session variable, raises exception if not set';
|
|
|
|
-- ============================================
|
|
-- 2. Enable RLS on ledger_events
|
|
-- ============================================
|
|
|
|
ALTER TABLE ledger_events ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE ledger_events FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS ledger_events_tenant_isolation ON ledger_events;
|
|
CREATE POLICY ledger_events_tenant_isolation
|
|
ON ledger_events
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 3. Enable RLS on ledger_merkle_roots
|
|
-- ============================================
|
|
|
|
ALTER TABLE ledger_merkle_roots ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE ledger_merkle_roots FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS ledger_merkle_roots_tenant_isolation ON ledger_merkle_roots;
|
|
CREATE POLICY ledger_merkle_roots_tenant_isolation
|
|
ON ledger_merkle_roots
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 4. Enable RLS on findings_projection
|
|
-- ============================================
|
|
|
|
ALTER TABLE findings_projection ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE findings_projection FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS findings_projection_tenant_isolation ON findings_projection;
|
|
CREATE POLICY findings_projection_tenant_isolation
|
|
ON findings_projection
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 5. Enable RLS on finding_history
|
|
-- ============================================
|
|
|
|
ALTER TABLE finding_history ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE finding_history FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS finding_history_tenant_isolation ON finding_history;
|
|
CREATE POLICY finding_history_tenant_isolation
|
|
ON finding_history
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 6. Enable RLS on triage_actions
|
|
-- ============================================
|
|
|
|
ALTER TABLE triage_actions ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE triage_actions FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS triage_actions_tenant_isolation ON triage_actions;
|
|
CREATE POLICY triage_actions_tenant_isolation
|
|
ON triage_actions
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 7. Enable RLS on ledger_attestations
|
|
-- ============================================
|
|
|
|
ALTER TABLE ledger_attestations ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE ledger_attestations FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS ledger_attestations_tenant_isolation ON ledger_attestations;
|
|
CREATE POLICY ledger_attestations_tenant_isolation
|
|
ON ledger_attestations
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 8. Enable RLS on orchestrator_exports
|
|
-- ============================================
|
|
|
|
ALTER TABLE orchestrator_exports ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE orchestrator_exports FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS orchestrator_exports_tenant_isolation ON orchestrator_exports;
|
|
CREATE POLICY orchestrator_exports_tenant_isolation
|
|
ON orchestrator_exports
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 9. Enable RLS on airgap_imports
|
|
-- ============================================
|
|
|
|
ALTER TABLE airgap_imports ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE airgap_imports FORCE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS airgap_imports_tenant_isolation ON airgap_imports;
|
|
CREATE POLICY airgap_imports_tenant_isolation
|
|
ON airgap_imports
|
|
FOR ALL
|
|
USING (tenant_id = findings_ledger_app.require_current_tenant())
|
|
WITH CHECK (tenant_id = findings_ledger_app.require_current_tenant());
|
|
|
|
-- ============================================
|
|
-- 10. Create admin bypass role
|
|
-- ============================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'findings_ledger_admin') THEN
|
|
CREATE ROLE findings_ledger_admin NOLOGIN BYPASSRLS;
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
COMMENT ON ROLE findings_ledger_admin IS
|
|
'Admin role that bypasses RLS for migrations and cross-tenant operations';
|
|
|
|
COMMIT;
|