Skip to content

feat(trivy-image-scan): add fail-on-finding, so the gate can actually gate - #166

Merged
patrick-hermann-sva merged 1 commit into
mainfrom
feat/trivy-fail-on-finding
Sep 5, 2026
Merged

feat(trivy-image-scan): add fail-on-finding, so the gate can actually gate#166
patrick-hermann-sva merged 1 commit into
mainfrom
feat/trivy-fail-on-finding

Conversation

@patrick-hermann-sva

Copy link
Copy Markdown
Contributor

The downstream half of stuttgart-things/dagger#351 (released as v0.129.0).

The defect

A consumer setting continue-on-error: false on this workflow had a gate that never fires. Verified against the published module before touching anything:

Case Result
alpine:3.10, carries 1 CRITICAL exit 0 — report returned, job green
image that does not exist exit 1

"Found something" reported success; "could not look" reported failure.

Two causes, both in the module: trivy exits 0 on findings and its exit code was discarded by || true, and the summary that should have carried the verdict was parsing secrets rather than vulnerabilities — so ParsedSummary was null on every image report this module has ever produced. dagger#351 fixes both and adds failOnFinding.

This half

  • fail-on-finding input, default false.
  • The module pin moves to trivy@v0.129.0.
  • A gate step placed after the artifact upload — with --fail-on-finding the module returns an error, so export is never reached and the report would go missing exactly when somebody wants it. Same two-call shape as call-dagger-govulncheck.yaml, for the same reason; the second call hits the cache from the first.

Why the default differs from the govulncheck template

call-dagger-govulncheck.yaml defaults fail-on-finding to true; this one to false, and that asymmetry is deliberate rather than an oversight.

govulncheck filters by reachability — it stays quiet about a CVE whose affected function is never called, so a finding means something is genuinely exposed and gating on day one is defensible. An image scan takes an inventory of a whole artefact, and its first findings are usually transitive and unactionable. Most consumers want to read a report before gating on one. Turning it on is a deliberate step once the list is known — which is exactly the discipline stuttgart-things/schmetterpause#86 followed for its own adoption.

Verified

  • The module behaviour was exercised locally across four cases before and after the fix — vulnerable image with the gate on (exit 1, names CVE-2021-36159 in apk-tools) and off (exit 0, ParsedSummary populated), a clean image with the gate on (exit 0), and a missing image (exit 1, unchanged).
  • pre-commit passes on the changed file, including check-github-workflows.
  • Not exercised: this workflow's own gate step. It is a uses:-only change that cannot run outside GitHub, and no consumer here has a vulnerable image to point it at. The first real proof will be a consumer enabling it.

Downstream

stuttgart-things/schmetterpause set continue-on-error: false on its Trivy job in #183 believing it had a gate. It does not until it also passes fail-on-finding: true against this revision — a follow-up PR there, plus a correction to the comment that currently overstates what the job does.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DGshyN1b9amKkrRRUubhbM

… gate

A consumer setting continue-on-error: false on this workflow got a gate that
never fires. The scan reported success on an image with a CRITICAL finding
and failed only when it could not reach the image at all -- verified against
the published module before fixing it.

stuttgart-things/dagger v0.129.0 fixes the module side: trivy's exit code
was discarded and the summary that should have carried the verdict was
parsing secrets rather than vulnerabilities, so ParsedSummary was null on
every image report ever produced. ScanImage now takes failOnFinding and
errors with the findings listed.

This is the other half. fail-on-finding defaults to false, unlike the
govulncheck template: an image scan takes an inventory of a whole artefact
and its first findings are usually transitive, so most consumers want to
read a report before gating on one. govulncheck filters by reachability,
which is what lets it gate on day one; this does not.

The gate is a second call placed after the artifact upload, because with
--fail-on-finding the module returns an error and export is never reached --
the report would go missing exactly when somebody wants it. Same shape as
call-dagger-govulncheck.yaml, for the same reason. The second call hits the
cache from the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGshyN1b9amKkrRRUubhbM
@patrick-hermann-sva
patrick-hermann-sva merged commit abd54d1 into main Sep 5, 2026
1 check passed
@patrick-hermann-sva
patrick-hermann-sva deleted the feat/trivy-fail-on-finding branch September 5, 2026 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant