Overview¶
Quorum (quorum-sec-scan, v0.8.3) is a CLI/Docker consensus security scanning tool: it orchestrates a pool of 12 open-source security scanners (Trivy, Grype, Checkov, KICS, Terrascan, tfsec, Regula, Conftest, Dockle, Kubescape, Polaris, kube-score) over a target, normalizes every finding into a canonical model, resolves vulnerability aliases, correlates equivalent findings across tools, and emits a single report that tells you how many and which scanners detected each problem — plus a confidence score derived from that consensus. Quorum is not yet another scanner: it is the lightweight correlation + consensus layer on top of the tools you already trust, designed to run inside a CI/CD pipeline and block a build via exit code. An opt-in advisory layer (--advice) can additionally attach curated remediation, OWASP references, and — when explicitly enabled — AI recommendations; it is presentation-only and never alters the deterministic core. This document describes the goal, the problem solved, the target audience, personas, benefits, differentiators, and use cases.
Code references verified for this document:
README.md,DESIGN.md,cmd/quorum/root.go,cmd/quorum/scan.go,internal/adapter/,crosswalk/.
1. System goal¶
Quorum's goal is to turn multiple incompatible scanner reports into a single consolidated, prioritizable report, in which each finding carries consensus evidence (how many and which engines detected it) and a computed confidence score, in a deterministic and CI/CD-actionable way.
Operationally, Quorum delivers:
- Orchestration — runs the supported scanners against the target in parallel, with a per-scanner timeout.
- Normalization — converts each tool's output into a canonical
model.Finding(a single severity scale, PURLs for packages, AVD/CIS/category for controls). - Alias resolution — unifies
CVE-…andGHSA-…of the same bug (only forVULN) via local aliases → local cache → OSV.dev (CVE preferred). - Correlation — groups equivalent findings by a deterministic, type-specific
correlationKey. - Consensus — computes
detectionCountandconfidence(0..1) for each group. - Report — emits SARIF (primary), JSON, or XML, always with the per-scanner status.
Pipeline per DESIGN.md §3 and the stage-by-stage description in README.md.
2. Problem solved¶
Different scanners find overlapping but not identical problems and report them in incompatible formats. Whoever runs three tools gets three reports, duplicated findings, and no signal about which findings are corroborated. This leads to concrete pains:
| Pain without Quorum | How Quorum solves it |
|---|---|
| N scanners → N reports in distinct formats | Single canonical model (model.Finding) + one consolidated report |
| Duplicated findings (the same CVE in Trivy and Grype) | Correlation by deterministic correlationKey + dedup |
GHSA-… (Grype) and CVE-… (Trivy) treated as different bugs |
Alias Resolver unifies to the canonical form (CVE preferred) |
| Identical IaC misconfig in Checkov/KICS/Terrascan/tfsec/Regula with no convergence signal | Crosswalk rule → canonical control (AVD hub) correlates across engines |
| K8s posture repeated in Kubescape/Polaris/kube-score with no consolidation | Crosswalk k8s.yaml (Kubescape C-#### hub) correlates the three engines |
| No corroboration signal across tools | detectionCount + detectedBy + confidence per finding |
| "0 findings" read as "it's safe" | Explicit per-scanner status (ran/skipped/unavailable/error/timeout) |
| Manual temporal dedup across CI runs | partialFingerprints["quorum/v1"] = sha256(correlationKey) in SARIF |
| Scanner images/binaries as a supply chain vector | Keyless signed distribution (cosign) + SLSA build-provenance attestation + attested SPDX SBOM |
Guiding principle: false split > false merge. When in doubt, Quorum keeps findings separate and marks them unmapped — a wrong merge hides risk. (See DESIGN.md §6, "No-match rule".)
What the problem is NOT (scope)¶
Quorum does not aim to be:
- a new scanner (it reuses existing OSS scanners);
- a runtime security solution (stream model, out of scope — a future proposal on the roadmap);
- a platform with a web dashboard, daemon, or persistent service.
The advisory layer does not change this scope: it is opt-in, presentation-only, and off by default. Without --advice, output is byte-identical, the deterministic core has no AI, and any AI recommendation is strictly opt-in (see §7 Differentiators and §9 Assumptions).
3. Target audience¶
Quorum is aimed at teams that already operate OSS scanners and need to consolidate and prioritize results within automated pipelines:
- AppSec / DevSecOps teams that maintain security gates in CI/CD.
- Platform / developer-productivity teams that standardize security tooling across repositories.
- Cloud/IaC engineers who validate Terraform and K8s manifests across clouds (AWS/Azure/GCP) before apply.
- Tech Leads / maintainers who need a reliable signal (consensus) to decide what blocks a merge.
- Compliance auditors who need traceable evidence (AVD/CIS canonical controls, per-scanner status, stable fingerprints).
Quorum is CLI/Docker only: there is no web frontend, relational database, or HTTP REST API. The deterministic core has no AI/LLM; an opt-in advisory layer (local or remote) can be enabled but is off by default (see §7 Differentiators and §9 Assumptions). The audience is therefore technical and automation-centric.
4. Personas¶
| Persona | Main goal | How they use Quorum | Success metric |
|---|---|---|---|
| AppSec / DevSecOps Engineer | Cut noise and prioritize what's real | Configures --fail-on, --min-severity, .quorumignore; analyzes confidence and detectionCount; optionally --advice for remediation |
Fewer false positives at the gate; corroborated findings prioritized |
| Tech Lead / Maintainer | Decide what blocks the merge without becoming a bottleneck | Uses the PR gate (exit code 1) and the per-severity summary on stderr | PRs blocked only when there is corroborated risk |
| Compliance Auditor | Traceable evidence mapped to controls | Reads SARIF/JSON with partialFingerprints, canonical controls (AVD/CIS), and per-scanner status |
Reproducible audit trail; suppressions always logged |
| Platform / CI/CD | Standardize the scan across N repositories without installing scanners | Uses the :full image or the GitHub Action composite (cosign-verified; socket auto-mounted on type: image) |
Repository onboarding with no local tooling install |
| Cloud/IaC Engineer | Validate multi-cloud Terraform/K8s before apply | quorum scan . --type repo / --type k8s, crosswalk rule→control (AWS/Azure/GCP + K8s) |
IaC misconfig and posture correlated across multiple engines |
5. Benefits¶
- Signal instead of noise. Consensus (
detectionCount+confidence) separates corroborated findings from isolated detections; the raw count is not confidence — the formula weighs engine diversity, severity, and authoritative confirmation (DESIGN.md§9). - Consensus beyond SCA. Cross-corroboration is no longer only about vulnerabilities: it covers multi-cloud IaC misconfig (Checkov × KICS × Terrascan × tfsec × Regula × Trivy) and Kubernetes posture (Kubescape × Polaris × kube-score), via a crosswalk derived from real output.
- One report, multiple formats. SARIF (primary, for GitHub code scanning/DefectDojo), JSON (for processing), and XML (legacy/JUnit-like pipelines).
- Optional telemetry.
--metricswrites metrics in Prometheus textfile format;--log-format jsonemits structured progress logs (one object per line) on stderr. - Free temporal dedup.
partialFingerprints["quorum/v1"]lets external tools recognize the same finding across runs. - Operational resilience. A missing scanner becomes
unavailableand is skipped — the scan never fails just because a tool is not installed. Timeout/OOM are distinguished from "not installed" via a version probe. DoS caps limit output (QUORUM_MAX_OUTPUT_BYTES, 512 MiB) and target size (QUORUM_MAX_TARGET_BYTES, 20 GiB). - Honesty about coverage. "0 findings is not proof of safety" is part of the product: the per-scanner status makes explicit whether anything actually ran.
- Direct CI gate. Exit code:
0= ok / no finding reached--fail-on;1= gate triggered;2= usage/runtime error. - Opt-in advisory layer.
--adviceattaches curated remediation templates + OWASP references (deterministic, no model) and, optionally, a natural-language recommendation from alocalorremoteprovider — always labeled "AI-generated, advisory only". It is presentation-only: it never touchescorrelationKey,fingerprint,confidence, aggregated severity, or the fail-on gate. - Verifiable supply chain. Images and binaries keyless-signed with cosign (OIDC) + SLSA build-provenance attestation + attested SPDX SBOM, verifiable at release. The knowledge pack + crosswalk also ship a SLSA build-provenance attestation each release.
- Determinism.
correlationKeyandFingerprint = sha256(correlationKey)are pure functions of the normalized data → reproducible reports.
6. Context diagram¶
flowchart TB
subgraph atores["Actors and triggers"]
dev["Dev / Tech Lead<br/>(PR)"]
ci["CI/CD Pipeline<br/>(GitHub Action / GitLab)"]
appsec["AppSec / DevSecOps"]
auditor["Compliance Auditor"]
end
subgraph quorum["Quorum (CLI / Docker)"]
orch["Orchestrator<br/>fan-out + timeout + probe"]
norm["Normalization<br/>model.Finding"]
alias["Alias Resolver<br/>(VULN)"]
corr["Correlator<br/>correlationKey"]
cons["Consensus<br/>detectionCount + confidence"]
adv["Advisory layer<br/>(--advice, opt-in)"]
rep["Reporters<br/>SARIF / JSON / XML"]
end
subgraph scanners["Pool of 12 OSS scanners"]
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["External services and data"]
osv["OSV.dev<br/>(aliases, optional)"]
cw["Crosswalk YAML<br/>aws/azure/gcp/k8s<br/>rule → canonical control"]
pol["Local Rego<br/>./policy (conftest)"]
know["Knowledge pack<br/>+ OWASP corpus<br/>(--advice)"]
llm["Advice provider<br/>local/remote (opt-in)"]
cache[("Local cache<br/>~/.cache/quorum")]
ghcr["GHCR<br/>signed images + SLSA + SBOM"]
end
subgraph consumidores["Report consumers"]
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 <-->|optional| 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 -.distributes.-> quorum
7. Differentiators¶
| Differentiator | What it is | Where it shows in the product |
|---|---|---|
| Consensus + score | detectionCount and confidence (0..1) per finding; confidence weighs engine diversity, severity, and authoritative confirmation |
properties.detectedBy/detectionCount/confidence in SARIF; DESIGN.md §9 |
| Multi-domain consensus | Cross-corroboration in VULN, multi-cloud MISCONFIG/IaC, and K8s posture — not just SCA | Crosswalk aws/azure/gcp.yaml (AVD hub) and k8s.yaml (Kubescape C-#### hub) derived from real output |
| false split > false merge | When in doubt, findings are not merged; a control with no mapping stays isolated and unmapped |
"No-match rule", DESIGN.md §6 |
| Per-scanner status transparency | Every report exposes ran/skipped/unavailable/error/timeout; a version probe distinguishes timeout/OOM/not-installed |
Summary on stderr (cmd/quorum/scan.go, printSummary); "0 findings is not proof of safety" |
| Deterministic correlation | Per-type correlationKey + Fingerprint = sha256(correlationKey); partialFingerprints["quorum/v1"] in SARIF |
DESIGN.md §6, §11 |
| Alias resolution with graceful degradation | CVE/GHSA unified via OSV.dev; a network failure does not bring down the scan; --offline disables OSV; aliases.json cache with perm 0600 and schemaVersion |
DESIGN.md §7; cmd/quorum/scan.go |
| Opt-in advisory layer | --advice attaches remediation + OWASP references (deterministic, DIGEST-PINNED corpus) and optional local/remote AI advice; --fix=suggest proposes a patch that must pass a verify-the-fix re-scan and never auto-applies |
internal/enrich, internal/rag, internal/advisor; docs/13-ia.md |
| Policy-as-code opt-in | conftest evaluates your Rego from ./policy (or QUORUM_CONFTEST_ARGS); with no policies it is reported as error — explicit opt-in |
internal/adapter/conftest.go |
| Per-scanner passthrough | QUORUM_<SCANNER>_ARGS appends arguments to the command (e.g., QUORUM_CHECKOV_ARGS --bc-api-key unlocks Prisma policies) |
README.md Scanners section; *-args inputs in the Action |
| Signed and attested supply chain | :full/:slim images and binaries keyless-signed (cosign/OIDC) + SLSA build-provenance + attested SPDX SBOM; bases pinned by sha256; scanners checksum-verified; the knowledge pack + crosswalk carry their own SLSA attestation; Action composite cosign-verifies before running |
README.md Install/CI/CD section; release.yml, .goreleaser.yaml |
| Pluggable crosswalk | rule → canonical control YAML (AVD/CIS); bundled at /opt/quorum/crosswalk with automatic fallback |
DESIGN.md §8; resolveCrosswalkDir in cmd/quorum/scan.go |
| Auditable baseline | .quorumignore by fingerprint/correlationKey; suppressions always logged, never silently dropped |
README.md Baseline section; filter.Apply |
8. Use cases¶
8.1 Pull Request gate (consensus in CI)¶
Block a PR when there is a corroborated finding at or above a threshold, accepting risks already triaged via baseline.
# GitHub Actions — via the composite Action (cosign-verifies the :full image)
- uses: Martinez1991/quorum-sec-scan@v0 # moving v0 tag advanced per release; pin by @<sha> in production
with:
target: .
type: repo
fail-on: high
- [ ] Set
--fail-on(e.g.,highorcritical). - [ ] Create/maintain
.quorumignorefor accepted risks (with a comment and date). - [ ] Upload the SARIF to GitHub code scanning.
- [ ] Treat exit code
1as the gate and2as a pipeline error.
8.2 Image scan (SCA / vulnerabilities)¶
SCA consensus over a container image, with CVE/GHSA aliases unified.
- [ ] Use
trivy+grypefor VULN corroboration. - [ ] Keep
--offlineif the environment cannot reach OSV.dev (uses local aliases + cache). - [ ] For a local image via
:full/Action, share the Docker socket (auto-mounted ontype: imagein the Action) — without it, the scan falls back to a pull and reports a false zero.
8.3 Infrastructure as Code (IaC / multi-cloud misconfig)¶
Misconfig consensus over Terraform (AWS/Azure/GCP), with SARIF for code scanning.
- [ ] Leverage consensus across Checkov, KICS, Terrascan, tfsec, Regula, and Trivy (tfsec emits native AVD and auto-correlates with Trivy).
- [ ] Ensure the crosswalk (
crosswalk/{aws,azure,gcp}.yaml) maps the rules to the canonical control (AVD). - [ ] Optional: add your Rego in
./policyto triggerconftest(policy-as-code). - [ ] Optional: add
--adviceto attach remediation + OWASP references per finding (deterministic; no data leaves the host). - [ ] Remember: a rule with no mapping stays
unmapped(it is not guessed).
8.4 Kubernetes posture (K8s posture, multi-engine)¶
Posture evaluation over K8s manifests, with consensus across three engines.
- [ ] Use
--type k8sto triggerkubescape,polaris, andkube-score(crosswalkk8s.yaml, Kubescape C-#### hub). - [ ] The crosswalk covers privilege-escalation, privileged, non-root, CPU/memory limits, probes, read-only-fs, linux-hardening, service-account automount, network-policy, host-network, host-PID/IPC, capabilities, and secrets.
- [ ] RBAC stays single-engine (Kubescape's RBAC requires cluster context; documented).
- [ ] Process the JSON (findings + per-scanner summary + severity rollup) downstream.
8.5 CI telemetry (Prometheus metrics)¶
Export scan metrics for observability.
- [ ] Collect
quorum.promas a node_exporter/pushgateway textfile. - [ ] Use
--log-format jsonfor structured ingestion of progress logs. - [ ] Under
--advice, extra metrics appear (quorum_advice_enriched,quorum_advice_provider,quorum_advice_fix) — including the verify-the-fix rate.
Distribution:
:fullimage (all 12 scanners,linux/amd64, pre-cached non-expiring grype DB) for self-contained CI;:slim(orchestrator only, amd64+arm64) when the scanners are already on PATH. Native binaries via GoReleaser. All images/binaries are signed (cosign) and attested (SLSA + SPDX SBOM).
9. Assumptions¶
- Version. Document aligned to v0.8.3 (revision 2026-07-04); flags, exit codes, scanners, and commands reflect
cmd/quorum/scan.go,cmd/quorum/root.go, andinternal/adapter/read at writing time (the version is injected at build/release). - Product scope. Quorum is CLI/Docker only. There is no web frontend, relational database, HTTP REST API, or user authentication/accounts. Corresponding items in enterprise templates are treated as N/A by architectural decision (a stateless orchestrator that integrates with CI/CD, not a service).
- The core has no AI; the advisory layer is opt-in. The deterministic core has no AI. An opt-in advisory layer (
--advice) can attach curated remediation + OWASP references (deterministic, no model) and, when explicitly enabled, local (--advice-provider=local) or remote (--advice-provider=remote) AI recommendations. It is off by default, presentation-only, and never touchescorrelationKey/fingerprint/confidence/aggregated severity/the fail-on gate; without--advicethe output is byte-identical (seedocs/13-ia.md). - Runtime security is N/A for now. The stream model (Falco/Tetragon) is out of scope; it appears only as a future proposal on the
README.md/DESIGN.mdroadmap. - Consensus by domain. VULN is shared by grype + trivy; MISCONFIG/IaC by trivy + checkov + kics + terrascan + tfsec + regula (+ conftest, policy-as-code); K8S_POSTURE by kubescape + polaris + kube-score; IMG_HARDENING is dockle-only (no pair for consensus yet). Kubescape's RBAC stays single-engine because it requires cluster context.
- Policy-as-code is opt-in.
conftesthas no built-in rules: with no Rego in./policy(or viaQUORUM_CONFTEST_ARGS), it is reported aserror— expected behavior. - Optional network dependency. Alias resolution via OSV.dev is optional and degrades gracefully;
--offlinedisables it. The scan does not depend on connectivity to complete. Likewise, the advisory layer's AI providers are optional: if the model is unreachable the report ships without AI advice and the scan never fails;remoterequires explicit consent (--advice-allow-egress) and is blocked by--offline. - Catalogs derived from real output. The crosswalk mappings (AVD/CKV, KICS UUIDs, Kubescape C-####) were derived from real output of the scanners in Terraform/K8s demos under the false split > false merge rule, but should be checked against the official catalogs before production (per the note in
README.mdandDESIGN.md§8). - Supply chain as a trust boundary. Scanner binaries embedded in the
:fullimage are part of the trust boundary; the release hardens this withsha256-pinned bases, checksum-verified scanners, cosign signing, SLSA build-provenance attestation, and an SPDX SBOM. The knowledge pack + crosswalk carry their own SLSA attestation (verify withgh attestation verify knowledge/owasp/corpus.yaml). For production, pin by digest and verify signatures/attestations. - Deterministic
confidence/correlationKey. Confidence values and correlation keys are functions of the normalized data; scanner-version changes may alter the input and therefore the output. - DoS caps. Per-scanner output is limited by
QUORUM_MAX_OUTPUT_BYTES(512 MiB) and on-disk target size byQUORUM_MAX_TARGET_BYTES(20 GiB;0disables).