Fullfør oppgave 4.1: recompute_access ved edge-endring
Når en tilgangsgivende edge (owner, admin, member_of, reader) opprettes, kalles nå recompute_access() i samme PG-transaksjon som edge-insertet. Dette sikrer at node_access-matrisen alltid er oppdatert — ingen vindu med stale tilgang. Implementasjon: - edge_type_to_access_level() mapper edge-typer til access_level enum - insert_edge_with_access() wrapper edge-insert + recompute_access i tx - Vanlige edges (belongs_to, mentions, etc.) skrives som før (fire-and-forget) Verifisert med SQL-tester: direkte tilgang + transitiv tilgang via belongs_to-edges fungerer korrekt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
03211e59a5
commit
c20fc9149b
2 changed files with 107 additions and 22 deletions
|
|
@ -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,
|
||||
|
|
|
|||
3
tasks.md
3
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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue