Ir para o conteúdo

Requisitos Não Funcionais

Este documento especifica os Requisitos Não Funcionais (RNF) do Quorum (quorum-sec-scan), versão v0.8.3 (revisão de 2026-07-04). O Quorum é uma ferramenta de consensus security scanning distribuída como CLI e imagem Docker — sem frontend web, sem banco de dados, sem API REST e sem autenticação de usuário. Ele orquestra um pool de 12 scanners OSS (Trivy, Grype, Checkov, KICS, Dockle, Kubescape, Polaris, kube-score, Terrascan, tfsec, Regula e Conftest), normaliza tudo para um modelo canônico (model.Finding), resolve aliases de vulnerabilidade, correlaciona findings equivalentes, calcula um score de confiança (consenso) e emite SARIF/JSON/XML.

O núcleo determinístico não tem IA. A partir da v0.8.3 existe uma camada de aconselhamento opt-in (habilitada com --advice) que é apenas de apresentação: ela nunca toca em correlationKey, Fingerprint, confidence, severidade agregada ou no gate --fail-on. Sem --advice a saída é byte-idêntica às releases anteriores, e todo anexo de IA é rotulado como "AI-generated, advisory only". Veja 13-ia.md e 21-proposta-ia.md para o enquadramento completo; o impacto dela nos RNF (determinismo, egresso, cadeia de suprimentos) é destacado ao longo do texto abaixo.

Por ser um binário/imagem de execução efêmera (não um serviço de longa duração), vários RNF clássicos de produtos SaaS não se aplicam diretamente. Onde for o caso, o requisito é declarado explicitamente como N/A com justificativa técnica, e — quando agregar valor — acompanhado de uma Proposta futura claramente separada. A natureza arquitetural do produto está descrita em 01-visao-geral.md e 04-arquitetura.md; o modelo de dados, a matriz de correlação e a matemática do consenso estão em DESIGN.md.

Convenção de criticidade dos RNF: P0 = essencial (release bloqueia se violado), P1 = importante, P2 = desejável.


1. Panorama dos RNF

mindmap
  root((RNF Quorum))
    Performance
      Fan-out paralelo 12 scanners
      Timeout por scanner
      Probe de versão 60s
      Grype DB pré-cacheado
      Caps de DoS (output/target)
    Escalabilidade
      CLI stateless
      Escala horizontal nos runners
    Disponibilidade
      N/A servico
      Distribuicao GHCR/Releases
    Seguranca
      Supply chain
      Imagens assinadas cosign
      SLSA provenance
      SBOM SPDX atestado
      Atestacao do knowledge pack
      Pin por sha256
      Sem segredos
    Observabilidade
      Logs stderr text/json
      Metricas Prometheus
      Status por scanner
    Auditoria
      Relatorio como evidencia
      Fingerprints
    Conformidade
      LGPD
      PCI DSS
      ISO 27001
      OWASP ASVS / Top 10
    Resiliencia
      Degradacao graciosa
      Retry cosign
      Grype DB nao expira
    Continuidade
      Stateless
      Artefatos reproduziveis
# Categoria Aplicabilidade Prioridade Resumo
2 Performance Aplicável P0 Paralelismo, timeouts, DB pré-cacheado, caps de DoS
3 Escalabilidade Aplicável P1 CLI stateless, escala horizontal em CI
4 Disponibilidade Reinterpretado P1 Não é serviço; vale a distribuição
5 Segurança Aplicável P0 Supply chain, assinaturas, SBOM, sem segredos
6 Observabilidade Aplicável P1 Logs stderr (text/json), métricas Prometheus, status por scanner
7 Auditoria Aplicável P1 Relatório como evidência, fingerprints
8 LGPD Aplicável (por exclusão) P1 Sem PII processada
9 PCI DSS N/A como produto P2 Pode auxiliar compliance
10 ISO 27001 Mapeamento parcial P2 Controles aplicáveis ao binário/pipeline
11 OWASP ASVS Subconjunto CLI P1 Controles relevantes a um CLI
12 OWASP Top 10 Aplicável ao próprio artefato P0 Risco do binário/imagem, não do alvo
13 Resiliência Aplicável P0 Degradação graciosa
14 Backup/DR/RTO/RPO N/A (stateless) P2 Artefatos reproduzíveis
15 SLA/SLO/SLI Definido P1 Uso em CI e pipeline de release

2. Performance

O Quorum é dominado por I/O e por subprocessos (cada scanner é um binário externo invocado via exec). O tempo de parede de um scan é, na prática, max(tempo de cada scanner) + overhead de correlação/consenso, porque os adapters rodam em paralelo. A camada de aconselhamento opt-in (--advice) roda depois do pipeline determinístico e está desligada por padrão, então nunca entra nesse caminho crítico a menos que seja explicitamente solicitada.

2.1 Paralelismo (fan-out)

O orquestrador dispara uma goroutine por adapter e agrega os resultados sob mutex (internal/orchestrator/orchestrator.go, Run). São 12 adapters registrados em internal/adapter (trivy, grype, checkov, kics, dockle, kubescape, polaris, kube-score, terrascan, tfsec, regula, conftest); apenas os que suportam o tipo de alvo entram no fan-out:

flowchart LR
  T[target] --> O[Orchestrator.Run]
  O -->|goroutine| A1[trivy.Run]
  O -->|goroutine| A2[grype.Run]
  O -->|goroutine| A3[checkov.Run]
  O -->|goroutine| A4[kics.Run]
  O -->|goroutine| A5[dockle.Run]
  O -->|goroutine| A6[kubescape.Run]
  O -->|goroutine| A7[polaris.Run]
  O -->|goroutine| A8[kube-score.Run]
  O -->|goroutine| A9[terrascan.Run]
  O -->|goroutine| A10[tfsec.Run]
  O -->|goroutine| A11[regula.Run]
  O -->|goroutine| A12[conftest.Run]
  A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 & A9 & A10 & A11 & A12 --> W[wg.Wait + mutex agrega]
  W --> C[Correlator.Enrich]
  C --> M[consensus.Merge]
  M --> R[Reporter SARIF/JSON/XML]

