-- 004_rls_policies.sql
-- RLS-policies på nodes og edges, basert på node_access-matrisen.
--
-- Maskinrommet kobler til som superuser (sidelinja) for skriveoperasjoner.
-- For tunge lesespørringer (søk, statistikk, graf-traversering) brukes
-- SET LOCAL ROLE synops_reader, som er underlagt RLS.
--
-- Ref: docs/retninger/bruker_ikke_workspace.md (RLS-policy-spesifikasjon)

BEGIN;

-- =============================================================================
-- Applikasjonsrolle for RLS-filtrerte spørringer
-- =============================================================================

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'synops_reader') THEN
        CREATE ROLE synops_reader NOLOGIN;
    END IF;
END
$$;

-- Gi lesetilgang til alle relevante tabeller
GRANT SELECT ON nodes, edges, node_access, auth_identities TO synops_reader;

-- Tillat synops_reader å lese sekvenser (for eventuelle funksjoner)
GRANT USAGE ON SCHEMA public TO synops_reader;

-- Sidelinja (superuser) kan bytte til synops_reader
GRANT synops_reader TO sidelinja;

-- =============================================================================
-- current_node_id() — leser brukerens node_id fra sesjonsvariabel
-- =============================================================================

CREATE OR REPLACE FUNCTION current_node_id() RETURNS UUID AS $$
BEGIN
    RETURN current_setting('app.current_node_id', true)::UUID;
EXCEPTION
    WHEN OTHERS THEN
        RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;

-- synops_reader må kunne kalle funksjonen
GRANT EXECUTE ON FUNCTION current_node_id() TO synops_reader;

-- =============================================================================
-- RLS på nodes
-- =============================================================================

ALTER TABLE nodes ENABLE ROW LEVEL SECURITY;

-- Policy: bruker kan se noder de har opprettet, har tilgang til, eller som er
-- discoverable/readable/open.
--
-- Tre sjekker (ref: bruker_ikke_workspace.md):
-- 1. Egne noder (created_by) — instant
-- 2. Eksplisitt tilgang via node_access — indeksert lookup
-- 3. Offentlig synlige noder (discoverable+) — kolonne-sjekk
CREATE POLICY node_select ON nodes FOR SELECT TO synops_reader
    USING (
        created_by = current_node_id()
        OR id IN (
            SELECT object_id FROM node_access
            WHERE subject_id = current_node_id()
        )
        OR visibility >= 'discoverable'
    );

-- =============================================================================
-- RLS på edges
-- =============================================================================

ALTER TABLE edges ENABLE ROW LEVEL SECURITY;

-- Policy: bruker kan se edges der de har tilgang til minst én av endepunktene.
-- System-edges (alias etc.) er alltid skjult med mindre brukeren er source.
CREATE POLICY edge_select ON edges FOR SELECT TO synops_reader
    USING (
        -- Ikke vis system-edges til andre enn eieren
        (NOT system OR source_id = current_node_id())
        AND (
            -- Bruker opprettet edgen
            created_by = current_node_id()
            -- Bruker er source eller target
            OR source_id = current_node_id()
            OR target_id = current_node_id()
            -- Bruker har tilgang til source- eller target-noden
            OR source_id IN (
                SELECT object_id FROM node_access
                WHERE subject_id = current_node_id()
            )
            OR target_id IN (
                SELECT object_id FROM node_access
                WHERE subject_id = current_node_id()
            )
        )
    );

-- =============================================================================
-- RLS på node_access (brukere kan bare se sine egne tilganger)
-- =============================================================================

ALTER TABLE node_access ENABLE ROW LEVEL SECURITY;

CREATE POLICY na_select ON node_access FOR SELECT TO synops_reader
    USING (subject_id = current_node_id());

-- =============================================================================
-- Indeks for RLS-ytelse
-- =============================================================================

-- node_access brukes i subquery med subject_id — allerede indeksert (idx_na_subject).
-- Legg til indeks på object_id for edge-policyen (reverse lookup).
CREATE INDEX IF NOT EXISTS idx_na_object ON node_access (object_id);

COMMIT;
