Ir para o conteúdo

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 em knowledge/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:

  1. Recomendações com IA (local-first).
  2. Geração automática de remediações.
  3. 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, severity agregada, nem a decisão de exit code do gate. Ela entra depois do consenso, escreve em campos novos marcados aiGenerated/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/Adviceresult.fixes[].artifactChanges (o GitHub renderiza como suggested change); Referencesresult.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:

  1. --fix=suggest apenas — emite o diff; nunca aplica (apply não é default e exige flag/consentimento explícito).
  2. 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.
  3. 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 + promptVersion no 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 :full ou baixado sob demanda (pinado por digest, verificado por checksum, igual aos scanners no Dockerfile.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
0implementada 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
1implementada 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)
2implementada 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)
3implementada 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 advisor roda 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/EndLine do 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.