Implicações de performance:

  • Escalonamento por scanner mais lento, não pela soma. Adicionar um scanner rápido a um conjunto que já contém um lento não altera muito o tempo total. Com 12 scanners, o gargalo típico continua sendo os processos Python/pesados (Checkov, KICS) e não o número de adapters em si.
  • A fase de correlação/consenso é in-process e CPU-leve (agrupamento por correlationKey em mapas, sha256 por chave) — desprezível frente aos scanners.
  • A resolução de aliases pode adicionar latência de rede (OSV.dev). Mitigada por cache local (~/.cache/quorum/aliases.json) e desligável com --offline.

2.2 Timeout por scanner

Dois orçamentos de tempo distintos protegem o pipeline contra travamentos:

Parâmetro Default Onde Efeito ao estourar
--timeout (PerScannerTime) 5m cmd/quorum/scan.go, Options.PerScannerTime Scanner marcado timeout; demais continuam
ProbeTime (probe de versão) 60s orchestrator.defaultProbeTime Scanner marcado unavailable com diagnóstico

O probe de versão de 60s é deliberadamente generoso: ferramentas pesadas (ex.: Checkov, um processo Python) demoram a inicializar a frio, especialmente quando os 12 scanners sobem ao mesmo tempo num runner com pouca memória. O orquestrador distingue três falhas do probe e emite mensagem acionável:

  • timeout do probe → "tool too slow to start or resource-starved (give the container more memory, or scope --scanners)";
  • killed (OOM)signal: killed → "likely out of memory; raise the container's memory limit";
  • não instalado → "not installed/available".

Um timeout de execução nunca derruba o scan inteiro: o status do scanner vira timeout/error e o relatório registra isso explicitamente — "0 findings is not proof of safety".

2.3 Grype DB pré-cacheado

A imagem :full (Dockerfile.full) congela a base de vulnerabilidades do Grype em build time:

ENV GRYPE_DB_CACHE_DIR=/opt/grype/db \
    GRYPE_DB_AUTO_UPDATE=false \
    GRYPE_DB_VALIDATE_AGE=false
RUN grype db update && grype db status

Benefícios diretos de performance e resiliência:

  • O primeiro scan funciona offline e não falha com "failed to load vulnerability db: database does not exist".
  • Elimina o download da DB no caminho crítico de cada job de CI.
  • GRYPE_DB_VALIDATE_AGE=false é obrigatório aqui: sem isso o Grype recusaria uma DB com mais de 5 dias (db.max-allowed-built-age) e falharia todo scan poucos dias após o build. A DB baked é aceita por design (não expira); a atualização é um rebuild ou GRYPE_DB_AUTO_UPDATE=true em runtime (requer rede).
  • Trade-off documentado: a DB é congelada na data do build — a frescor é uma escolha de supply chain, não um crash.

2.4 Caps de DoS (limites de recurso)

Dois limites protegem o processo Quorum contra alvos/outputs patológicos (R2/R5), independentemente da confiabilidade do scanner:

Cap Default Env de override Comportamento ao estourar Onde
Stdout por scanner 512 MiB QUORUM_MAX_OUTPUT_BYTES (bytes) aborta o adapter com erro (evita OOM ao bufferizar) internal/adapter/adapter.go, runCmd/capWriter
Tamanho do alvo (repo/k8s) 20 GiB QUORUM_MAX_TARGET_BYTES (bytes; 0 desabilita) recusa cedo o scan com mensagem acionável cmd/quorum/scan.go, checkTargetSize
  • O cap de output usa um capWriter que corta a leitura assim que o teto é cruzado — um scanner que despeje gigabytes de JSON não derruba o processo.
  • O cap de alvo faz um filepath.WalkDir com early-abort: assim que a soma dos arquivos regulares ultrapassa o teto, a varredura para (repos normais pagam só um passo leve de stat). Alvos do tipo imagem (sem árvore local) são pulados.

2.5 Metas de performance (SLO de produto)

Metas-alvo; ainda não validadas por benchmark formal (ver Gaps).

Métrica Meta Condição Prioridade
Overhead do orquestrador (correlação+consenso+report) ≤ 2s ≤ 50k findings brutos P1
Tempo do probe de todos os scanners ≤ 60s imagem :full warm P0
Latência de alias (cache hit) ~0 (sem rede) re-scan idempotente P1
Tempo total de scan SCA (:full, imagem média) ≤ tempo do scanner mais lento + 2s runner 2 vCPU / 4 GB P1
Pico de memória do orquestrador (excluindo scanners) ≤ 256 MB ≤ 50k findings + caps de DoS ativos P2

Checklist de performance:

  • [ ] Rodar com --offline em CI quando a rede OSV não for desejada no caminho crítico.
  • [ ] Restringir --scanners ao necessário em runners pequenos (12 scanners no :full).
  • [ ] Persistir ~/.cache/quorum/aliases.json entre jobs de CI.
  • [ ] Garantir memória suficiente ao container :full (Checkov/KICS são pesados).
  • [ ] Ajustar QUORUM_MAX_OUTPUT_BYTES/QUORUM_MAX_TARGET_BYTES só se um alvo legítimo exceder os defaults.
  • [ ] Manter --advice desligado (default) no caminho crítico; a camada de aconselhamento é pós-processamento e opcional.

