Valider fase 3–4: fiks belongs_to-tilgangspropagering og mottakssortering
Validering av fase 3 (frontend) og fase 4 (tilgangskontroll) avdekket to bugs: 1. belongs_to-access-gap: Når en belongs_to-edge opprettes ETTER at noen allerede har tilgang til foreldrenoden, fikk ikke barnenoden tilgangsoppføringer i node_access-matrisen. F.eks. kunne Vegard (eier av en kommunikasjonsnode) ikke se innhold opprettet av Claude med belongs_to-edge til den noden. Løsning: Ny PG-funksjon propagate_belongs_to_access() som kopierer forelderens tilgangsrader til barnet. Kalles fra maskinrommet ved opprettelse av belongs_to-edges (create_node m/context, create_edge, create_communication m/context). Retroaktiv fiks for eksisterende data. 2. Mottaksflate-sortering: Brukte .microsSinceUnixEpoch (SpacetimeDB- BigInt-arv) på vanlig number-felt, ga alltid 0n → ingen sortering. Fikset til direkte number-sammenligning. Verifisert: SvelteKit + maskinrommet bygger og kjører. PG-skjema, OIDC, WebSocket/NOTIFY, RLS-policies, team-transitivitet og visibility fungerer.
This commit is contained in:
parent
773569759c
commit
5dfaeff53c
4 changed files with 85 additions and 7 deletions
|
|
@ -67,11 +67,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by created_at descending
|
// Sort by created_at descending
|
||||||
nodes.sort((a, b) => {
|
nodes.sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
|
||||||
const ta = a.createdAt?.microsSinceUnixEpoch ?? 0n;
|
|
||||||
const tb = b.createdAt?.microsSinceUnixEpoch ?? 0n;
|
|
||||||
return tb > ta ? 1 : tb < ta ? -1 : 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -595,6 +595,16 @@ pub async fn create_node(
|
||||||
"belongs_to-edge opprettet (kontekst-arv)"
|
"belongs_to-edge opprettet (kontekst-arv)"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Propager tilgang: alle som har tilgang til ctx_id får tilgang til node_id
|
||||||
|
if let Err(e) = sqlx::query("SELECT propagate_belongs_to_access($1, $2)")
|
||||||
|
.bind(node_id)
|
||||||
|
.bind(ctx_id)
|
||||||
|
.execute(&state.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::error!("propagate_belongs_to_access feilet: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
Some(edge_id)
|
Some(edge_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -881,6 +891,18 @@ pub async fn create_edge(
|
||||||
internal_error("Databasefeil ved opprettelse av edge")
|
internal_error("Databasefeil ved opprettelse av edge")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// Propager tilgang ved belongs_to: alle som har tilgang til target (forelder) får tilgang til source (barn)
|
||||||
|
if req.edge_type == "belongs_to" {
|
||||||
|
if let Err(e) = sqlx::query("SELECT propagate_belongs_to_access($1, $2)")
|
||||||
|
.bind(req.source_id)
|
||||||
|
.bind(req.target_id)
|
||||||
|
.execute(&state.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::error!("propagate_belongs_to_access feilet: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger rendering ved belongs_to
|
// Trigger rendering ved belongs_to
|
||||||
if req.edge_type == "belongs_to" {
|
if req.edge_type == "belongs_to" {
|
||||||
if let Ok(Some(config)) = crate::publishing::find_publishing_collection_by_id(&state.db, req.target_id).await {
|
if let Ok(Some(config)) = crate::publishing::find_publishing_collection_by_id(&state.db, req.target_id).await {
|
||||||
|
|
@ -1946,6 +1968,16 @@ pub async fn create_communication(
|
||||||
context_id = %context_id,
|
context_id = %context_id,
|
||||||
"belongs_to-edge opprettet til kontekstnode"
|
"belongs_to-edge opprettet til kontekstnode"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Propager tilgang fra kontekstnoden
|
||||||
|
if let Err(e) = sqlx::query("SELECT propagate_belongs_to_access($1, $2)")
|
||||||
|
.bind(node_id)
|
||||||
|
.bind(context_id)
|
||||||
|
.execute(&state.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::error!("propagate_belongs_to_access feilet: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
|
|
||||||
51
migrations/020_belongs_to_access_propagation.sql
Normal file
51
migrations/020_belongs_to_access_propagation.sql
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
-- Migrasjon 020: Propager tilgang ved nye belongs_to-edges
|
||||||
|
--
|
||||||
|
-- Når en belongs_to-edge opprettes mellom barn og forelder, skal alle
|
||||||
|
-- som allerede har tilgang til forelderen også få tilgang til barnet.
|
||||||
|
-- recompute_access håndterer dette i steg 2 for access-granting edges,
|
||||||
|
-- men ikke for belongs_to-edges som opprettes etter at tilgang allerede er gitt.
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION propagate_belongs_to_access(
|
||||||
|
p_child_id UUID,
|
||||||
|
p_parent_id UUID
|
||||||
|
) RETURNS void LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
-- For alle som har tilgang til forelder: gi samme tilgang til barnet
|
||||||
|
INSERT INTO node_access (subject_id, object_id, access, via_edge)
|
||||||
|
SELECT na.subject_id, p_child_id, na.access, na.via_edge
|
||||||
|
FROM node_access na
|
||||||
|
WHERE na.object_id = p_parent_id
|
||||||
|
ON CONFLICT (subject_id, object_id)
|
||||||
|
DO UPDATE SET access = GREATEST(node_access.access, EXCLUDED.access),
|
||||||
|
via_edge = CASE
|
||||||
|
WHEN EXCLUDED.access > node_access.access THEN EXCLUDED.via_edge
|
||||||
|
ELSE node_access.via_edge
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- Retroaktivt: fiks eksisterende belongs_to-edges der tilgang mangler.
|
||||||
|
-- Finn barn som har belongs_to-edge til forelder, men der forelderens
|
||||||
|
-- tilgangssubjekter ikke har tilgang til barnet.
|
||||||
|
DO $$
|
||||||
|
DECLARE
|
||||||
|
r RECORD;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN
|
||||||
|
SELECT e.source_id AS child_id, e.target_id AS parent_id
|
||||||
|
FROM edges e
|
||||||
|
WHERE e.edge_type = 'belongs_to'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM node_access na
|
||||||
|
WHERE na.object_id = e.target_id
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM node_access na2
|
||||||
|
WHERE na2.subject_id = na.subject_id
|
||||||
|
AND na2.object_id = e.source_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
LOOP
|
||||||
|
PERFORM propagate_belongs_to_access(r.child_id, r.parent_id);
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
3
tasks.md
3
tasks.md
|
|
@ -296,8 +296,7 @@ fiks direkte hvis det er småting, eller opprett nye work_items (tasks)
|
||||||
med spesifikasjon for det som trenger en dedikert sesjon.
|
med spesifikasjon for det som trenger en dedikert sesjon.
|
||||||
|
|
||||||
- [x] 23.1 Valider fase 1–2 (infra + maskinrommet): PG-skjema, indekser, auth-middleware, intensjoner, STDB-klient (nå erstattet av WS). Verifiser at skjema matcher docs, at auth fungerer, at skrivestien er konsistent.
|
- [x] 23.1 Valider fase 1–2 (infra + maskinrommet): PG-skjema, indekser, auth-middleware, intensjoner, STDB-klient (nå erstattet av WS). Verifiser at skjema matcher docs, at auth fungerer, at skrivestien er konsistent.
|
||||||
- [~] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering.
|
- [x] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering.
|
||||||
> Påbegynt: 2026-03-18T14:30
|
|
||||||
- [ ] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet.
|
- [ ] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet.
|
||||||
- [ ] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.
|
- [ ] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.
|
||||||
- [ ] 23.5 Valider fase 11 (produksjon): LiveKit-oppsett, sanntidslyd, pruning-logikk, podcast-RSS.
|
- [ ] 23.5 Valider fase 11 (produksjon): LiveKit-oppsett, sanntidslyd, pruning-logikk, podcast-RSS.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue