diff --git a/maskinrommet/src/intentions.rs b/maskinrommet/src/intentions.rs index ee4a962..4e3473f 100644 --- a/maskinrommet/src/intentions.rs +++ b/maskinrommet/src/intentions.rs @@ -554,7 +554,21 @@ fn spawn_pg_insert_node( }); } +/// Mapper edge_type til access_level for tilgangsgivende edges. +/// Returnerer None for edges som ikke gir tilgang. +fn edge_type_to_access_level(edge_type: &str) -> Option<&'static str> { + match edge_type { + "owner" => Some("owner"), + "admin" => Some("admin"), + "member_of" => Some("member"), + "reader" => Some("reader"), + _ => None, + } +} + /// Spawner en tokio-task som skriver edgen til PostgreSQL i bakgrunnen. +/// For tilgangsgivende edges (owner, admin, member_of, reader) kalles +/// recompute_access i samme transaksjon — ingen vindu med stale tilgang. fn spawn_pg_insert_edge( db: PgPool, edge_id: Uuid, @@ -566,33 +580,105 @@ fn spawn_pg_insert_edge( created_by: Uuid, ) { tokio::spawn(async move { - let result = sqlx::query( - r#" - INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by) - VALUES ($1, $2, $3, $4, $5, $6, $7) - "#, - ) - .bind(edge_id) - .bind(source_id) - .bind(target_id) - .bind(&edge_type) - .bind(&metadata) - .bind(system) - .bind(created_by) - .execute(&db) - .await; + let access_level = edge_type_to_access_level(&edge_type); - match result { - Ok(_) => { - tracing::info!(edge_id = %edge_id, "Edge persistert til PostgreSQL"); + if let Some(level) = access_level { + // Tilgangsgivende edge: wrap i transaksjon med recompute_access + let result = insert_edge_with_access(&db, edge_id, source_id, target_id, &edge_type, &metadata, system, created_by, level).await; + match result { + Ok(_) => { + tracing::info!( + edge_id = %edge_id, + edge_type = %edge_type, + access_level = %level, + "Edge + node_access persistert til PostgreSQL" + ); + } + Err(e) => { + tracing::error!( + edge_id = %edge_id, + error = %e, + "Kunne ikke persistere edge + node_access til PostgreSQL" + ); + } } - Err(e) => { - tracing::error!(edge_id = %edge_id, error = %e, "Kunne ikke persistere edge til PostgreSQL"); + } else { + // Vanlig edge uten tilgangspåvirkning + let result = sqlx::query( + r#" + INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by) + VALUES ($1, $2, $3, $4, $5, $6, $7) + "#, + ) + .bind(edge_id) + .bind(source_id) + .bind(target_id) + .bind(&edge_type) + .bind(&metadata) + .bind(system) + .bind(created_by) + .execute(&db) + .await; + + match result { + Ok(_) => { + tracing::info!(edge_id = %edge_id, "Edge persistert til PostgreSQL"); + } + Err(e) => { + tracing::error!(edge_id = %edge_id, error = %e, "Kunne ikke persistere edge til PostgreSQL"); + } } } }); } +/// Inserter en tilgangsgivende edge og oppdaterer node_access i én transaksjon. +/// source_id = subject (bruker/team), target_id = object (noden det gis tilgang til). +async fn insert_edge_with_access( + db: &PgPool, + edge_id: Uuid, + source_id: Uuid, + target_id: Uuid, + edge_type: &str, + metadata: &serde_json::Value, + system: bool, + created_by: Uuid, + access_level: &str, +) -> Result<(), sqlx::Error> { + let mut tx = db.begin().await?; + + sqlx::query( + r#" + INSERT INTO edges (id, source_id, target_id, edge_type, metadata, system, created_by) + VALUES ($1, $2, $3, $4, $5, $6, $7) + "#, + ) + .bind(edge_id) + .bind(source_id) + .bind(target_id) + .bind(edge_type) + .bind(metadata) + .bind(system) + .bind(created_by) + .execute(&mut *tx) + .await?; + + // Kall recompute_access: subject=source_id, object=target_id + sqlx::query( + "SELECT recompute_access($1, $2, $3::access_level, $4)", + ) + .bind(source_id) + .bind(target_id) + .bind(access_level) + .bind(edge_id) + .execute(&mut *tx) + .await?; + + tx.commit().await?; + + Ok(()) +} + /// Spawner en tokio-task som oppdaterer noden i PostgreSQL. fn spawn_pg_update_node( db: PgPool, diff --git a/tasks.md b/tasks.md index b443ca0..74fd840 100644 --- a/tasks.md +++ b/tasks.md @@ -71,8 +71,7 @@ Uavhengige faser kan fortsatt plukkes. ## Fase 4: Tilgangskontroll -- [~] 4.1 `recompute_access` i maskinrommet: ved edge-endring, oppdater `node_access`-matrisen. Håndter direkte edges (owner, admin, member, reader). - > Påbegynt: 2026-03-17T14:45 +- [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. - [ ] 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.