3. Escalabilidade

3.1 CLI stateless

Cada execução do Quorum é autocontida e sem estado compartilhado:

  • Nenhum estado é persistido entre execuções além de caches opcionais (aliases em disco e — apenas sob --advice — o cache de advice indexado por fingerprint+provider+model) que são idempotentes e reconstruíveis.
  • Não há servidor, sessão, fila ou coordenação entre processos.
  • A saída (SARIF/JSON/XML) é função determinística das entradas (alvo + scanners + crosswalk + baseline), com os correlationKey/Fingerprint puros. A camada de aconselhamento não altera isso: com --advice desligado a saída é byte-idêntica e, mesmo ligada, os campos de correlação e consenso ficam intactos.

3.2 Escala horizontal nos runners de CI

flowchart TB
  subgraph CI[Pipeline / CI fleet]
    R1[Runner 1\nquorum scan repoA]
    R2[Runner 2\nquorum scan repoB]
    R3[Runner N\nquorum scan imageX]
  end
  R1 --> S1[(SARIF/JSON\nartefato)]
  R2 --> S2[(SARIF/JSON\nartefato)]
  R3 --> S3[(SARIF/JSON\nartefato)]
  • A escala é embaraçosamente paralela: N execuções independentes em N runners, sem ponto central de contenção (exceto o registry/Releases na obtenção do artefato).
  • O gargalo de escala é o recurso do runner (CPU/memória para os 12 scanners), não o Quorum em si.
  • Dependência externa única na execução: OSV.dev para aliases — mitigável com --offline ou cache compartilhado.
Vetor de escala Mecanismo Limite
Mais repositórios/imagens mais jobs/runners paralelos capacidade da frota de CI
Mais scanners por scan fan-out de goroutines (até 12) memória do runner
Re-scans frequentes cache de aliases tamanho do cache (negligível)

N/A: escalabilidade vertical de um serviço (auto-scaling de pods, sharding de banco, balanceamento de carga) — não há serviço de longa duração. Ver §4.


4. Disponibilidade

N/A como serviço. O Quorum não expõe endpoint, daemon ou processo de longa duração; portanto não há uptime de serviço a medir. O conceito é reinterpretado como disponibilidade da distribuição — a capacidade de obter e executar o artefato.

flowchart LR
  Dev[Desenvolvedor / CI] -->|docker pull| GHCR[(GHCR\nghcr.io)]
  Dev -->|download| REL[(GitHub Releases\nGoReleaser)]
  Dev -->|api.osv.dev| OSV[(OSV.dev\nopcional)]
  GHCR --> Run[quorum scan ...]
  REL --> Run
  OSV -. degradação graciosa .-> Run
Dependência Papel Disponibilidade Mitigação
GHCR (ghcr.io) distribuição das imagens :full/:slim SLA do GitHub pin por @sha256, mirror interno, cache de runner
GitHub Releases binários nativos + checksums + assinaturas SLA do GitHub mirror interno, cópia versionada
OSV.dev resolução de aliases (apenas VULN) best-effort --offline, cache local, degradação graciosa
Binários dos scanners execução real local (imagem :full, 12 scanners) ou PATH (:slim) :full já embute tudo

Metas de disponibilidade de distribuição:

  • [ ] Imagens publicadas de forma reprodutível a cada tag semver (release.yml).
  • [ ] Possível operar 100% offline com :full (DB do Grype pré-cacheada + crosswalk embutido + --offline).
  • [ ] Recomendação enterprise: espelhar as imagens em registry interno e pinar por digest.

Proposta futura (claramente separada): não há plano de transformar o Quorum em serviço hospedado; caso surja, esta seção passaria a definir uptime/SLA de serviço real.


5. Segurança

A superfície de segurança do Quorum tem duas frentes: (a) segurança do próprio artefato e da sua cadeia de suprimentos, e (b) higiene de execução (não manusear segredos). O alvo escaneado é dado de entrada — o Quorum só o lê.

5.1 Cadeia de suprimentos (supply chain)

flowchart LR
  src[Código fonte\nGo 1.26] --> rel[release.yml]
  rel --> img[Imagens :full / :slim]
  rel --> bin[Binários GoReleaser]
  rel --> kn[Knowledge pack + crosswalk]
  img --> cosign[cosign sign --yes\nkeyless OIDC + retry]
  bin --> cblob[cosign verify-blob\nchecksums.txt.sig]
  img --> slsa1[attest-build-provenance\nSLSA v1]
  img --> sbom1[attest-sbom\nSPDX atestado]
  bin --> slsa2[attest-build-provenance\nsubject-checksums]
  bin --> sbom2[GoReleaser + syft\nSBOM por binário]
  kn --> slsa3[attest-build-provenance\nknowledge.sha256]
  cosign --> ver[Verify no release + retry]
  slsa1 --> ver
  sbom1 --> ver
  slsa2 --> ver
  slsa3 --> ver
