Fullfør oppgave 4.2: team-transitivitet i recompute_access

Legger til steg 4 i recompute_access: når en bruker melder seg inn i
et team (member_of-edge), arver brukeren all tilgang teamet allerede
har. Tidligere håndterte funksjonen kun retningen "team får ny tilgang
→ propager til eksisterende medlemmer" (steg 3). Nå håndteres begge
retninger:

- Steg 3: Team får tilgang → alle eksisterende medlemmer arver
- Steg 4: Ny bruker melder seg inn → arver teamets eksisterende tilgang

Testet med scenario: Trond → Podcastteamet → Sidelinja → Episode 42.
Trond arver member-tilgang til alle tre noder via team-transitivitet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-17 15:01:51 +01:00
parent 28e6056644
commit e0f30bba27
4 changed files with 80 additions and 2 deletions

View file

@ -291,6 +291,16 @@ BEGIN
WHERE na.subject_id = p_subject_id WHERE na.subject_id = p_subject_id
ON CONFLICT (subject_id, object_id) ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access); DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
-- Team-transitivitet: arv tilgang fra teamet.
-- Når en bruker melder seg inn i et team, arver brukeren
-- all tilgang teamet allerede har til andre noder.
INSERT INTO node_access (subject_id, object_id, access, via_edge)
SELECT p_subject_id, na.object_id, na.access, na.via_edge
FROM node_access na
WHERE na.subject_id = p_root_node_id
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
``` ```

View file

@ -112,6 +112,16 @@ BEGIN
WHERE na.subject_id = p_subject_id WHERE na.subject_id = p_subject_id
ON CONFLICT (subject_id, object_id) ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access); DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
-- Team-transitivitet: arv tilgang fra teamet.
-- Når en bruker melder seg inn i et team, arver brukeren
-- all tilgang teamet allerede har til andre noder.
INSERT INTO node_access (subject_id, object_id, access, via_edge)
SELECT p_subject_id, na.object_id, na.access, na.via_edge
FROM node_access na
WHERE na.subject_id = p_root_node_id
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;

View file

@ -0,0 +1,59 @@
-- 003_team_transitivity.sql
-- Team-transitivitet: når en bruker melder seg inn i et team (member_of-edge),
-- arver brukeren all tilgang teamet allerede har.
--
-- Tidligere håndterte recompute_access kun retningen "team får ny tilgang →
-- propager til eksisterende medlemmer". Nå håndteres også "ny bruker melder
-- seg inn i team → arv teamets eksisterende tilganger".
--
-- Ref: docs/retninger/bruker_ikke_workspace.md, docs/primitiver/edges.md
BEGIN;
CREATE OR REPLACE FUNCTION recompute_access(
p_subject_id UUID,
p_root_node_id UUID,
p_access access_level,
p_via_edge UUID
) RETURNS void AS $$
BEGIN
-- Steg 1: Direkte tilgang til roten
INSERT INTO node_access (subject_id, object_id, access, via_edge)
VALUES (p_subject_id, p_root_node_id, p_access, p_via_edge)
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, p_access);
-- Steg 2: Transitiv: noder som tilhører roten (belongs_to)
INSERT INTO node_access (subject_id, object_id, access, via_edge)
SELECT p_subject_id, e.source_id, p_access, p_via_edge
FROM edges e
WHERE e.target_id = p_root_node_id
AND e.edge_type = 'belongs_to'
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, p_access);
-- Steg 3: Hvis subject er et team: propager til alle teammedlemmer
INSERT INTO node_access (subject_id, object_id, access, via_edge)
SELECT e.source_id, na.object_id, na.access, na.via_edge
FROM node_access na
JOIN edges e ON e.target_id = p_subject_id
AND e.edge_type = 'member_of'
WHERE na.subject_id = p_subject_id
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
-- Steg 4: Team-transitivitet — arv tilgang fra teamet.
-- Når en bruker (p_subject_id) melder seg inn i et team (p_root_node_id),
-- arver brukeren all tilgang teamet allerede har til andre noder.
-- Sjekker om root_node har node_access-rader som subject (= er et team
-- eller annen entitet med tilgang). Kopierer disse til p_subject_id.
INSERT INTO node_access (subject_id, object_id, access, via_edge)
SELECT p_subject_id, na.object_id, na.access, na.via_edge
FROM node_access na
WHERE na.subject_id = p_root_node_id
ON CONFLICT (subject_id, object_id)
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access);
END;
$$ LANGUAGE plpgsql;
COMMIT;

View file

@ -72,8 +72,7 @@ Uavhengige faser kan fortsatt plukkes.
## Fase 4: Tilgangskontroll ## Fase 4: Tilgangskontroll
- [x] 4.1 `recompute_access` i maskinrommet: ved edge-endring, oppdater `node_access`-matrisen. Håndter direkte edges (owner, admin, member, reader). - [x] 4.1 `recompute_access` i maskinrommet: ved edge-endring, oppdater `node_access`-matrisen. Håndter direkte edges (owner, admin, member, reader).
- [~] 4.2 Team-transitivitet: member_of-edge til team → arv tilgang fra teamets edges. - [x] 4.2 Team-transitivitet: member_of-edge til team → arv tilgang fra teamets edges.
> Påbegynt: 2026-03-17T14:57
- [ ] 4.3 Visibility-filtrering: STDB-spørringer respekterer visibility-enum. Frontend ser bare noder brukeren har tilgang til. - [ ] 4.3 Visibility-filtrering: STDB-spørringer respekterer visibility-enum. Frontend ser bare noder brukeren har tilgang til.
- [ ] 4.4 RLS-policies på PG: `node_access`-basert filtrering for tunge spørringer. - [ ] 4.4 RLS-policies på PG: `node_access`-basert filtrering for tunge spørringer.