Visão Geral¶
O Quorum (quorum-sec-scan, v0.8.3) é uma ferramenta CLI/Docker de consensus security scanning: ela orquestra um pool de 12 scanners de segurança open source (Trivy, Grype, Checkov, KICS, Terrascan, tfsec, Regula, Conftest, Dockle, Kubescape, Polaris, kube-score) sobre um alvo, normaliza todos os achados para um modelo canônico, resolve aliases de vulnerabilidade, correlaciona findings equivalentes entre as ferramentas e emite um único relatório que informa quantos e quais scanners detectaram cada problema — acrescido de um score de confiança derivado desse consenso. O Quorum não é mais um scanner: é a camada leve de correlação + consenso sobre as ferramentas que você já confia, projetada para rodar dentro de um pipeline de CI/CD e barrar um build via exit code. Uma camada consultiva opt-in (--advice) pode adicionalmente anexar remediação curada, referências OWASP e — quando explicitamente habilitada — recomendações de IA; ela é apenas de apresentação e nunca altera o núcleo determinístico. Este documento descreve objetivo, problema resolvido, público-alvo, personas, benefícios, diferenciais e casos de uso.
Referências de código verificadas para este documento:
README.md,DESIGN.md,cmd/quorum/root.go,cmd/quorum/scan.go,internal/adapter/,crosswalk/.
1. Objetivo do sistema¶
O objetivo do Quorum é transformar múltiplos relatórios de scanners incompatíveis em um único relatório consolidado e priorizável, no qual cada finding carrega evidência de consenso (quantas e quais engines o detectaram) e um score de confiança calculado, de forma determinística e acionável em CI/CD.
Em termos operacionais, o Quorum entrega:
- Orquestração — roda os scanners suportados para o alvo em paralelo, com timeout por scanner.
- Normalização — converte a saída de cada ferramenta em um
model.Findingcanônico (uma única escala de severidade, PURLs para pacotes, AVD/CIS/categoria para controles). - Resolução de aliases — unifica
CVE-…eGHSA-…do mesmo bug (apenas paraVULN) via aliases locais → cache local → OSV.dev (CVE preferido). - Correlação — agrupa findings equivalentes por um
correlationKeydeterminístico, específico por tipo. - Consenso — calcula
detectionCounteconfidence(0..1) para cada grupo. - Relatório — emite SARIF (primário), JSON ou XML, sempre com o status por scanner.
Pipeline conforme DESIGN.md §3 e o estágio-a-estágio descrito no README.md.
2. Problema resolvido¶
Diferentes scanners encontram problemas sobrepostos mas não idênticos e os reportam em formatos incompatíveis. Quem roda três ferramentas obtém três relatórios, findings duplicados e nenhum sinal sobre quais findings estão corroborados. Daí decorrem dores concretas:
| Dor sem o Quorum | Como o Quorum resolve |
|---|---|
| N scanners → N relatórios em formatos distintos | Modelo canônico único (model.Finding) + um relatório consolidado |
| Findings duplicados (o mesmo CVE em Trivy e Grype) | Correlação por correlationKey determinístico + dedup |
GHSA-… (Grype) e CVE-… (Trivy) tratados como bugs diferentes |
Alias Resolver unifica para a forma canônica (CVE preferido) |
| Misconfig de IaC igual em Checkov/KICS/Terrascan/tfsec/Regula sem sinal de convergência | Crosswalk regra → controle canônico (hub AVD) correlaciona entre engines |
| Postura de K8s repetida em Kubescape/Polaris/kube-score sem consolidação | Crosswalk k8s.yaml (hub C-#### do Kubescape) correlaciona os três engines |
| Sem sinal de corroboração entre ferramentas | detectionCount + detectedBy + confidence por finding |
| "0 findings" interpretado como "está seguro" | Status por scanner explícito (ran/skipped/unavailable/error/timeout) |
| Dedup temporal manual entre execuções de CI | partialFingerprints["quorum/v1"] = sha256(correlationKey) no SARIF |
| Imagens/binários de scanner como vetor de supply chain | Distribuição assinada keyless (cosign) + atestação SLSA build-provenance + SBOM SPDX atestada |
Princípio orientador: false split > false merge. Na dúvida, o Quorum mantém os findings separados e os marca como unmapped — um merge errado esconde risco. (Ver DESIGN.md §6, "Regra do não-match".)
O que o problema NÃO é (escopo)¶
O Quorum não se propõe a ser:
- um scanner novo (ele reusa scanners OSS existentes);
- uma solução de runtime security (modelo de stream, fora de escopo — proposta futura no roadmap);
- uma plataforma com painel web, daemon ou serviço persistente.
A camada consultiva não muda esse escopo: é opt-in, apenas de apresentação e desligada por padrão. Sem --advice, a saída é byte-idêntica, o núcleo determinístico não tem IA e qualquer recomendação de IA é estritamente opt-in (ver §7 Diferenciais e §9 Premissas).
3. Público-alvo¶
O Quorum é destinado a equipes que já operam scanners OSS e precisam consolidar e priorizar resultados dentro de pipelines automatizados:
- Equipes de AppSec / DevSecOps que mantêm security gates em CI/CD.
- Times de plataforma / engenharia de produtividade que padronizam tooling de segurança entre repositórios.
- Engenheiros de Cloud/IaC que validam Terraform e manifests K8s multi-cloud (AWS/Azure/GCP) antes do apply.
- Tech Leads / mantenedores que precisam de um sinal confiável (consenso) para decidir o que bloqueia um merge.
- Auditores de compliance que precisam de evidência rastreável (controles canônicos AVD/CIS, status por scanner, fingerprints estáveis).
O Quorum é CLI/Docker only: não há frontend web, banco relacional nem API REST HTTP. O núcleo determinístico não tem IA/LLM; uma camada consultiva opt-in (local ou remota) pode ser habilitada, mas fica desligada por padrão (ver §7 Diferenciais e §9 Premissas). O público é, portanto, técnico e centrado em automação.
4. Personas¶
| Persona | Objetivo principal | Como usa o Quorum | Métrica de sucesso |
|---|---|---|---|
| AppSec / DevSecOps Engineer | Reduzir ruído e priorizar o que é real | Configura --fail-on, --min-severity, .quorumignore; analisa confidence e detectionCount; opcionalmente --advice para remediação |
Menos falsos positivos no gate; findings corroborados priorizados |
| Tech Lead / Mantenedor | Decidir o que bloqueia o merge sem virar gargalo | Usa o gate de PR (exit code 1) e o resumo por severidade no stderr | PRs barrados apenas quando há risco corroborado |
| Auditor de Compliance | Evidência rastreável e mapeada a controles | Lê SARIF/JSON com partialFingerprints, controles canônicos (AVD/CIS) e status por scanner |
Trilha de auditoria reproduzível; supressões sempre logadas |
| Plataforma / CI/CD | Padronizar o scan entre N repositórios sem instalar scanners | Usa a imagem :full ou o GitHub Action composite (cosign-verificado; socket auto-montado em type: image) |
Onboarding de repositórios sem instalar tooling local |
| Engenheiro de Cloud/IaC | Validar Terraform/K8s multi-cloud antes do apply | quorum scan . --type repo / --type k8s, crosswalk regra→controle (AWS/Azure/GCP + K8s) |
Misconfig e postura de IaC correlacionadas entre múltiplas engines |
5. Benefícios¶
- Sinal em vez de ruído. O consenso (
detectionCount+confidence) separa findings corroborados de detecções isoladas; a contagem bruta não é confiança — a fórmula pesa diversidade de engine, severidade e confirmação autoritativa (DESIGN.md§9). - Consenso além de SCA. A corroboração cruzada não é mais só de vulnerabilidades: cobre misconfig de IaC multi-cloud (Checkov × KICS × Terrascan × tfsec × Regula × Trivy) e postura de Kubernetes (Kubescape × Polaris × kube-score), via crosswalk derivado de output real.
- Um relatório, vários formatos. SARIF (primário, para GitHub code scanning/DefectDojo), JSON (para processamento) e XML (pipelines legados/JUnit-like).
- Telemetria opcional.
--metricsgrava métricas em formato textfile do Prometheus;--log-format jsonemite logs de progresso estruturados (um objeto por linha) no stderr. - Dedup temporal grátis.
partialFingerprints["quorum/v1"]permite que ferramentas externas reconheçam o mesmo finding entre execuções. - Resiliência operacional. Scanner ausente vira
unavailablee é pulado — o scan nunca falha só porque uma ferramenta não está instalada. Timeout/OOM são distinguidos de "não instalado" via probe de versão. Caps de DoS limitam saída (QUORUM_MAX_OUTPUT_BYTES, 512 MiB) e tamanho de alvo (QUORUM_MAX_TARGET_BYTES, 20 GiB). - Honestidade sobre cobertura. "0 findings is not proof of safety" é parte do produto: o status por scanner deixa explícito se algo de fato rodou.
- Gate de CI direto. Exit code:
0= ok / nenhum finding atingiu--fail-on;1= gate disparou;2= erro de uso/runtime. - Camada consultiva opt-in.
--adviceanexa templates de remediação curados + referências OWASP (determinístico, sem modelo) e, opcionalmente, uma recomendação em linguagem natural de um provedorlocalouremote— sempre rotulada como "AI-generated, advisory only". É apenas de apresentação: nunca toca emcorrelationKey,fingerprint,confidence, severidade agregada ou o gate de fail-on. - Cadeia de suprimentos verificável. Imagens e binários assinados keyless com cosign (OIDC) + atestação SLSA build-provenance + SBOM SPDX atestada, verificáveis no release. O knowledge pack + crosswalk também recebem uma atestação SLSA build-provenance a cada release.
- Determinismo.
correlationKeyeFingerprint = sha256(correlationKey)são funções puras dos dados normalizados → relatórios reproduzíveis.
6. Diagrama de contexto¶
flowchart TB
subgraph atores["Atores e gatilhos"]
dev["Dev / Tech Lead<br/>(PR)"]
ci["Pipeline CI/CD<br/>(GitHub Action / GitLab)"]
appsec["AppSec / DevSecOps"]
auditor["Auditor de Compliance"]
end
subgraph quorum["Quorum (CLI / Docker)"]
orch["Orchestrator<br/>fan-out + timeout + probe"]
norm["Normalização<br/>model.Finding"]
alias["Alias Resolver<br/>(VULN)"]
corr["Correlator<br/>correlationKey"]
cons["Consensus<br/>detectionCount + confidence"]
adv["Camada consultiva<br/>(--advice, opt-in)"]
rep["Reporters<br/>SARIF / JSON / XML"]
end
subgraph scanners["Pool de 12 scanners OSS"]
sca["VULN<br/>trivy · grype"]
iac["MISCONFIG / IaC<br/>trivy · checkov · kics<br/>terrascan · tfsec · regula · conftest"]
img["IMG_HARDENING<br/>dockle"]
k8s["K8S_POSTURE<br/>kubescape · polaris · kube-score"]
end
subgraph ext["Serviços e dados externos"]
osv["OSV.dev<br/>(aliases, opcional)"]
cw["Crosswalk YAML<br/>aws/azure/gcp/k8s<br/>regra → controle canônico"]
pol["Rego local<br/>./policy (conftest)"]
know["Knowledge pack<br/>+ corpus OWASP<br/>(--advice)"]
llm["Provedor de advice<br/>local/remote (opt-in)"]
cache[("Cache local<br/>~/.cache/quorum")]
ghcr["GHCR<br/>imagens assinadas + SLSA + SBOM"]
end
subgraph consumidores["Consumidores do relatório"]
gh["GitHub code scanning"]
dd["DefectDojo / SIEM"]
prom["Prometheus<br/>(--metrics)"]
gate["Build gate (exit code)"]
end
dev --> ci
ci --> orch
appsec --> orch
orch --> scanners
scanners --> norm
pol --> iac
norm --> alias
alias <-->|opcional| osv
alias <--> cache
alias --> corr
cw --> corr
corr --> cons
cons --> adv
know -.->|opt-in| adv
llm -.->|opt-in| adv
adv --> rep
rep --> gh
rep --> dd
rep --> prom
rep --> gate
gate --> ci
auditor --> rep
ghcr -.distribui.-> quorum
7. Diferenciais¶
| Diferencial | O que é | Onde se vê no produto |
|---|---|---|
| Consenso + score | detectionCount e confidence (0..1) por finding; confiança pondera diversidade de engine, severidade e confirmação autoritativa |
properties.detectedBy/detectionCount/confidence no SARIF; DESIGN.md §9 |
| Consenso multi-domínio | Corroboração cruzada em VULN, MISCONFIG/IaC multi-cloud e postura K8s — não só SCA | Crosswalk aws/azure/gcp.yaml (hub AVD) e k8s.yaml (hub C-#### Kubescape) derivados de output real |
| false split > false merge | Na dúvida, não une findings; controle sem mapeamento fica isolado e unmapped |
"Regra do não-match", DESIGN.md §6 |
| Transparência de status por scanner | Todo relatório expõe ran/skipped/unavailable/error/timeout; probe de versão distingue timeout/OOM/não-instalado |
Resumo no stderr (cmd/quorum/scan.go, printSummary); "0 findings is not proof of safety" |
| Correlação determinística | correlationKey por tipo + Fingerprint = sha256(correlationKey); partialFingerprints["quorum/v1"] no SARIF |
DESIGN.md §6, §11 |
| Alias resolution com degradação graciosa | CVE/GHSA unificados via OSV.dev; falha de rede não derruba o scan; --offline desliga OSV; cache aliases.json com perm 0600 e schemaVersion |
DESIGN.md §7; cmd/quorum/scan.go |
| Camada consultiva opt-in | --advice anexa remediação + referências OWASP (determinístico, corpus DIGEST-PINNED) e advice de IA local/remoto opcional; --fix=suggest propõe um patch que deve passar por um re-scan verify-the-fix e nunca aplica sozinho |
internal/enrich, internal/rag, internal/advisor; docs/13-ia.md |
| Policy-as-code opt-in | conftest avalia o seu Rego de ./policy (ou QUORUM_CONFTEST_ARGS); sem políticas, é reportado como error — opt-in explícito |
internal/adapter/conftest.go |
| Passthrough por scanner | QUORUM_<SCANNER>_ARGS anexa argumentos ao comando (ex.: QUORUM_CHECKOV_ARGS --bc-api-key destrava políticas Prisma) |
README.md seção Scanners; inputs *-args na Action |
| Supply chain assinado e atestado | Imagens :full/:slim e binários assinados keyless (cosign/OIDC) + SLSA build-provenance + SBOM SPDX atestada; bases pinadas por sha256; scanners verificados por checksum; o knowledge pack + crosswalk carregam sua própria atestação SLSA; Action composite cosign-verifica antes de rodar |
README.md seção Install/CI/CD; release.yml, .goreleaser.yaml |
| Crosswalk plugável | YAML regra → controle canônico (AVD/CIS); bundled em /opt/quorum/crosswalk com fallback automático |
DESIGN.md §8; resolveCrosswalkDir em cmd/quorum/scan.go |
| Baseline auditável | .quorumignore por fingerprint/correlationKey; supressões sempre logadas, nunca descartadas em silêncio |
README.md seção Baseline; filter.Apply |
8. Casos de uso¶
8.1 Gate de Pull Request (consenso em CI)¶
Barrar um PR quando houver finding corroborado igual ou acima de um limiar, aceitando riscos já triados via baseline.
# GitHub Actions — via Action composite (cosign-verifica a imagem :full)
- uses: Martinez1991/quorum-sec-scan@v0 # tag móvel v0 avançada por release; pin por @<sha> em produção
with:
target: .
type: repo
fail-on: high
- [ ] Defina
--fail-on(ex.:highoucritical). - [ ] Crie/mantenha
.quorumignorepara riscos aceitos (com comentário e data). - [ ] Faça upload do SARIF para o GitHub code scanning.
- [ ] Trate exit code
1como gate e2como erro de pipeline.
8.2 Scan de imagem (SCA / vulnerabilidades)¶
Consenso de SCA sobre uma imagem de container, com aliases CVE/GHSA unificados.
- [ ] Use
trivy+grypepara corroboração de VULN. - [ ] Mantenha
--offlinese o ambiente não puder acessar a OSV.dev (usa aliases locais + cache). - [ ] Para imagem local via
:full/Action, compartilhe o socket do Docker (auto-montado emtype: imagena Action) — sem isso, o scan cai em pull e reporta falso-zero.
8.3 Infraestrutura como Código (IaC / misconfig multi-cloud)¶
Consenso de misconfig sobre Terraform (AWS/Azure/GCP), com SARIF para code scanning.
- [ ] Aproveite o consenso entre Checkov, KICS, Terrascan, tfsec, Regula e Trivy (tfsec emite AVD nativo e auto-correlaciona com Trivy).
- [ ] Garanta que o crosswalk (
crosswalk/{aws,azure,gcp}.yaml) mapeie as regras para o controle canônico (AVD). - [ ] Opcional: adicione seu Rego em
./policypara acionarconftest(policy-as-code). - [ ] Opcional: adicione
--advicepara anexar remediação + referências OWASP por finding (determinístico; nenhum dado sai do host). - [ ] Lembre-se: regra sem mapeamento fica
unmapped(não é chutada).
8.4 Postura de Kubernetes (K8s posture, multi-engine)¶
Avaliação de postura sobre manifests K8s, com consenso entre três engines.
- [ ] Use
--type k8spara acionarkubescape,polarisekube-score(crosswalkk8s.yaml, hub C-#### do Kubescape). - [ ] O crosswalk cobre privilege-escalation, privileged, non-root, limites de CPU/memória, probes, read-only-fs, linux-hardening, automount de service account, network-policy, host-network, host-PID/IPC, capabilities e secrets.
- [ ] RBAC segue single-engine (o RBAC do Kubescape exige contexto de cluster; documentado).
- [ ] Processe o JSON (findings + resumo por scanner + rollup de severidade) downstream.
8.5 Telemetria em CI (métricas Prometheus)¶
Exportar métricas do scan para observabilidade.
- [ ] Colete
quorum.promcomo textfile do node_exporter/pushgateway. - [ ] Use
--log-format jsonpara ingestão estruturada dos logs de progresso. - [ ] Sob
--advice, surgem métricas extras (quorum_advice_enriched,quorum_advice_provider,quorum_advice_fix) — incluindo a taxa verify-the-fix.
Distribuição: imagem
:full(todos os 12 scanners,linux/amd64, grype DB pré-cacheado que não expira) para CI self-contained;:slim(orquestrador apenas, amd64+arm64) quando os scanners já estão no PATH. Binários nativos via GoReleaser. Todas as imagens/binários são assinados (cosign) e atestados (SLSA + SBOM SPDX).
9. Premissas¶
- Versão. Documento alinhado à v0.8.3 (revisão 2026-07-04); flags, exit codes, scanners e comandos refletem
cmd/quorum/scan.go,cmd/quorum/root.goeinternal/adapter/lidos no momento da redação (a versão é injetada no build/release). - Escopo de produto. O Quorum é CLI/Docker only. Não há frontend web, banco de dados relacional, API REST HTTP nem autenticação/contas de usuário. Itens correspondentes em templates enterprise são tratados como N/A por decisão de arquitetura (orquestrador stateless que se integra a CI/CD, não um serviço).
- O núcleo não tem IA; a camada consultiva é opt-in. O núcleo determinístico não tem IA. Uma camada consultiva opt-in (
--advice) pode anexar remediação curada + referências OWASP (determinístico, sem modelo) e, quando explicitamente habilitada, recomendações de IA local (--advice-provider=local) ou remota (--advice-provider=remote). Ela fica desligada por padrão, é apenas de apresentação e nunca toca emcorrelationKey/fingerprint/confidence/severidade agregada/o gate de fail-on; sem--advicea saída é byte-idêntica (verdocs/13-ia.md). - Runtime security é N/A no presente. Modelo de stream (Falco/Tetragon) está fora de escopo; aparece apenas como proposta futura no roadmap do
README.md/DESIGN.md. - Consenso por domínio. VULN é compartilhado por grype + trivy; MISCONFIG/IaC por trivy + checkov + kics + terrascan + tfsec + regula (+ conftest, policy-as-code); K8S_POSTURE por kubescape + polaris + kube-score; IMG_HARDENING é dockle-only (sem par para consenso ainda). O RBAC do Kubescape segue single-engine por exigir contexto de cluster.
- Policy-as-code é opt-in. O
conftestnão tem regras embutidas: sem Rego em./policy(ou viaQUORUM_CONFTEST_ARGS), ele é reportado comoerror— comportamento esperado. - Dependência opcional de rede. A resolução de aliases via OSV.dev é opcional e degrada graciosamente;
--offlinea desabilita. O scan não depende de conectividade para concluir. Da mesma forma, os provedores de IA da camada consultiva são opcionais: se o modelo estiver inacessível, o relatório sai sem advice de IA e o scan nunca falha; oremoteexige consentimento explícito (--advice-allow-egress) e é bloqueado por--offline. - Catálogos derivados de output real. Os mapeamentos do crosswalk (AVD/CKV, UUIDs de KICS, C-#### de Kubescape) foram derivados de output real dos scanners em demos Terraform/K8s sob a regra false split > false merge, mas devem ser conferidos contra os catálogos oficiais antes de produção (conforme nota no
README.mdeDESIGN.md§8). - Cadeia de suprimentos como fronteira de confiança. Binários de scanner embutidos na imagem
:fullfazem parte do trust boundary; a release endurece isso com bases pinadas porsha256, scanners verificados por checksum, assinatura cosign, atestação SLSA build-provenance e SBOM SPDX. O knowledge pack + crosswalk carregam sua própria atestação SLSA (verifique comgh attestation verify knowledge/owasp/corpus.yaml). Para produção, recomenda-se pinar por digest e verificar assinaturas/atestações. confidence/correlationKeydeterminísticos. Os valores de confiança e as chaves de correlação são funções dos dados normalizados; mudanças de versão de scanner podem alterar a entrada e, consequentemente, a saída.- Caps de DoS. Saída por scanner é limitada por
QUORUM_MAX_OUTPUT_BYTES(512 MiB) e o tamanho do alvo em disco porQUORUM_MAX_TARGET_BYTES(20 GiB;0desabilita).