Controle Implementação Evidência
Assinatura keyless de imagem cosign sign via OIDC do GitHub (sem chaves), com retry (4 tentativas) release.yml (step "Sign image")
Atestação SLSA build-provenance actions/attest-build-provenance@v2 (imagem por digest e binários por subject-checksums) release.yml
SBOM SPDX atestado actions/attest-sbom@v2 para a imagem (syft SPDX-JSON) além do BuildKit sbom: true; GoReleaser+syft por binário release.yml, .goreleaser.yaml
Atestação do knowledge pack + crosswalk actions/attest-build-provenance@v2 sobre knowledge.sha256 (todo arquivo do pack de aconselhamento + crosswalk); verificada no mesmo release release.yml (job knowledge)
Verificação no próprio release gh attestation verify oci://…@DIGEST (com retry) falha o build se inválida release.yml (step "Verify provenance")
Assinatura de binários checksums.txt + cosign verify-blob (.sig/.pem) README §Native binary
Pin de scanners por digest FROM …@sha256: (Trivy, KICS, golang, alpine); Kubescape/tfsec/Terrascan/Regula/Conftest verificados por checksum SHA256 Dockerfile.full
Bases pinadas por @sha256 imagens de build/runtime (golang:1.26-alpine, alpine:3.20) pinadas por digest Dockerfile.full
GitHub Action verifica antes de rodar action.yml (composite) faz cosign-verify da :full por padrão (verify: true) action.yml
Trigger de release restrito tags semver v[0-9]+.[0-9]+.[0-9]+ apenas release.yml
Tag móvel v0/v0.x para pin do action avançada automaticamente a cada release semver; não dispara release tag-major.yml, README §CI/CD
THIRD_PARTY_NOTICES.md inventário de licenças de dependências/scanners repositório

Verificação esperada do consumidor (recomendado em produção):

cosign verify ghcr.io/martinez1991/quorum-sec-scan:full \
  --certificate-identity-regexp \
    "https://github.com/Martinez1991/quorum-sec-scan/.github/workflows/release.yml@.*" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

gh attestation verify oci://ghcr.io/martinez1991/quorum-sec-scan:full \
  --repo Martinez1991/quorum-sec-scan

# Knowledge pack de aconselhamento (corpus OWASP pinado por digest + templates de remediação):
gh attestation verify knowledge/owasp/corpus.yaml \
  --repo Martinez1991/quorum-sec-scan

Nota de risco honesta: o Dockerfile.full pina Trivy, KICS e as bases (golang/alpine) por @sha256, e verifica os demais scanners (Grype/Syft/Dockle/Kubescape/Polaris/kube-score/tfsec/Terrascan/Regula/Conftest) por checksum SHA256 dos artefatos oficiais de release. Converter todos para digest imutável de imagem é uma melhoria incremental (DESIGN §12). Ver Gaps.

5.2 Ausência de segredos

Aspecto Estado Justificativa
Credenciais de usuário inexistentes sem contas/autenticação
Tokens de API próprios inexistentes OSV.dev é endpoint público sem chave
Passthrough de credencial de scanner opt-in via QUORUM_<SCANNER>_ARGS (ex.: QUORUM_CHECKOV_ARGS --bc-api-key …) fornecido pelo operador, nunca ecoado nos logs (action.yml)
Chave do provedor de aconselhamento apenas com --advice-provider=remote, via QUORUM_ADVICE_API_KEY (opt-in) encaminhada como env pelo action.yml; o remoto exige --advice-allow-egress, é bloqueado por --offline e recusa --fix (enviaria código-fonte)
Segredos em build/release apenas GITHUB_TOKEN efêmero do runner escopo mínimo (contents, packages, id-token, attestations)
Persistência de segredos nenhuma nada é gravado além do cache de aliases (públicos) e do cache opt-in de advice (findings normalizados + texto de advice, sem código-fonte)
Detecção de segredos no alvo via adapter trivy (TypeSecret) findings reportados, com o Match do Trivy redigido (redactSecretText), nunca persistidos fora do relatório

Princípios de execução segura:

  • [ ] O Quorum não solicita nem armazena credenciais.
  • [ ] Logs vão para stderr e não devem conter segredos (o conteúdo de segredos detectados é redigido antes de sair no relatório).
  • [ ] Permissões do workflow de release seguem least privilege.
  • [ ] Imagens devem ser verificadas antes do uso (cosign + provenance + SBOM).
  • [ ] O relatório é gravado com permissão restrita 0600 e o caminho é normalizado com filepath.Clean (emit, scan.go).
  • [ ] O provedor de aconselhamento remoto envia apenas o finding normalizado, nunca código-fonte; está desligado por padrão e exige consentimento explícito de egresso.

5.3 Modelo de ameaças resumido

Ameaça Vetor Mitigação
Imagem adulterada registry comprometido / tag mutável assinatura cosign + SLSA + SBOM atestado + pin por digest
Binário de scanner trojanizado upstream comprometido pin por digest/checksum no build
Falso negativo silencioso scanner não roda mas reporta 0 status por scanner explícito (§6)
Bind mount malformado -v errado escaneia /work vazio; imagem local invisível aviso na doc; action.yml auto-monta docker.sock em type: image
Argument injection alvo iniciando com - interpretado como flag do scanner validateTargetRef recusa alvos que começam com -
DoS por output/alvo gigante scanner despeja GBs / árvore patológica caps QUORUM_MAX_OUTPUT_BYTES (512 MiB) e QUORUM_MAX_TARGET_BYTES (20 GiB) (§2.4)
Exfiltração de dados do alvo rede em runtime --offline; única chamada externa é OSV (somente IDs de vuln). O provedor de aconselhamento remoto está desligado por padrão, exige --advice-allow-egress e é bloqueado por --offline

6. Observabilidade

Sendo um CLI efêmero, a observabilidade é local ao processo: logs para humanos ou máquinas em stderr, status de máquina no próprio relatório e, agora, métricas exportáveis para um coletor Prometheus.

6.1 Logs (stderr) — texto ou JSON

  • Toda a telemetria de progresso vai para stderr (scan.go, logf), deixando stdout limpo para o relatório quando não há --output.
  • A flag --log-format text|json (default text) escolhe o formato:
  • text: linhas legíveis com prefixo [quorum];
  • json: um objeto por linha com {ts, level, msg} (RFC3339 UTC), pronto para ingestão por um coletor de logs estruturados.
  • --quiet/-q suprime os logs de progresso e o sumário.
  • Eventos logados: alvo/tipo/contagem de regras do crosswalk, início/fim por scanner com duração, supressões de baseline/min-severity, escrita de métricas e o disparo do gate.
