Files

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_ADMIN krijgt de expliciete globale scope (workspace_id=None) en ziet dat ook op het scherm staan (Scope: All workspaces).
  • WORKSPACE_ADMIN en AUDITOR zijn gebonden aan principal.workspace_id, voor lijst, statustellers, filters, source-namen, detail en retry. AUDITOR is 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 een payload.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 UPDATE zelf, 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 als SECURITY_FAILURE met 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_ROOTS blijft 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, stat en open onschadelijk 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.