5.1 KiB
Security Controls
Identity
OIDC voor mensen; gehashte, roteerbare service tokens met scopes en expiry voor applications. Tokens worden slechts eenmaal getoond.
Authorization
Deny by default, explicit grants, effective-space intersection, use-case policies, database scoping, verplichte Qdrantfilters en resource reauthorization voor citations/downloads.
Operations isolation
Iedere workspace-scoped job draagt expliciete ownership: jobs.jobs.workspace_id
is een echte kolom (migratie 0018), geen veld in payload. Elke lijst, teller,
detailpagina en mutatie filtert daarop in de query zelf --- nooit op rijen die al
opgehaald zijn.
PLATFORM_ADMINkrijgt de expliciete globale scope (workspace_id=None) en ziet dat ook op het scherm staan (Scope: All workspaces).WORKSPACE_ADMINenAUDITORzijn gebonden aanprincipal.workspace_id, voor lijst, statustellers, filters, source-namen, detail en retry.AUDITORis read-only: retry vereist een rol uit_RETRY_ROLES.- Een job zonder ownership (
workspace_id IS NULL, alleen mogelijk voor rijen van vóór 0018 waarvan de eigenaar niet betrouwbaar vast te stellen was) faalt gesloten: onzichtbaar en onmuteerbaar voor iedere workspace-scoped principal, uitsluitend inspecteerbaar door een platform admin. Er is nergens eenpayload.get("workspace_id") or principal.workspace_id-fallback; die kende een ownerloze job toe aan wie er toevallig naar keek. - Tellers zijn ook tenantdata. Dashboard- en System Health-queuecijfers gebruiken dezelfde scope als de Jobs-lijst.
- Ook de operatorfilters (status, type) en de paginering zijn predicaten van
diezelfde query (
JobListFilter--- migratie 0019 voegt de bijbehorende index toe). Er wordt dus geen bredere set opgehaald dan getoond wordt: elke rij die dit proces binnenkomt is er één die deze principal mag zien. De vijf tellers boven de tabel blijven bewust een scope-brede samenvatting van de wachtrij en het scherm zegt dat er ook bij. - Retry dwingt ownership af in het
UPDATEzelf, niet in een voorafgaande read: een cross-tenant mutatie die alleen onder concurrency lukt is nog steeds een cross-tenant mutatie. Een geweigerde toegang of retry wordt vastgelegd alsSECURITY_FAILUREmet actor, workspace, actie, doel en reden --- zonder payload.
Nieuwe jobs kunnen niet ownerloos ontstaan: JobService.enqueue eist
workspace_id en PostgresJobRepository.enqueue weigert een Job zonder.
Filesystem-backed sources
Een Folder-source, en de lokale checkout root van een Git-source, geven de worker
een leesprimitief op de host: alles onder dat pad wordt vindbare content. Dat is
iets anders dan content beheren, dus het vereist FILESYSTEM_SOURCE_MANAGE
bovenop SOURCE_MANAGE, bij zowel aanmaken als bewerken (bewerken is precies
hoe een goedgekeurde source op een andere directory gericht wordt).
Gekozen model: alleen PLATFORM_ADMIN. RAGCORE_SOURCE_ROOTS is één
deployment-brede lijst zonder per-workspace mapping, dus een pad binnen de
allowlist kan prima het corpus van een andere tenant zijn; een workspace admin met
dit recht zou workspace B kunnen lezen door er een source op te richten. Zolang
roots niet per workspace geconfigureerd zijn, is het kiezen van een serverpad een
deploymentbeslissing en hoort die bij de rol die de deployment bezit. Per-workspace
roots (het sterkere self-service model) blijven mogelijk als self-service
filesystem sources later echt nodig blijken.
Alleen de gevoelige kinds zijn beperkt: SOURCE_MANAGE blijft ongewijzigd voor
Editors en Space Managers, en upload-sources worden er niet moeilijker door.
Autorisatie en sandbox zijn twee onafhankelijke poorten, allebei altijd vereist:
RAGCORE_SOURCE_ROOTSblijft lexicaal afgedwongen bij opslaan, en volledig geresolved (symlinks gevolgd) in worker en connector vlak voor iedere read. Een pad buiten elke root wordt geweigerd --- ook voor een platform admin. Zonder geconfigureerde roots kan geen enkele filesystem-source bestaan.- De source mounts horen read-only te zijn. Dat is een security-invariant, niet
alleen een aanbeveling: het is wat het resterende TOCTOU-venster tussen
padvalidatie,
statenopenonschadelijk maakt. Zijn de directories muteerbaar door niet-vertrouwde actoren, dan is die aanname geschonden.
Network
Alleen app achter reverse proxy. PostgreSQL/Qdrant/worker op internal network. Geen debug/adminpoorten publiek. Egress voor connector/modelworkers zo beperkt mogelijk.
Content
MIME sniffing, allowlists, size/time/depth limits, archive-bombdetectie, quarantine, sandboxing waar haalbaar, geen macro/scriptuitvoering en read-only source mounts.
Secrets
Environment/secrets mount, geen plaintext in database/logs/evidence, redaction processor, onafhankelijke token pepper en rotatieprocedure.
Abuse prevention
Rate limits per principal/application, request/body/token/context limits, bounded concurrency, job quotas en circuit breakers.
Audit
Append-only events voor auth, grants, source changes, publication, modelroute, adminacties en security failures. Querycontentlogbeleid is per space configureerbaar.