[quorum] target=. type=repo crosswalk=142 rules (./crosswalk) offline=false
[quorum] run  trivy (0.71.2) ...
[quorum] done trivy: 17 findings in 4.2s
[quorum] skip grype: does not support target repo
[quorum] filtered: 3 suppressed by baseline (5 entries), 2 below min-severity medium
[quorum] metrics written to quorum.prom
[quorum] gate: found HIGH finding >= --fail-on high → exit 1

O mesmo evento em --log-format json:

{"ts":"2026-07-04T12:00:00Z","level":"info","msg":"done trivy: 17 findings in 4.2s"}

6.2 Métricas Prometheus (--metrics)

A flag --metrics <arquivo> grava as métricas do scan em formato texto Prometheus (internal/report/metrics.go, WriteMetrics), adequado a um textfile collector do node_exporter ou a um Pushgateway — a forma canônica de expor telemetria de um CLI sem processo de longa duração. O arquivo é gravado com permissão 0644 (contagens não sensíveis, feitas para scraping).

Métricas emitidas:

Métrica Tipo Labels Significado
quorum_scan_duration_seconds gauge tempo total de parede do scan
quorum_scanner_up gauge scanner, status 1 se rodou, 0 caso contrário
quorum_scanner_findings gauge scanner findings brutos por scanner (pré-consenso)
quorum_scanner_duration_seconds gauge scanner duração por scanner
quorum_findings_after_consensus gauge findings após o merge de consenso
quorum_findings_total gauge severity findings de consenso por severidade
quorum_multi_detected gauge findings corroborados por mais de um scanner

Métricas de aconselhamento (emitidas apenas sob --advice, descrevendo só a camada de aconselhamento — nunca alteram as métricas de consenso acima):

Métrica Tipo Labels Significado
quorum_advice_enriched gauge kind (remediation|references|recommendation) findings enriquecidos por cada fase de aconselhamento
quorum_advice_provider gauge provider provedor de aconselhamento em uso (none|local|remote)
quorum_advice_fix gauge stage (proposed|verified) taxa de verify-the-fix (verified/proposed)

6.3 Status por scanner

Cada execução produz um ScannerRun (orchestrator.go) com status de máquina, exposto no sumário (stderr), no relatório e nas métricas (quorum_scanner_up):

Status Significado
ran rodou e produziu resultados (mesmo que 0)
skipped scanner não suporta o tipo de alvo
unavailable binário ausente / probe falhou (timeout/OOM/não instalado)
error erro de execução do scanner
timeout execução excedeu --timeout

O sumário ao final imprime status, contagem por severidade, findings multi-detectados e a frase âncora "0 findings is not proof of safety — see scanner statuses above." Isso transforma o status em sinal observável, não em ruído.

6.4 Estado e propostas

Capacidade Estado Observação
Logs em stderr ✅ Implementado prefixados, com --quiet
Log estruturado JSON em stderr ✅ Implementado --log-format json ({ts,level,msg})
Status por scanner ✅ Implementado no sumário, no relatório e nas métricas
Duração por scanner ✅ Implementado ScannerRun.Duration
Métricas Prometheus (textfile/Pushgateway) ✅ Implementado --metrics <arquivo>
Métricas de aconselhamento ✅ Implementado apenas sob --advice (quorum_advice_*)
Traços OpenTelemetry ⚠️ Proposta futura sem processo de longa duração; não priorizado

7. Auditoria

O relatório é a evidência de auditoria. Ele é reproduzível, carimba quem detectou o quê e fornece identidade estável por finding.

Artefato de auditoria Conteúdo Onde
Status por scanner ran/skipped/unavailable/error/timeout + versão + duração Result.Runs, relatório, métricas
Procedência da detecção detectedBy[], detectionCount, confidence MergedFinding, SARIF properties
Identidade estável Fingerprint = sha256(correlationKey) SARIF partialFingerprints["quorum/v1"], JSON fingerprint
Supressões sempre logadas e contabilizadas, nunca descartadas em silêncio baseline .quorumignore, filter.Apply
Versão dos scanners ScannerVersion por finding / ScannerRun.Version relatório
Métricas do scan contagens/durações em formato Prometheus arquivo de --metrics

Propriedades de auditoria:

  • Reprodutibilidade: mesma entrada → mesmo correlationKey/Fingerprint (função pura). Permite diff temporal de relatórios. Os anexos de aconselhamento opt-in (Remediation/References/Advice) são aditivos e claramente rotulados como "AI-generated, advisory only"; não alteram a identidade.
  • Rastreabilidade de supressão: um finding suprimido pelo baseline é reportado como suprimido (com a entrada que o suprimiu), não some.
  • Cadeia de custódia do artefato: SARIF/JSON pode ser arquivado como evidência de gate de CI; assinaturas/provenance/SBOM (§5) atestam a origem do binário que o gerou.

Checklist de auditoria em CI:

  • [ ] Arquivar o relatório (SARIF/JSON) como artefato do job.
  • [ ] Arquivar o arquivo de --metrics junto ao relatório (telemetria histórica).
  • [ ] Versionar o .quorumignore (cada supressão revisada e datada).
  • [ ] Reter a saída do sumário (status por scanner) junto ao artefato.
  • [ ] Registrar a versão/digest da imagem Quorum usada.

8. LGPD (Lei Geral de Proteção de Dados)

