Skip to content

Checklists

This document gathers five actionable checklists for the Quorum (quorum-sec-scan, v0.8.3) lifecycle: Development, QA, Security, Deploy/Release and Production/Operation. Every item is specific to the project's real flow — a CLI/Docker consensus security scanning tool written in Go 1.26, distributed as signed images on GHCR and native binaries via GoReleaser. Items are verifiable (with a command or acceptance criterion) and anchored to the behavior of the code (cmd/quorum, internal/*) and the workflows (.github/workflows/{ci,e2e,release,tag-major}.yml, action.yml).

Principle that runs through all checklists: "false split > false merge" and "0 findings is not proof of safety". An item is only "done" when you can prove the scanners ran (status ran) — not when the report came back empty.

Useful cross-links: Overview · Architecture · DevOps · Infrastructure · Observability · Roadmap.


Flow map (where each checklist acts)

flowchart LR
    DEV["1. Development\n(branch + code + local tests)"]
    PR["Pull Request → main"]
    CI["CI: ci.yml + e2e.yml\n(vet, test -race, coverage, build, real consensus)"]
    QA["2. QA\n(functional verification + contract tests)"]
    SEC["3. Security\n(trust boundary, supply chain)"]
    MERGE["Merge into main"]
    TAG["Semver tag vX.Y.Z"]
    REL["4. Deploy/Release\nrelease.yml: images + binaries\ncosign + SLSA + SBOM attested"]
    OPS["5. Production/Operation\nmount, socket, fail-on, baseline, verification"]

    DEV --> PR --> CI
    CI --> QA
    CI --> SEC
    QA --> MERGE
    SEC --> MERGE
    MERGE --> TAG --> REL --> OPS
    OPS -. feedback / baseline triage .-> DEV
Real stage Trigger Workflow / artifact Checklist
Code on a branch local work make test/vet/build 1. Development
PR to main pull_request ci.yml, e2e.yml 2. QA
Chain review PR / pre-release release.yml, action.yml, Dockerfile.full 3. Security
Tag vX.Y.Z push of a semver tag release.yml (images+binaries) 4. Deploy/Release
Moving tag v0/v0.8 published release tag-major.yml (auto-advances) 4. Deploy/Release
Pipeline usage docker run / action :full/:slim image 5. Production/Operation

1. Development Checklist

Goal: ensure a change is faithful to Quorum's architecture, passes the local gates before the PR and honors the adapters' contracts. Reproduces locally what ci.yml requires.

