Dossiê — RAG access control (UNKNOWN)
Falha crítica #3 da auditoria "Manus AI" (NO-GO). ✅ RESOLVIDO (2026-09-04): FINDING-2 fechado — driver RAG access regravado localmente (200/403/401 exatos, run
20260904T044108Z-da114ad), exercitando o gate que a auditoria não rodou. Veredito do audit: GO CONDICIONAL (03-findings.md§FINDING-2). Veredito: o controle de acesso ao RAG existe e está implementado — a auditoria marcou "UNKNOWN" porque não o executou (não há evidência de que o gate foi exercitado). O mecanismo é role-gated, fail-closed, e coberto por um e2e dedicado (E2E-34) que roda verde.
1. O que a auditoria apontou
"RAG access control — UNKNOWN": a auditoria não conseguiu determinar se o acesso ao RAG do conhecimento é controlado por role.
2. O mecanismo (role-gated, fail-closed)
O RAG do conhecimento do projeto (owner pinha) é acessível por duas rotas, ambas gateadas por role via Keycloak (RFC 7662) + Datomic authority:
| Rota | Permissão | Handler |
|---|---|---|
POST /rag/ingest | :rag-ingest | rag-ingest-handler (core.clj:382) |
POST /rag/query | :rag-read | rag-query-handler (core.clj:471) |
O fluxo de autorização (authorization/authorize-request → authenticate + authorize):
- authenticate — introspecta o Bearer token contra o Keycloak; sem token
ativo → {:authorized? false :reason :unauthenticated} → 401.
- authorize — resolve as roles do ator no Datomic authority store e
verifica permitted? para a operação; sem permissão → {:authorized? false :reason :forbidden} → 403.
- allowlist de owner — mesmo autorizado, o handler ainda verifica
(contains? rag-allowlist owner-id) via roles-rag-allowlist (união das allowlists das roles). Owner fora da allowlist → 403 "forbidden: RAG owner pinha not allowed for this role".
O seed de produção (config.clj:178) define:
| Role | Permissões | :rags (owners) |
|---|---|---|
::operator | #{:* :rag-ingest :rag-read} | #{"pinha" "dev-machine"} |
::admin | #{:register-user! :read …} | #{} (vazio) |
::user | #{:read} | #{} (vazio) |
::teste | #{:read} | #{} (vazio) |
E o mapeamento de usuários (config.clj:201):
ianffcs → ::operator
pcms → ::operator
ctni.teste → #{::user ::teste} ; "must NOT reach the project knowledge RAG"
Fail-closed: roles-rag-allowlist retorna #{} (vazio) quando a role não tem :rags — e (contains? #{} "pinha") é false. Ou seja, qualquer role sem pinha na allowlist é negada, não "permitida por omissão".
3. Evidência de que funciona (E2E-34)
O cenário E2E-34 (docs/test-plans/done/e2e-34-rag-knowledge-access-control.md, driver e2e_rag_knowledge_access.clj) evidencia, sobre o servidor Jetty real:
pcms/ianffcs(role::operator) → 200 emPOST /rag/querye
POST /rag/ingest;
ctni.teste(role::user) → 403 em ambos;- sem token → 401.
O driver roda com clojure -M:dev -m small-pine.e2e-rag-knowledge-access → exit 0.
4. Por que a auditoria marcou "UNKNOWN"
O gate de RAG não é exercitado por nenhum caminho que a auditoria "Manus AI" tenha percorrido. As causas prováveis:
- O RAG estava desabilitado em produção na época da auditoria — o conf não
renderizava rag-enabled (o artefato era a Fase 1 lexical afbefc0943f7, sem E5), então POST /rag/query retornava 503 "rag is disabled" antes de chegar ao gate de role. A auditoria viu 503, não 401/403, e não conseguiu distinguir "desabilitado" de "não controlado".
- A correção do deploy que renderizou
rag-enabled(neotek-20260831T214119-84895)
é posterior à auditoria — o E2E-40 (RAG habilitado em produção) foi marcado implementado em 2026-08-31.
Ou seja: o "UNKNOWN" é um artefato de timing (RAG desligado no momento da auditoria), não uma ausência de controle.
5. Conclusão
- O controle de acesso ao RAG existe, é role-gated e fail-closed — três
camadas (401 sem token, 403 sem permissão, 403 owner fora da allowlist).
- O "UNKNOWN" reflete que a auditoria não executou o gate (RAG desligado na
época), não que o gate está ausente.
- A evidência de que funciona é o E2E-34 (verde) + o E2E-40 (RAG
habilitado em produção, operador 200 / ::user 403 / sem token 401).