Aplicável por exclusão — o Quorum não trata dados pessoais. A justificativa é técnica: os dados processados são metadados de software e infraestrutura, não dados de pessoas naturais.

Categoria de dado Processado? Natureza
Identificadores de vulnerabilidade (CVE/GHSA/AVD) Sim dado técnico público
PURLs / versões de pacote Sim dado técnico
Caminhos de arquivo, recursos IaC/K8s Sim dado técnico do alvo
Conteúdo de segredos detectados (Trivy) Possível não é PII por definição; redigido e fica só no relatório do usuário
Dados pessoais (nome, CPF, e-mail, etc.) Não fora do escopo funcional

Consequências:

  • Sem PII ⇒ sem necessidade de base legal, consentimento, DPO ou DPIA atribuíveis ao Quorum como controlador/operador.
  • A única chamada externa (OSV.dev) envia somente IDs de vulnerabilidade (ex.: CVE-2021-…) — não há dado pessoal no tráfego. Desligável com --offline.
  • Responsabilidade do usuário: se o alvo escaneado contiver PII (ex.: um segredo que seja um e-mail), o relatório gerado pode contê-la mesmo com a redação de segredos. O tratamento e a retenção desse relatório são responsabilidade de quem opera o Quorum, não do produto.
  • O provedor de aconselhamento remoto (opt-in) envia apenas o finding normalizado, não código-fonte; está desligado por padrão, exige consentimento explícito de egresso e é bloqueado por --offline.

N/A: direitos do titular, portabilidade, anonimização interna — não há base de dados pessoais sob controle do Quorum.


9. PCI DSS

N/A como produto. O Quorum não armazena, processa ou transmite dados de cartão (CHD/SAD) e não faz parte de um Cardholder Data Environment (CDE) por construção. Logo, não está no escopo do PCI DSS como sistema.

Entretanto, o Quorum pode auxiliar a conformidade de quem opera um CDE, como ferramenta de apoio aos requisitos abaixo:

Requisito PCI DSS v4.0 Como o Quorum auxilia
6.2 / 6.3 — desenvolver software seguro e gerir vulnerabilidades consenso de SCA (Trivy+Grype) com confidence para priorização
6.3.1 — identificar vulnerabilidades por fontes reconhecidas IDs CVE via OSV; confirmação autoritativa pesa no score
6.3.2 — inventário de componentes (bespoke/3rd-party) PURLs por finding; SBOM SPDX atestado da imagem :full
6.4 / 6.5 — proteger aplicações e gerir mudanças gate em CI por --fail-on; baseline auditável; policy-as-code (Conftest)
11.3 — varreduras de vulnerabilidade varredura automatizável em pipeline, evidência em SARIF

O Quorum não substitui um ASV scan externo nem um pentest. É um controle compensatório/preventivo no SDLC, não uma atestação de conformidade.


10. ISO/IEC 27001 (Anexo A)

Mapeamento dos controles aplicáveis ao Quorum (como ferramenta e como cadeia de build). Controles organizacionais amplos ficam a cargo de quem adota.

Controle (ISO 27001:2022) Aplicabilidade Como o Quorum endereça
A.8.8 — Gestão de vulnerabilidades técnicas ✅ Direta núcleo do produto: detecção + consenso + gate
A.8.25 — Ciclo de vida de desenvolvimento seguro ✅ Apoia integra-se ao SDLC via CI
A.8.28 — Codificação segura ✅ Apoia findings IaC/MISCONFIG/SECRET/policy-as-code acionáveis
A.8.29 — Testes de segurança em dev/aceite ✅ Apoia gate por exit code
A.8.30 — Desenvolvimento terceirizado ⚙️ Parcial scan de componentes 3rd-party (SCA)
A.8.31 — Separação de ambientes ➖ Do adotante execução isolada por job efêmero
A.8.15 — Logging ⚙️ Parcial logs stderr (text/json) + status por scanner + métricas
A.8.16 — Monitoramento ⚙️ Parcial métricas Prometheus (--metrics)
A.5.23 — Segurança em serviços cloud ➖ Do adotante N/A (sem serviço cloud próprio)
A.5.7 — Threat intelligence ⚙️ Parcial OSV/CVE como fonte de vulnerabilidade
Cadeia de suprimentos (A.5.19–A.5.23) ✅ Própria cosign + SLSA provenance + SBOM atestado + atestação do knowledge pack + pin por sha256/checksum (§5)

Legenda: ✅ atende/apoia diretamente · ⚙️ parcial · ➖ responsabilidade do adotante.


11. OWASP ASVS (controles relevantes a um CLI)

A maioria dos capítulos do ASVS pressupõe uma aplicação web com sessão e autenticação — N/A aqui. Restam os controles aplicáveis a um binário/CLI:

Domínio ASVS Aplicabilidade Estado no Quorum
V1 Arquitetura & threat modeling DESIGN.md + §5.3 deste doc
V5 Validação de entrada parsing de flags (cobra); validateTargetRef recusa -…; parsers de adapter com contract tests
V7 Tratamento de erros & logging erros acionáveis, logs em stderr (text/json), redação de segredos
V10 Código malicioso / integridade assinatura, provenance, SBOM, pin de dependências
V12 Arquivos & recursos ⚙️ lê alvo/crosswalk/baseline; relatório escrito com 0600 e filepath.Clean; caps de DoS de output/alvo
V14 Configuração defaults seguros (--offline opcional, crosswalk com fallback, aconselhamento desligado por padrão)
V2 Autenticação ➖ N/A sem autenticação
V3 Sessão ➖ N/A sem sessão
V4 Controle de acesso ➖ N/A sem multiusuário
V6 Criptografia armazenada ➖ N/A não armazena dado sensível
V8/V9 Dados/Comunicação ⚙️ OSV via HTTPS; aconselhamento remoto (opt-in) via HTTPS com consentimento explícito de egresso; sem dado sensível em trânsito
V13 APIs ➖ N/A não expõe API