1.1 Setup and branch

  • [ ] Go 1.26+ installed (go version) — this is the version pinned in ci.yml, e2e.yml and release.yml.
  • [ ] Work done on a branch off main (never a direct commit to main); the flow is always via PR.
  • [ ] Required OSS scanners on PATH for manual end-to-end testing, or use of the :full image. There are 12 adapters registered (internal/adapter/*.go, via init()/Register):
  • [ ] VULN/SCA: trivy, grype.
  • [ ] MISCONFIG/IaC: trivy, checkov, kics, terrascan, tfsec, regula (+ conftest for policy-as-code).
  • [ ] K8S_POSTURE: kubescape, polaris, kube-score.
  • [ ] IMG_HARDENING: dockle.
  • [ ] SECRET: trivy (with redaction of Match).
  • Missing tools are reported as unavailable, and do not break the build.

1.2 Architecture adherence (as-is)

  • [ ] The change respects package boundaries: cmd/quorum (cobra CLI) vs. internal/{adapter,orchestrator,correlate,consensus,alias,cache,crosswalk,filter,model,purl,report,severity}.
  • [ ] Nothing introduces a dependency on a web frontend, relational database or REST API — out of the product's scope (CLI/Docker only).
  • [ ] The deterministic core stays AI-free: any AI/LLM lives in the opt-in advisory layer (internal/{enrich,rag,advisor}), is off by default, and is presentation-only — it never touches correlationKey, fingerprint, confidence, aggregated severity or the fail-on gate.
  • [ ] New output/normalization converges to the canonical model model.Finding (no raw scanner format leaks out of the adapter). New advisory fields (Remediation, References, Advice) hang off MergedFinding and are populated only under --advice.
  • [ ] If the change affects correlation, the correlationKey stays deterministic per type (VULN/MISCONFIG/K8S_POSTURE/etc — DESIGN §6) and the false split > false merge principle holds (when in doubt, isolate and mark unmapped).
  • [ ] The Trivy secret/Match is redacted before it leaves the adapter (do not leak a credential into the report).

1.3 Adapters (when applicable)

  • [ ] The adapter implements the full Adapter interface: Name / Version / Supports / Capabilities / Run.
  • [ ] A contract test exists against a versioned fixture in internal/adapter/testdata (a format change must break the test before it breaks production).
  • [ ] Version(ctx) is light enough for the 60s probe (Options.ProbeTime) and correctly distinguishes absence vs. slowness.
  • [ ] Supports(target) reflects the scanner's real targets (e.g. grype does not support k8s; dockle/kube-score are single-target; trivy supports all three types).
  • [ ] Passthrough honored: the adapter appends extraArgs(<name>) (read from QUORUM_<NAME>_ARGS) to its arguments, without breaking the output parse.
  • [ ] stdout buffer capped by QUORUM_MAX_OUTPUT_BYTES (default 512 MiB) — output above that is aborted with a clear error (anti-OOM).

1.4 Advisory layer (when applicable)

  • [ ] Phase 0 (deterministic, no model): curated remediation templates + OWASP references matched by canonicalControl/ruleId/category/type (package internal/enrich; data in knowledge/*.yaml — aws/azure/gcp/k8s/image/categories). New/edited templates keep the output byte-identical when --advice is off.
  • [ ] Phase 2 (RAG-as-artifact, deterministic): retrieval from a versioned, digest-pinned OWASP corpus (knowledge/owasp/corpus.yaml, package internal/rag). Lexical retrieval by default (no model); semantic only when the corpus is embedded via quorum advise-index, and scan auto-picks semantic when the corpus has vectors — the digest pin is preserved.
  • [ ] Phase 1 (opt-in local LLM, internal/advisor): reproducible via temperature=0 + an on-disk cache keyed by fingerprint+provider+model; --fix=suggest must pass a verify-the-fix re-scan (apply to a temp copy, re-scan with the same scanner, keep only if the finding is gone and the file parses) and never auto-applies. Graceful degradation: if the model is unreachable the report ships without AI advice and the scan never fails.
  • [ ] Phase 3 (opt-in remote provider): sends only the normalized finding, never source code; gated on --advice-allow-egress, blocked by --offline, and refuses --fix.
  • [ ] Every AI attachment is labeled "AI-generated, advisory only".
  • [ ] Evals updated when advisory behavior changes: internal/evals measures deterministic remediation coverage, OWASP reference relevance and the verify-the-fix rate (runs in CI, no heavy model).

1.5 Local gates (mirror ci.yml)

  • [ ] make vet (or go vet ./...) with no findings.
  • [ ] make test / go test -race ./... green (unit + contract + eval tests); coverage reported in CI.
  • [ ] make build / go build -trimpath -o dist/quorum ./cmd/quorum compiles.
  • [ ] Smoke: ./dist/quorum list-scanners lists the 12 registered adapters.
  • [ ] Manual functional test: ./dist/quorum scan <target> --format json produces a report and the stderr summary shows per-scanner status.
  • [ ] Advisory smoke (optional): ./dist/quorum scan <target> --advice attaches deterministic remediation/references without altering the fingerprints; the same scan without --advice produces byte-identical output.

1.6 PR hygiene

  • [ ] New/changed crosswalk in crosswalk/*.yaml follows the schema and the hub per cloud/platform family:
  • [ ] aws.yaml / azure.yaml / gcp.yamlAVD hub (S3/IAM/EBS/SG/RDS/ KMS/CloudTrail/VPC-flow-logs; Azure Storage/Key Vault; GCP bucket/ firewall/SQL).
  • [ ] k8s.yamlC-#### (kubescape) hub correlating kubescape × polaris × kube-score (privilege-escalation, privileged, non-root, cpu/mem limits, probes, read-only-fs, linux-hardening, automount-SA, network-policy, host-network, host-PID/IPC, capabilities, secrets).
  • A rule with no mapping is not "guessed" (it stays unmapped); the crosswalk is derived from real output (favors false split over false merge).
  • [ ] A change to ./policy (Rego) for conftest ships with a test — conftest has no rules of its own, it evaluates YOUR Rego (default ./policy).
  • [ ] Documentation updated when behavior changes (README.md, README.pt-BR.md, DESIGN.md, this docs/ and the docs published on GitHub Pages via MkDocs Material).
  • [ ] PR opened against main; waits for ci.yml and e2e.yml green.

2. QA Checklist

Goal: validate Quorum's observable behavior — real consensus, exit codes, formats and status transparency — not just "the unit tests passed". Anchored to e2e.yml, which runs real scanners (not fixtures).

2.1 Automated suite (PR)

  • [ ] ci.yml green: vet + go test -race ./... + coverage + build + smoke.
  • [ ] e2e.yml green on the consensus scenarios:
  • [ ] IaC/MISCONFIG (Trivy + Checkov/KICS/tfsec/terrascan/regula over examples/terraform) with summary.multiDetected >= 1.
  • [ ] SCA/VULN (Trivy + Grype over alpine:3.10) with summary.multiDetected >= 1.
  • [ ] K8S_POSTURE (kubescape × polaris × kube-score) correlating via crosswalk/k8s.yaml.
  • [ ] Adapter contract tests cover the updated fixture of the tool's real version.

2.2 Execution transparency (per-scanner status)

  • [ ] The report exposes per-scanner status: ran | skipped | unavailable | error | timeout.
  • [ ] The "tool missing" scenario produces unavailable and does not fail the scan.
  • [ ] The "per-scanner timeout" scenario (short --timeout) produces status timeout and an associated error message, not ran.
  • [ ] conftest with no policies in ./policy reports error (expected — policy-as-code is opt-in), not ran with 0 findings.
  • [ ] Manually validate that "0 findings" comes with the statuses — a 0 with everything ran is different from a 0 with everything unavailable.

2.3 Exit codes (gate)

Test scenario Command Expected exit
No --fail-on, or nothing hits the threshold scan … 0
Finding ≥ --fail-on scan … --fail-on high 1
Usage / runtime error scan with no target, invalid --type, invalid --log-format 2
  • [ ] 0 when no finding hits --fail-on (or the flag is absent).
  • [ ] 1 when there is a finding with severity ≥ --fail-on (gate fires, log gate: found … >= --fail-on … → exit 1).
  • [ ] 2 on a usage/runtime error (e.g. invalid --fail-on, invalid --format, --log-format other than text|json, a non-existent baseline passed explicitly via --baseline, a target starting with - refused, a target above QUORUM_MAX_TARGET_BYTES, an invalid --advice-provider, or --advice-provider=remote without --advice-allow-egress).

2.4 Output formats and telemetry

  • [ ] SARIF (default): contains partialFingerprints["quorum/v1"] = sha256(correlationKey) and properties.detectedBy/detectionCount/confidence.
  • [ ] JSON: field fingerprint, summary.multiDetected, scanners[] with status and count, severity rollup.
  • [ ] XML: the same structure serialized (legacy/JUnit-like pipelines).
  • [ ] --output/-o writes to a file: the path goes through filepath.Clean, creates the parent directory if needed and writes with perm 0600 (the report may contain sensitive detail); without -o it writes to stdout.
  • [ ] --metrics <file> writes metrics in Prometheus text format (textfile collector), perm 0644 (non-sensitive counts).
  • [ ] --log-format text|json controls the progress log on stderr (json emits {ts,level,msg}).

2.5 Severity, baseline and min-severity

  • [ ] --min-severity removes findings below the threshold from the report and from gating; suppressions are logged (filtered: … below min-severity <sev>).
  • [ ] --baseline/.quorumignore suppresses by fingerprint or correlationKey; suppressions are always logged (never silently dropped; the log carries the count of entries and of suppressed items).
  • [ ] A comment line (#) and blank lines in .quorumignore are ignored correctly.

2.6 Alias resolution

  • [ ] With network: CVE-… (Trivy) and GHSA-… (Grype) for the same bug correlate (local alias → cache ~/.cache/quorum/aliases.json → OSV.dev, CVE preferred). The OSV id is validated and passes through url.PathEscape.
  • [ ] --offline: no call to OSV; graceful degradation (uses local aliases + cache).
  • [ ] A simulated network failure does not bring down the scan (graceful degradation).
  • [ ] The alias cache is written with perm 0600 and loads a compatible schemaVersion (a corrupted/old-version file is ignored, does not break).

2.7 Advisory layer (only under --advice)

  • [ ] Byte-identical without --advice: the same scan with and without the flag produces identical output (advisory is presentation-only; it never touches correlationKey/fingerprint/confidence/severity/the gate).
  • [ ] Phase 0 attaches deterministic Remediation/References matched by control/rule/category/type; no network needed.
  • [ ] Phase 2: lexical retrieval works with the digest-pinned corpus offline; after quorum advise-index, scan auto-picks semantic retrieval.
  • [ ] --advice-provider=local degrades gracefully when the endpoint is unreachable (report ships without AI advice, scan does not fail); reproducible via temperature=0 + fingerprint cache.
  • [ ] --fix=suggest only keeps a patch that passes the verify-the-fix re-scan (finding gone + file still parses) and never auto-applies.
  • [ ] --advice-provider=remote sends only the normalized finding (titles, paths, controls — never source), requires --advice-allow-egress, is blocked by --offline, and refuses --fix.
  • [ ] Every AI attachment is labeled "AI-generated, advisory only".
  • [ ] Metrics under --advice present when --metrics is used: quorum_advice_enriched{kind=remediation|references|recommendation}, quorum_advice_provider{provider}, quorum_advice_fix{stage=proposed|verified} (verified/proposed = the verify-the-fix rate).

3. Security Checklist

Goal: treat Quorum's own chain as a trust boundary and validate the supply-chain guarantees (DESIGN §12). Covers both what Quorum produces and what it consumes (packaged scanner binaries).

3.1 Release supply chain

  • [ ] Images are keyless-signed with cosign (OIDC), over the manifest digest, with retry — verify before use:
    cosign verify ghcr.io/martinez1991/quorum-sec-scan:slim \
      --certificate-identity-regexp \
        "https://github.com/Martinez1991/quorum-sec-scan/.github/workflows/release.yml@.*" \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com
    
  • [ ] SLSA build-provenance attestation present and verifiable (image):
    gh attestation verify oci://ghcr.io/martinez1991/quorum-sec-scan:full \
      --repo Martinez1991/quorum-sec-scan
    
  • [ ] Attested SPDX SBOM (actions/attest-sbom, via syft) verifiable — in addition to the sbom: true attestation from BuildKit:
    gh attestation verify oci://ghcr.io/martinez1991/quorum-sec-scan:full \
      --repo Martinez1991/quorum-sec-scan --predicate-type https://spdx.dev/Document
    
  • [ ] Native binaries: checksums.txt + cosign signature (cosign verify-blob) + SLSA attestation by subject-checksums (gh attestation verify quorum_<ver>_<os>_<arch>.tar.gz --repo …) + per-binary SPDX SBOM (GoReleaser/syft).
  • [ ] Knowledge pack attested: the advisory knowledge pack + crosswalk get a SLSA build-provenance attestation each release (release.yml knowledge job) — verify the corpus before trusting the advisory layer offline:
    gh attestation verify knowledge/owasp/corpus.yaml \
      --repo Martinez1991/quorum-sec-scan
    
  • [ ] release.yml itself re-verifies the attestation (image and binary) as a release step, with retry — a release with a broken attestation must fail.

3.2 CI permissions and identity

  • [ ] release.yml keeps minimal permissions: contents: read (job images), packages: write, id-token: write (cosign keyless), attestations: write (SLSA + SBOM + knowledge pack).
  • [ ] Job binaries uses contents: write only to create the release (plus id-token/attestations: write).
  • [ ] The release trigger is restricted to semver tags v[0-9]+.[0-9]+.[0-9]+ — moving tags (v0, v0.8, used to pin the action) do not trigger a build; they are advanced by tag-major.yml on the release event.

3.3 Composite GitHub Action (action.yml)

  • [ ] By default verify: "true" → cosign-verifies the :full image before running it (installs cosign if absent).
  • [ ] In production, image is pinned by @sha256:<digest> (not a moving tag) and the action is pinned by @<sha>.
  • [ ] docker-socket reviewed: for type: image the socket /var/run/docker.sock is auto-mounted (avoids a false-zero when scanning a freshly-built local image); off disables even for image, true forces it for other types. Without the socket, a local-image scan emits a warning.
  • [ ] Passthrough inputs (trivy-args, grype-args, checkov-args, kics-args, dockle-args, kubescape-args) reviewed — they can carry secrets (e.g. checkov --bc-api-key for Prisma/Bridgecrew) and so are not echoed in the log.
  • [ ] Advisory inputs reviewed: advice, advice-provider, advice-endpoint, advice-model, advice-embed-model, advice-max, advice-cache, advice-allow-egress, advice-api-key, fix. For local the action auto-adds host-gateway; for remote the advice-api-key is forwarded via env (never on the command line) and egress needs explicit consent.
  • [ ] Sensitive inputs (baseline, crosswalk, offline) reviewed for security impact (e.g. a baseline is not suppressing a real risk).

3.4 Packaged scanner binaries (:full image)

  • [ ] Acknowledged that the packaged OSS binaries are part of the consumer's trust boundary (THIRD_PARTY_NOTICES.md lists the licenses).
  • [ ] Image bases pinned by @sha256; scanner downloads (kubescape, tfsec, terrascan, regula, conftest) verified by checksum in Dockerfile.full.
  • [ ] Grype DB pre-cached in :full, from a trusted source (Anchore), built with GRYPE_DB_VALIDATE_AGE=false (does not expire on runners without egress) — the version matches the supported schema.

3.5 Secure by default (hardening)

  • [ ] --offline available for egress-less environments (turns off OSV and blocks --advice-provider=remote).
  • [ ] AI egress is off by default and opt-in: --advice-provider=remote requires explicit --advice-allow-egress, sends only the normalized finding (never source), and refuses --fix. --advice-provider=local and the deterministic phases never leave the host.
  • [ ] Argument injection blocked: a target starting with - is refused (use ./-name).
  • [ ] DoS caps active: QUORUM_MAX_OUTPUT_BYTES (512 MiB) and QUORUM_MAX_TARGET_BYTES (20 GiB) — override/disable by env.
  • [ ] --output normalized (filepath.Clean) and written with perm 0600; metrics with 0644.
  • [ ] Suppressions (--baseline, --min-severity) are auditable: always logged; review ensures no entry is masking an active finding.
  • [ ] Alias cache (~/.cache/quorum/aliases.json, perm 0600, with schemaVersion) treated as untrusted/derived data (can be deleted without loss of correctness); the advisory cache (--advice-cache) is likewise derived and safe to delete.
  • [ ] The Trivy secret (Match) is redacted — the report does not leak a credential.
  • [ ] False negatives from a malformed mount are prevented (see checklist 5.1) — an empty /work reports 0 findings.

4. Deploy/Release Checklist

Goal: run a reproducible, signed release. The release is triggered by a push of a semver tag vX.Y.Z; release.yml builds/publishes images (:full, :slim) and binaries (GoReleaser), signs and attests everything (cosign + SLSA + SBOM SPDX + knowledge pack).

4.1 Pre-tag

  • [ ] main is green (ci.yml + e2e.yml) on the commit to be tagged.
  • [ ] The chosen version follows strict semver vX.Y.Z (e.g. v0.8.3) — the release.yml only fires for v[0-9]+.[0-9]+.[0-9]+.
  • [ ] CHANGELOG/notes checked; GoReleaser has full history (fetch-depth: 0) to generate the changelog.
  • [ ] The packaged crosswalk reviewed (crosswalk/{aws,azure,gcp,k8s}.yaml) — it is bundled into /opt/quorum/crosswalk in the images and binaries.
  • [ ] Rego policies in ./policy (if any) reviewed — they ship along for conftest use.
  • [ ] The advisory knowledge pack reviewed (knowledge/*.yaml, knowledge/owasp/corpus.yaml) — the corpus digest pin is intact and the pack ships bundled for offline Phase 0/2.

4.2 Triggering the release

  • [ ] Tag created and pushed:
    git tag v0.8.3
    git push origin v0.8.3
    
  • [ ] The release.yml workflow started for the tag (not for a moving tag).

4.3 Images (job images)

  • [ ] :full published on linux/amd64 with tags :full, :<version>, :<version>-full, :latest (all 12 scanners packaged; Grype DB pre-cached).
  • [ ] :slim published on linux/amd64,linux/arm64 with tags :slim, :<version>-slim (orchestrator only).
  • [ ] provenance: true and sbom: true on the build-push (BuildKit).
  • [ ] cosign sign (with retry) applied to the manifest digest (covers all the tags that point to it).
  • [ ] actions/attest-build-provenance generated and pushed the SLSA attestation to GHCR.
  • [ ] actions/attest-sbom generated and pushed the attested SPDX SBOM (syft → sbom.spdx.json).
  • [ ] The "Verify provenance attestation" step passed (end-to-end re-check, with retry).

4.4 Binaries (job binaries, tag-only)

  • [ ] GoReleaser published archives per OS/arch + checksums.txt + cosign signature, with per-binary SPDX SBOMs (syft).
  • [ ] SLSA attestation by subject-checksums: dist/checksums.txt generated.
  • [ ] The verification step ("spot-check" of one artifact) passed (with retry).

4.5 Knowledge pack (job knowledge)

  • [ ] The advisory knowledge pack + crosswalk got a SLSA build-provenance attestation this release — verify before trusting the advisory layer:
    gh attestation verify knowledge/owasp/corpus.yaml \
      --repo Martinez1991/quorum-sec-scan
    

4.6 GitHub Action / moving tag

  • [ ] Moving tag v0 (and v0.8) auto-advanced by tag-major.yml on the release event — action pin uses: Martinez1991/quorum-sec-scan@v0.
  • [ ] Moving v0/v0.8 does not trigger a new release build (the trigger is semver-restricted).

4.7 Post-publication validation (consumer side)

  • [ ] cosign verify of the freshly-published image OK (see 3.1).
  • [ ] gh attestation verify of the image (provenance and SBOM), of a binary, and of the knowledge corpus OK.
  • [ ] docker run --rm … :full list-scanners lists the 12 packaged scanners.
  • [ ] Real smoke: a scan of a known target produces consensus (detectionCount > 1 on at least one finding).
sequenceDiagram
    participant Dev
    participant GH as GitHub (tag vX.Y.Z)
    participant REL as release.yml
    participant GHCR
    participant Sigstore as Sigstore/OIDC

    Dev->>GH: git push origin vX.Y.Z
    GH->>REL: trigger (semver only)
    REL->>GHCR: build & push :full / :slim (+SBOM/provenance BuildKit)
    REL->>Sigstore: cosign sign (digest, keyless, retry)
    REL->>GHCR: attest SLSA build-provenance
    REL->>GHCR: attest SBOM SPDX (syft)
    REL->>GHCR: attest knowledge pack (SLSA)
    REL->>GHCR: gh attestation verify (re-check, retry) ✓
    REL->>GH: GoReleaser release (binaries + checksums + sig + SBOM)
    GH->>GH: tag-major.yml advances v0 / v0.8

5. Production/Operation Checklist

Goal: run Quorum correctly in pipelines, avoid the classic false negative (wrong mount / missing socket) and operate the gate with confidence. Applies to a direct docker run, to container:/CI, and to the composite action.

5.1 Correct mount and Docker socket (the #1 mistake)

  • [ ] Source mounted at /work with the correct colon of the host:container separator:
  • [ ] Linux/macOS: -v "$PWD:/work"
  • [ ] PowerShell: -v "${PWD}:/work"
  • [ ] cmd.exe: -v "%cd%:/work"
  • [ ] Do not use a malformed mount like -v "%cd%/work" (no :), which mounts an empty /work → reports 0 findings for everything (false negative).
  • [ ] Container workdir coherent (-w /work) when the target is ..
  • [ ] Local image scan (--type image of a freshly-built image): mount the host daemon socket, otherwise the image is invisible from inside the container → false-zero:
  • [ ] docker run: -v /var/run/docker.sock:/var/run/docker.sock.
  • [ ] Action: auto-mounted for type: image (opt-out docker-socket: "off", force with "true").
  • [ ] Anti-false-negative validation: confirm in the summary that scanners are ran (not unavailable) and that the number of analyzed files makes sense.

5.2 Verify before running

  • [ ] Image cosign-verified before use (or verify: true in the action) — see 3.1.
  • [ ] SLSA + SBOM verified when policy requires it (gh attestation verify for provenance and for the SPDX SBOM); verify the knowledge corpus attestation when relying on the offline advisory layer.
  • [ ] In production, the image is pinned by @sha256:<digest> and the action by @<sha>.

5.3 Scan configuration

  • [ ] Correct --type (image|repo|k8s) or confirmed that inference (existing path → repo, otherwise image) hits the right target.
  • [ ] --scanners sets the desired pool (or is omitted for all that support the target) — remember that grype does not do k8s and dockle/kube-score are single-target.
  • [ ] --crosswalk: using the bundled /opt/quorum/crosswalk (auto-detected in the image when ./crosswalk is absent) or pointing at your own mappings; the initial log shows crosswalk=N rules (<dir>).
  • [ ] conftest: Rego policies in ./policy (or QUORUM_CONFTEST_ARGS="--policy <dir>") — without them the scanner is error, which is expected.
  • [ ] Per-scanner passthrough via QUORUM_<SCANNER>_ARGS when you need to broaden coverage or unlock policies (e.g. QUORUM_CHECKOV_ARGS="--bc-api-key <key> …"). Treat as a secret (do not echo).
  • [ ] --timeout per scanner suited to the runner (default 5m); if there is unavailable from a slow/OOM probe (60s), increase the container memory or reduce --scanners.
  • [ ] DoS caps adjusted if needed: QUORUM_MAX_OUTPUT_BYTES (512 MiB), QUORUM_MAX_TARGET_BYTES (20 GiB).

5.4 Build gate

  • [ ] --fail-on <sev> set per policy (the gate fires exit 1).
  • [ ] The pipeline handles the exit codes correctly: 0 ok · 1 gate · 2 error (do not confuse 1 with 2).
  • [ ] --min-severity used to reduce noise without masking the gate (review that the threshold does not hide the --fail-on severity).

5.5 Baseline and continuous triage

  • [ ] .quorumignore versioned, with one fingerprint/correlationKey per line + a justification comment + a revision date.
  • [ ] Fingerprints copied from the report itself (partialFingerprints["quorum/v1"] in SARIF / fingerprint in JSON).
  • [ ] Suppressions reviewed periodically (every suppression is logged — audit the CI log).

5.6 Integration, artifacts and telemetry

  • [ ] SARIF published to GitHub code scanning / DefectDojo (free dedupe via partialFingerprints).
  • [ ] The report (-o quorum.sarif/.json/.xml, perm 0600) saved as a pipeline artifact (always, including on a gate failure).
  • [ ] --metrics <file> exported to the Prometheus textfile collector when observability exists (counts per scanner/severity; plus quorum_advice_* when --advice is on).
  • [ ] --log-format json enabled when the log aggregator consumes NDJSON.
  • [ ] Egress-less environment: --offline on (turns off OSV and blocks remote advice; alias consensus falls back to the local cache). Grype DB on :full does not expire.

5.7 Optional advisory layer

  • [ ] Advisory is off by default; enable with --advice when you want human-readable remediation/references attached — output stays presentation-only and never changes the gate.
  • [ ] Phase 0/2 run offline and deterministically (curated templates + the digest-pinned OWASP corpus); quorum advise-index embeds the corpus for semantic retrieval, preserving the pin.
  • [ ] --advice-provider=local points at an on-host OpenAI-compatible endpoint (e.g. Ollama via --advice-endpoint); reproducible (temperature=0 + --advice-cache); degrades gracefully if the model is unreachable.
  • [ ] --advice-provider=remote used only with explicit consent (--advice-allow-egress, QUORUM_ADVICE_API_KEY), is blocked by --offline, refuses --fix, and sends only the normalized finding.
  • [ ] --fix=suggest proposals are treated as suggestions only (verify-the-fix re-scan, never auto-applied); a human still reviews and applies them.
  • [ ] Every AI attachment is read as "AI-generated, advisory only".

5.8 Operation and diagnosis

  • [ ] The stderr summary (── quorum summary ──) inspected: per-scanner status, multi-detected count, severities, elapsed.
  • [ ] unavailable/timeout/error statuses treated as a signal — not as "clean". Remember: "0 findings is not proof of safety".
  • [ ] On OOM (version probe killed/signal: killed or output above the cap): raise the container memory limit or the cap.
  • [ ] quorum list-scanners used to confirm which of the 12 adapters are registered/packaged in the image in use.

Assumptions

  • Reference version: documentation written for Quorum v0.8.3 (revision 2026-07-04), based on the current state of the repository (README.md, DESIGN.md, cmd/quorum/{root,scan,advise_index}.go, internal/adapter/*.go, internal/orchestrator/orchestrator.go, internal/{enrich,rag,advisor,evals}, knowledge/*.yaml, .github/workflows/{ci,e2e,release,tag-major}.yml, action.yml, Dockerfile.full, .goreleaser.yaml, crosswalk/*.yaml). Items marked as behavior (exit codes, status, flags, env) reflect the code as-is.
  • Product scope: CLI/Docker only is assumed. Checklist items that in enterprise templates would deal with a web frontend, relational database or REST API are N/A by design and were deliberately omitted (there is no corresponding surface in the code). AI/LLM is not out of scope, but it lives strictly in the opt-in advisory layer (off by default, presentation-only); the deterministic core has no AI.
  • Owner/repo: the verification commands use ghcr.io/martinez1991/quorum-sec-scan and Martinez1991/quorum-sec-scan, as in README.md/action.yml/release.yml. In forks, adjust the owner/cosign certificate identity.
  • Typical production environment: execution in a CI/CD pipeline is assumed (GitHub Actions, GitLab CI or docker run), not a cluster runtime — Quorum has no resident component. "Production/Operation" items refer to operating the scanner in a pipeline. RBAC via kubescape is single-engine (needs cluster context) and is documented as such.
  • Platforms: :full is linux/amd64 only (scanner binaries are amd64); :slim covers amd64+arm64. Mount/execution checklists assume a host capable of running the target image (e.g. emulation for arm64).
  • Version probe: the 60s value (Options.ProbeTime/defaultProbeTime) is treated as fixed; if exposed via a flag in future versions, item 5.3 must be updated.
  • Version in the binary: main.version defaults to 0.1.0, overridden at build-time via -ldflags "-X main.version=…" in the release; v0.8.3 here refers to the published product version, not a literal hard-coded in the code.