Migration: parent_kb backfill (OpenFGA tuple store)
Storage: OpenFGA tuple store (persisted). This change requires a migration — it is not a no-op.
Required vs no-op
Required. Two things must happen in order:
- Publish the new authorization-model version (the
data_source.parent_kbrelation + inheritedcan_*). Until the new model is live,parent_kbtuples reference an unknown relation. - Backfill one
data_source:<id> parent_kb knowledge_base:<id>edge per existing KB-backed datasource.
No application DB (Mongo/SQL) changes. No index changes.
Schema / model changes
See contracts/openfga-model.md. New OpenFGA model version adds the parent_kb relation and three tupleToUserset branches on data_source. Linked types: data_source (changed), knowledge_base (unchanged).
Data movement (the backfill)
- What: for each datasource id
Xthat has a corresponding knowledge base, writedata_source:X parent_kb knowledge_base:X. - Source of pairing: the shared
<datasource_id>(1:1). Enumerate from one of:- existing
knowledge_base:<id>tuples in the store, and/or - the RAG server
/v1/datasourceslist (already used by the catalog route).
- existing
- Idempotency: writes go through the existing
writeOpenFgaTuples, which pre-checks each tuple and skips ones already present → safe to re-run (INV-5 / US2 SC-002). - Batching: respects the existing OpenFGA per-call write cap (chunking already implemented in
openfga.ts). Datasource counts are small, so typically a single chunk. - Framework: add as a new entry in
ui/src/lib/rbac/migrations/registry.tsfollowing the strictly-additive pattern ofdata_source_grants_backfill_v1(which this eventually retires). Suggested id:data_source_parent_kb_backfill_v1. Deletes: none.
Ordering & mirror cushion (see research R5 — DECISION NEEDED)
Recommended:
- Deploy new model version.
- Run
data_source_parent_kb_backfill_v1. - Keep the mirror (
mirrorKnowledgeBaseDiffToDataSource) writing for one release as rollback insurance. - Follow-up: remove the mirror + its call sites; retire
data_source_grants_backfill_v1.
Rollback
- Revert the model version to the prior one. Because direct
data_sourceaccess tuples are still present (written by the create path historically + the retained mirror during the cushion), effective access is unchanged by the revert. data_source:<id> parent_kb knowledge_base:<id>tuples are inert under the old model (the relation no longer exists in the model) and can be left in place or swept by a reverse backfill later. They grant nothing on their own.- No data loss: the migration only adds tuples.
Environments
- Helm and local Docker Compose load the same chart JSON model, so there is one artifact to version. No per-environment divergence. Apply the model version + backfill in each environment's OpenFGA store.
Verification
- After backfill:
ListObjects(member, can_read, data_source)returns the same or a superset of pre-migration results for a representative user set (no access lost — SC-002). - Spot-check: a datasource with only
team#member reader knowledge_base:<id>(nodata_sourcetuple) now passesCheck(member, can_read, data_source:<id>) = true(SC-001). - See
quickstart.mdfor concrete commands.