Checklist ASVS prática:

  • [ ] Validar formato/severidade das flags e falhar com exit code 2 em uso inválido.
  • [ ] Garantir que parsers de adapter tenham fixture/contract test versionado (cobertura no CI).
  • [ ] Não emitir conteúdo de segredo em logs de progresso (redação ativa).
  • [ ] Verificar integridade do binário/imagem antes de executar.

12. OWASP Top 10 (do próprio binário/imagem)

Escopo: riscos do artefato Quorum em si, não do alvo que ele escaneia (esse é o trabalho dos scanners). Mapeamento ao OWASP Top 10:2021.

Risco Relevância p/ o Quorum Controle
A01 Broken Access Control Baixa sem controle de acesso (CLI local)
A02 Cryptographic Failures Baixa não guarda segredos; assinaturas via Sigstore; relatório 0600
A03 Injection Média invoca scanners via exec (args, não shell); validateTargetRef bloqueia argument injection por -
A04 Insecure Design Média princípio "false split > false merge"; threat model em DESIGN
A05 Security Misconfiguration Média defaults seguros; auto-mount de docker.sock em type: image; crosswalk com fallback
A06 Vulnerable & Outdated Components Alta deps Go + 12 binários de scanner pinados; SBOM SPDX; o próprio Quorum deve ser escaneado
A07 Identification & Auth Failures N/A sem autenticação
A08 Software & Data Integrity Failures Alta cosign (com retry) + SLSA provenance + SBOM atestado + atestação do knowledge pack + pin por digest/checksum
A09 Logging & Monitoring Failures Média status por scanner + métricas evitam falso negativo silencioso
A10 SSRF Baixa única saída de rede é OSV.dev (host fixo); --offline desliga. O endpoint remoto de aconselhamento (opt-in) é configurado pelo usuário e gated por consentimento explícito de egresso

Ações priorizadas:

  • [ ] A06/A08: rebuild periódico para refrescar DB do Grype e bumps de versão de scanner.
  • [ ] A08: converter os checksums restantes para @sha256 de imagem no Dockerfile.full.
  • [ ] A03: manter invocação de scanners por args (sem shell), revisada em code review.

Nota sobre a camada de aconselhamento por IA: o OWASP LLM Top 10 só se aplica quando a camada de IA está habilitada (--advice-provider=local|remote). O núcleo determinístico não tem IA; ver 13-ia.md.


13. Resiliência (degradação graciosa)

A resiliência é um princípio de design central: uma falha parcial degrada, não derruba, e a degradação é sempre visível.

flowchart TD
  A[Scanner ausente] --> A1[status unavailable\nscan continua]
  B[Probe lento / OOM] --> B1[status unavailable\nmensagem acionável]
  C[Scanner estoura --timeout] --> C1[status timeout\ndemais continuam]
  D[OSV.dev indisponível] --> D1[usa id original\ncache local; sem falhar]
  E[Crosswalk ausente] --> E1[fallback /opt/quorum/crosswalk\nou finding unmapped]
  F[Controle não mapeado] --> F1[finding isolado\nflag unmapped]
  G[Output/alvo gigante] --> G1[cap de DoS aborta\ncom mensagem acionável]
  H[cosign/OIDC instável no release] --> H1[retry 4x\ncom backoff]
  I[Modelo de advice inacessível] --> I1[relatório sai sem advice de IA\nscan nunca falha]
Falha Comportamento Fonte
Scanner não instalado unavailable, scan prossegue orchestrator.runOne
Probe lento / OOM unavailable com diagnóstico (memória/scope) orchestrator.runOne
Timeout de execução timeout, outros scanners continuam orchestrator + --timeout
Rede OSV indisponível aliases degradam para id original; nunca falha o scan alias/DESIGN §7
:full sem rede DB do Grype pré-cacheada + crosswalk embutido Dockerfile.full
DB do Grype envelhecida GRYPE_DB_VALIDATE_AGE=false — DB não expira, scan não trava Dockerfile.full
Output de scanner gigante abortado no cap de 512 MiB (QUORUM_MAX_OUTPUT_BYTES) adapter.runCmd
Alvo repo/k8s gigante recusado no cap de 20 GiB (QUORUM_MAX_TARGET_BYTES) scan.checkTargetSize
Crosswalk default ausente fallback automático para /opt/quorum/crosswalk resolveCrosswalkDir
Controle não mapeável finding fica isolado, flag unmapped (não chuta merge) DESIGN §6
Assinatura/verificação instável no release retry (4 tentativas, backoff crescente) no cosign e no gh attestation verify release.yml
Modelo/endpoint de advice inacessível degradação graciosa: relatório sai sem advice de IA, scan nunca falha internal/advisor

Invariante de resiliência: "0 findings is not proof of safety" — toda degradação aparece como status, evitando que uma falha vire um falso "tudo certo".


14. Backup, DR, RTO e RPO

N/A — o Quorum é stateless. Não há dado de produção sob sua custódia que possa ser perdido. A continuidade depende de artefatos reproduzíveis, não de backup/restore.

Conceito Aplicabilidade Justificativa
Backup de dados N/A sem armazenamento persistente de estado de negócio
Disaster Recovery (DR) N/A (serviço) não há serviço para recuperar
RTO ~minutos, reinterpretado "recuperar" = re-executar o scan em outro runner
RPO 0, reinterpretado nada a perder; cada scan é recomputável da fonte

