21. Proposta — Camada de IA consultiva (opt-in)¶
Versão de referência: v0.8.3 — proposta de 2026-07-04.
Status: FASES 0, 1, 2 e 3 IMPLEMENTADAS. Fase 0 (
--advice: templates + referências OWASP,internal/enrich) — determinística, sem IA. Fase 2 (RAG-as-artifact: corpus OWASP pinado por digest emknowledge/owasp/, retrieval léxico determinístico por padrão e semântico por embeddings quando disponível,internal/rag) — também determinística e roda sob--advice. Fase 1 (--advice-provider=local+--fix=suggest: recomendação de LLM local, aterrada no corpus RAG, e patch com verify-the-fix,internal/advisor) — opt-in, off por padrão. A Fase 3 (--advice-provider=remote: API externa, com egress explícito) — opt-in, off por padrão, com os guardrails abaixo. O núcleo segue 100% determinístico e, sem as flags, a saída é byte-idêntica.
Cross-links: 13. IA (as-is) · 05. Modelo de dados · 06. Interfaces (CLI) · 12. Segurança · DESIGN.md.
Escopo desta proposta — três features solicitadas:
- Recomendações com IA (local-first).
- Geração automática de remediações.
- RAG com documentação OWASP.
1. Princípio-âncora (inegociável)¶
O diferencial do Quorum é ser determinístico, auditável e air-gapped: o mesmo
input produz o mesmo Fingerprint = sha256(correlationKey), e a decisão de
pass/fail do gate é 100% reproduzível. IA generativa é probabilística. Logo, toda
esta proposta obedece a uma única regra:
A camada de IA é consultiva e opcional. Ela NUNCA toca
correlationKey,fingerprint,confidence,severityagregada, nem a decisão de exit code do gate. Ela entra depois do consenso, escreve em campos novos marcadosaiGenerated/advisory, e pode ser removida sem alterar nenhum byte do núcleo.
Corolário de distribuição: local-first. Para uma ferramenta que roda em CI
air-gapped e não pode vazar código-fonte, o provedor local é o default e o
remoto é o opt-in excepcional (com egress explícito e bloqueável por --offline).
2. As três features — veredito¶
| Feature | Valor | Risco principal | Como a proposta neutraliza |
|---|---|---|---|
| 1. Recomendações com IA | Alto (triagem/priorização; descrições dos scanners são secas) | Alucinação; não-determinismo; prompt-injection via conteúdo do finding | Local-first; temperature=0+seed; cache por fingerprint; rotulagem advisory |
| 2. Remediação automática | Muito alto p/ IaC/K8s/Dockerfile | Patch errado "que parece seguro"; HCL que nem parseia | 2 níveis (template determinístico + IA); verify-the-fix loop; --fix=suggest (nunca apply) |
| 3. RAG com OWASP | Alto (aterra 1 e 2 em fonte citável) | Vector DB vivo colide com "sem DB, air-gapped, determinístico" | RAG-as-artifact: índice pinado por digest, retrieval determinístico |
3. Arquitetura — onde encaixa¶
Um novo estágio advisor roda após o merge/consenso, sobre
[]model.MergedFinding, atrás de uma interface plugável no espírito dos adapters
(internal/adapter) e do alias resolver (internal/alias).
flowchart LR
C["correlate + consensus<br/>(determinístico — núcleo)"] --> R0["MergedFinding[]"]
R0 --> G{"--advice / --fix<br/>ligados?"}
G -- não --> OUT["report SARIF/JSON/XML<br/>(idêntico ao de hoje)"]
G -- sim --> ADV["advisor stage (opcional)"]
subgraph ADV_INNER["advisor (nunca toca o núcleo)"]
T["Nível A: template<br/>remediação por canonicalControl"]
KB["retrieval OWASP<br/>(artefato pinado)"]
L["Nível B: LLM local<br/>(temp=0, cache p/ fingerprint)"]
V["verify-the-fix<br/>re-scan do arquivo corrigido"]
T --> L
KB --> L
L --> V
end
ADV --> OUT2["report + campos advice/remediation/references<br/>(marcados aiGenerated/advisory)"]
classDef det fill:#dfd,stroke:#080;
classDef ai fill:#ffe8cc,stroke:#d90;
class C,R0,T,KB,V det;
class L ai;
Interface proposta (internal/advisor):
// Advisor produz conselho consultivo para um finding já correlacionado/scored.
// Erro NUNCA falha o scan (degradação graciosa, igual ao OSV client §DESIGN 7).
type Advisor interface {
Advise(ctx context.Context, f model.MergedFinding, kb KnowledgeBase) (Advice, error)
}
// Implementações:
// nullAdvisor — default/off; retorna Advice vazio.
// localAdvisor — endpoint OpenAI-compatible/Ollama em localhost.
// remoteAdvisor — opt-in; egress explícito; bloqueado por --offline.
Campos novos no MergedFinding (todos omitempty, ignorados pelo gate):
Remediation *Remediation `json:"remediation,omitempty"` // Nível A: template determinístico
Advice *Advice `json:"advice,omitempty"` // Nível B: IA (aiGenerated:true, advisory:true)
References []DocRef `json:"references,omitempty"` // OWASP/CWE curados
Mapeamento de saída:
- SARIF:
Remediation/Advice→result.fixes[].artifactChanges(o GitHub renderiza como suggested change);References→result.relatedLocations/help. Tudo marcado"AI-generated, advisory only"quando vier do Nível B. - JSON: campos diretos no finding. XML: idem, opcionais.
4. Feature 2 — Remediação automática (dois níveis)¶
Escopo (decidido): apenas IaC / K8s / Dockerfile — onde o fix é
bem-escopado e o Quorum já tem Location.File/StartLine/EndLine. SCA/CVE fica
de fora do auto-fix (bump de versão de dependência é arriscado e quebra build);
para SCA, no máximo um texto "atualize pkg para ≥ X.Y.Z" como recomendação, sem
patch.
Nível A — determinístico (sem IA), construir primeiro¶
Templates de correção curados, indexados por canonicalControl (o crosswalk já
resolve o controle). Exemplos:
| canonicalControl | Remediação-template |
|---|---|
AVD-AWS-0088 (S3 sem SSE) |
injeta bloco server_side_encryption_configuration |
C-0017 (readOnlyRootFilesystem) |
securityContext.readOnlyRootFilesystem: true |
IMG_HARDENING (Dockerfile sem USER) |
adiciona USER <non-root> |
Propriedades: auditável, air-gapped, zero alucinação, reproduzível. Cobre o top-N dos controles. Esta camada sozinha já justifica um release.
Nível B — IA (opt-in), para o long tail / contextualização¶
Usa o LLM local para gerar um patch proposto contra o arquivo real (ex.: finding sem template, ou adaptar o template ao HCL específico). Regras:
--fix=suggestapenas — emite o diff; nunca aplica (applynão é default e exige flag/consentimento explícito).- Verify-the-fix loop (a maior salvaguarda anti-alucinação, e a cara do produto): gerar patch → re-scanear o arquivo corrigido com o mesmo scanner → só apresentar se (a) o finding desapareceu e (b) o arquivo ainda parseia. Patch que não passa nesse teto é descartado, não mostrado.
- Rotulagem
aiGenerated: true, advisory: true.
flowchart LR
F["finding + arquivo real"] --> P["LLM local propõe patch"]
P --> AP["aplica patch numa cópia temporária"]
AP --> RS["re-scan (mesmo scanner)"]
RS --> Q{"finding sumiu<br/>E arquivo parseia?"}
Q -- sim --> SHOW["emite como suggested fix (verificado)"]
Q -- não --> DROP["descarta (não mostra)"]
5. Feature 3 — RAG com OWASP (as-artifact, não as-service)¶
Nada de vector DB vivo. Duas camadas:
Nível A — mapa curado determinístico¶
Lookup table CWE / canonicalControl / category → referências OWASP, no mesmo
padrão do crosswalk/*.yaml (YAML versionado, carregado como dado). Exemplos:
| Chave | Referência OWASP |
|---|---|
CWE-311 (encryption) |
OWASP Cryptographic Failures / Transport Layer Security Cheat Sheet |
K8S_POSTURE |
OWASP Kubernetes Security Cheat Sheet |
CWE-284 (network/access) |
OWASP Access Control / Authorization Cheat Sheet |
100% determinístico, sem embeddings, sem modelo. Cobre ~80% do valor.
Nível B — retrieval semântico sobre artefato pinado¶
Corpus OWASP (ASVS, Cheat Sheets, Top 10, K8s/IaC) chunked + embeddado em build-time num índice read-only, versionado e pinado por digest, distribuído como:
- artefato no
:full(ao lado do crosswalk), ou - OCI artifact separado
quorum-knowledge@sha256:…, atestado igual às base images (SLSA + SBOM).
Retrieval em CI = k-NN sobre índice imutável → air-gap preservado e reproduzível (índice não muda entre runs). O embedding roda local (mesmo runtime do LLM). Sem chamadas externas.
Licença: conteúdo OWASP é CC-BY-SA → exige atribuição em THIRD_PARTY_NOTICES.md e preservação de licença no artefato de conhecimento.
6. Feature 1 — Recomendações com IA (reprodutíveis por cache)¶
Recomendação/triagem em linguagem natural para um finding já correlacionado
(prioridade, "por que isto importa aqui", próximos passos), aterrada nas
References OWASP (Feature 3) e no template (Feature 2). Melhorias que a tornam
auditável:
- Determinismo prático:
temperature=0+ seed fixa + modelo pinado por digest. - Cache por
fingerprint + modelDigest + promptVersionno mesmo padrão do~/.cache/quorum/aliases.json(0600,schemaVersion). Mesmo finding + mesmo modelo → mesmo texto (servido do cache). O não-determinismo do LLM vira cacheável e reproduzível. - Rotulagem
"AI-generated, advisory only"em toda saída.
7. Flags e configuração¶
Consistentes com as existentes (--offline, --metrics, --log-format):
| Flag | Default | Efeito |
|---|---|---|
--advice |
off |
liga a camada consultiva (templates determinísticos + referências OWASP) |
--advice-provider |
none |
none | local | remote |
--advice-endpoint |
http://localhost:11434/v1 |
base URL OpenAI-compatible (local por padrão; para remoto, ex.: https://api.openai.com/v1) |
--advice-model |
qwen2.5-coder:7b |
id do modelo para --advice-provider=local |
--advice-embed-model |
nomic-embed-text |
modelo de embedding para retrieval semântico OWASP / advise-index |
--advice-cache |
~/.cache/quorum/advice.json |
arquivo de cache do conselho de IA (chaveado por fingerprint+modelo) |
--advice-max |
50 |
máximo de findings enviados ao provedor de IA por run (0 = sem limite) |
--advice-allow-egress |
off |
consentimento p/ enviar findings para fora do host: obrigatório para --advice-provider=remote |
--fix |
off |
off | suggest (apply nunca é default) |
--offline |
(existente) | bloqueia remote; local continua permitido (é on-host) |
O novo subcomando quorum advise-index embeda o corpus OWASP (preservando o pin
por digest); a partir daí, scan --advice --advice-provider local seleciona
automaticamente o retrieval semântico. Sem nenhuma flag ligada, a saída é
byte-idêntica à de hoje.
8. Guardrails (expande 13-ia §6)¶
| Guardrail | Regra |
|---|---|
| Opt-in explícito | Tudo atrás de flag, off por padrão |
| Núcleo intocável | IA não altera correlação, fingerprint, confidence, severidade agregada ou exit code |
| Determinismo do gate | Decisão pass/fail permanece 100% determinística |
| Local-first | O provedor local é o modo on-host de referência; remote exige opt-in e é bloqueado por --offline |
| Privacidade | Enviar só o finding normalizado ao modelo; o remoto exige --advice-allow-egress e recusa --fix (sem upload de código) |
| Anti prompt-injection | Conteúdo de finding tratado como dado, sanitizado/escapado; nunca como instrução |
| Verify-the-fix | Todo patch do Nível B re-scaneado; só apresenta se o finding some e o arquivo parseia |
| Rotulagem | Toda saída de modelo marcada "AI-generated, advisory only" |
| Reprodutibilidade | temperature=0, seed, modelo pinado por digest, cache por fingerprint |
| Supply chain do modelo | Artefato do modelo e índice OWASP pinados por digest e atestados (igual às base images @sha256, ao grype DB e ao knowledge pack com atestação SLSA) |
| Custo/limites | Timeout, retries, fallback gracioso (padrão do OSV client); IA fora do ar → relatório sai sem advice, scan nunca falha |
| Evals | Suite de avaliação (internal/evals: cobertura de remediação, relevância de referências OWASP, taxa do verify-the-fix) roda no CI antes de promover qualquer recurso a default |
Atenção — o OWASP LLM Top 10 deixa de ser N/A. O 13-ia §4 lista prompt-injection etc. como N/A porque não há IA no núcleo. Ao habilitar a camada consultiva, essa superfície reabre: o artefato do modelo vira dependência de supply chain (pinar/atestar) e o conteúdo de findings vira vetor de prompt-injection (sanitizar). Reabrir o checklist de conformidade do §5.
9. Distribuição do modelo (decidido)¶
- O modelo local é shipado fora do
:slim— só no:fullou baixado sob demanda (pinado por digest, verificado por checksum, igual aos scanners noDockerfile.full). O:slim(orchestrator-only, multi-arch) não infla. - Alvo default: modelo pequeno quantizado apto a código (ex.: Qwen2.5-Coder 7B ou
Llama 3.1 8B via Ollama). O default shipado em
--advice-modeléqwen2.5-coder:7b, guiado por evals.
10. Roadmap faseado (cada fase é útil sozinha)¶
| Fase | Entrega | IA? | Risco |
|---|---|---|---|
| 0 ✅ implementada | Templates de remediação por canonicalControl + mapa controle/categoria/tipo → OWASP (Níveis A de 2 e 3). Flag --advice, pacote internal/enrich, knowledge/*.yaml |
Não | Zero — 100% on-brand |
| 1 ✅ implementada | localAdvisor (OpenAI-compatible/Ollama): recomendações + patch sob --fix=suggest com verify-the-fix, cache por fingerprint, rotulagem, degradação graciosa. Pacote internal/advisor; flags --advice-provider/-endpoint/-model/-cache/-max, --fix |
Sim (local) | Baixo (opt-in, verificado) |
| 2 ✅ implementada | RAG-as-artifact: corpus OWASP pinado por digest (knowledge/owasp/corpus.yaml), retrieval léxico (default, sem modelo) + semântico por embeddings quando disponível; anexa referências e aterra o prompt da Fase 1. Subcomando advise-index, pacote internal/rag |
Léxico: não; semântico: local | Médio (peso/supply chain) |
| 3 ✅ implementada | Provedor remote opt-in: API externa autenticada (QUORUM_ADVICE_API_KEY), egress explícito (--advice-allow-egress), bloqueado por --offline, recusa --fix (sem upload de código); só o finding normalizado sai. advisor.NewRemoteClient |
Sim (remoto) | Médio (privacidade) |
Observabilidade: sob --advice, o Quorum exporta quorum_advice_enriched{kind=remediation|references|recommendation},
quorum_advice_provider{provider} e quorum_advice_fix{stage=proposed|verified}
(verified/proposed = a taxa do verify-the-fix).
Recomendação: começar pela Fase 0, que entrega a maior fatia do valor com risco zero e mantém a promessa determinística intacta.
Premissas¶
- O estado as-is (sem IA no núcleo) está em 13-ia e continua sendo o enquadramento honesto: o núcleo não tem IA, e esta camada consultiva é opt-in e off por padrão.
- A camada
advisorroda estritamente após o consenso, sobre[]MergedFinding, sem realimentar o núcleo — consistente com o pipeline atual (04-arquitetura, 05-modelo-de-dados). - O
Location.File/StartLine/EndLinedo modelo é suficiente para localizar o trecho a corrigir em IaC/K8s/Dockerfile (verificado em internal/model/model.go). - SCA/CVE foi deliberadamente excluído do auto-fix (risco de quebrar build no bump de dependência); decisão registrada nesta proposta.
- O modelo local e o índice OWASP são tratados como dependências de supply
chain (pinar por digest + atestar), o mesmo tratamento das base images e do
grype DB (10-infraestrutura, 12-seguranca); o
knowledge pack agora carrega uma atestação de build-provenance SLSA a cada
release (verifique com
gh attestation verify knowledge/owasp/corpus.yaml). - "RAG-as-artifact" pressupõe índice imutável versionado; qualquer atualização do corpus OWASP é uma nova versão pinada, nunca um fetch dinâmico em runtime.