O que substitui backup/DR:

  • Reprodutibilidade: imagens pinadas por digest + binários assinados + provenance + SBOM atestado permitem reconstruir/obter exatamente o mesmo artefato.
  • Mirror de distribuição: espelhar imagens/binários em registry interno protege contra indisponibilidade do GHCR/Releases.
  • Cache de aliases: descartável; reconstruído a partir do OSV/scanner. Gravado com permissão 0600 e schemaVersion para invalidação segura. (O cache opt-in de advice é igualmente descartável e reconstruível, indexado por fingerprint+provider+model.)

Único item recuperável de fato: o relatório arquivado como evidência (§7) — sua retenção/backup é responsabilidade do pipeline que o gera, não do Quorum.

Proposta futura (separada): se um modo com cache persistente compartilhado for adotado em larga escala, definir política de backup/retenção desse cache.


15. SLA / SLO / SLI

Não há SLA contratual de serviço (não é serviço). Definimos SLO/SLI para dois contextos operacionais reais: uso em CI e pipeline de release.

15.1 Uso em CI (o binário/imagem como dependência do pipeline)

SLI Definição SLO alvo Como medir
Confiabilidade do scan % de jobs que terminam com exit 0/1 (sem 2) ≥ 99% exit codes do job
Determinismo % de re-scans da mesma entrada com mesmo fingerprint set 100% diff de relatórios
Latência de overhead overhead do orquestrador (sem scanners) ≤ 2s p95 sumário/Duration/métricas
Resiliência a falha de rede scans concluídos com OSV indisponível 100% (degrada) execução --offline
Cobertura de execução % de scanners suportados com status ran ≥ 95% em :full status por scanner / quorum_scanner_up
Neutralidade do aconselhamento % de scans em que --advice mantém a saída do núcleo (fingerprints/consenso) inalterada 100% byte-diff com/sem --advice

15.2 Pipeline de release (publicação do artefato)

SLI Definição SLO alvo Como medir
Sucesso de publicação % de tags semver que publicam imagens+binários 100% release.yml
Integridade verificada % de releases com cosign+provenance+SBOM+knowledge pack verificados no próprio build 100% steps "Verify provenance" / attest-sbom / job knowledge
Reprodutibilidade do build build determinístico (-trimpath, deps pinadas, bases por sha256) 100% Dockerfile.full/GoReleaser
Cobertura de testes testes com -race -covermode=atomic a cada push/PR verde bloqueante ci.yml (step "Test (race + coverage)")
Cobertura de evals do aconselhamento cobertura de remediação, relevância de referências OWASP e taxa de verify-the-fix medidas em CI acompanhada (sem modelo pesado) harness internal/evals
Tempo de release tag → imagens+binários publicados ≤ 30 min duração do workflow

Distinção importante de SLA do produto vs. integridade: a disponibilidade de publicação depende do GitHub/GHCR (não controlado por nós), mas a integridade (assinatura + provenance + SBOM + knowledge pack verificados) é bloqueante no próprio release — um artefato com atestação quebrada falha o build. Instabilidade transitória do Sigstore/OIDC é absorvida por retry (§13), não por relaxamento da verificação.


Premissas

  • Os números/metas em §2.5 e §15 são alvos de engenharia, ainda não validados por benchmark formal neste repositório.
  • Assume-se que o consumidor em produção verifica imagem/binário (cosign + gh attestation verify) e, idealmente, pina por digest — o produto fornece os meios (assinatura, provenance, SBOM atestado, atestação do knowledge pack), a aplicação é do adotante.
  • O --offline é o modo recomendado quando a política de CI proíbe egressos de rede; com isso a única dependência externa em runtime (OSV.dev) é eliminada e o provedor de aconselhamento remoto é totalmente bloqueado.
  • "Sem PII" pressupõe que o produto não é configurado para tratar dados pessoais; PII eventualmente presente no alvo é responsabilidade do operador do relatório (mesmo com a redação de segredos aplicada).
  • A camada de aconselhamento (--advice) é opt-in e desligada por padrão; quando desligada, a saída é byte-idêntica e o determinismo é preservado. Apenas o provedor remoto faz dados saírem do host, e somente sob consentimento explícito (--advice-allow-egress), enviando o finding normalizado, nunca código-fonte.
  • Mapeamentos de PCI DSS, ISO 27001, ASVS e OWASP Top 10 são interpretativos, baseados no comportamento as-is do código (v0.8.3), e não constituem atestação de conformidade.
  • A disponibilidade da distribuição depende de serviços de terceiros (GitHub GHCR/Releases, OSV.dev), cujos SLAs não são controlados por este projeto.
  • A imagem :full é linux/amd64 (os 12 scanners embutidos são amd64); cenários arm64 usam :slim (amd64+arm64) com scanners no PATH, o que altera o perfil de performance/disponibilidade local.
  • Os defaults dos caps de DoS (512 MiB de output por scanner, 20 GiB de alvo) são dimensionados muito acima de qualquer caso real; alvos legítimos que os excedam exigem override explícito por env.

Lacunas conhecidas (gaps)

  • Não há benchmark de performance versionado para sustentar os SLOs alvo.
  • Nem todos os scanners no Dockerfile.full estão pinados por digest imutável de imagem (Trivy/KICS/bases sim; os demais por versão+checksum SHA256); endurecer todos para @sha256 é uma melhoria incremental recomendada.
  • A observabilidade cobre logs (text/json), status por scanner e métricas Prometheus (--metrics, mais as métricas opt-in quorum_advice_*); traços OpenTelemetry permanecem proposta futura.
  • Não há mecanismo nativo de mirror/retenção de artefatos; é responsabilidade do adotante.