Skip to content

ci: scan the release and main binaries with trivy - #129

Merged
katbyte merged 2 commits into
mainfrom
kt/binary-sec-checks
Sep 22, 2026
Merged

katbyte merged 2 commits into
mainfrom
kt/binary-sec-checks

Conversation

@katbyte

@katbyte katbyte commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Scan the last released binary and a fresh build of main with trivy, on every push to main, weekly, and after each release publishes. Same workflow as katbyte/tctest#146 and #149, in one change.

Why: govulncheck only reports advisories whose code is actually reachable, so it stays green while a version-based scanner, or a user running one, flags the shipped binary. Nothing today turns main red for "the binary users are running has a known vulnerability".

Two jobs, so the red X says what to do. Each is its own check on the main commit.

  • release binary downloads the latest release's linux_amd64 tarball and scans it. Red means cut a release.
  • build of main builds the commit and scans that. Red means bump a dependency.

Release red with main green means the fix is merged and a tag is all that is left. Both red means bump.

on:
  push:
    branches: [ 'main' ]
  schedule:
    - cron: '23 5 * * 1' # weekly, so new advisories against unchanged binaries still turn main red
  workflow_dispatch: # release.yaml reruns the failed jobs once a release publishes

Rescans once a release publishes, by rerunning in place. Without that, shipping the fix would leave main red until the next push or the Monday cron. A last job in the release workflow, with actions: write, finds every binary scan run on main's head that failed and reruns its failed jobs, which re-downloads the release just published. A rerun replaces the red check run; a scan started from a new event would sit beside it and the commit would stay red, which is what happened on katbyte/tctest after v1.3.4 with the workflow_run approach (fixed there in katbyte/tctest#149).

  rescan:
    needs: goreleaser
    permissions:
      actions: write # rerun workflow jobs
    steps:
      - run: |
          head=$(gh api "repos/$GH_REPO/commits/main" --jq .sha)
          runs=$(gh run list -w main-binary-scan.yaml -c "$head" ... select(.conclusion == "failure"))
          for run in $runs; do gh run rerun "$run" --failed; done

Scanned in rootfs mode, not fs. Checked locally on extracted releases: fs mode reported zero packages and zero findings for every binary, rootfs mode read the embedded module list and Go version. The Go version matters, since an old toolchain shows up as stdlib advisories.

Unfixed findings are skipped, everything else fails the job. High and Critical only, with ignore-unfixed so an advisory with no fixed version cannot make the check permanently red. Fixable findings the binary can never reach go in .github/trivyignore with a reason, which is empty today.

        with:
          scan-type: rootfs
          scan-ref: release
          scanners: vuln
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          trivyignores: .github/trivyignore
          exit-code: 1

Expect the first run to be green. A local trivy run with the same flags on a build of main is clean, and the 1.0.1 release scanned clean earlier today. tctest's first run went red on x/text as predicted, so the workflow is known to fail when it should.

Things that are fine as they are

  • No PR trigger. This gates what ships, not what is proposed; govulncheck stays as the reachability check on PRs.
  • The workflow could not be run before merge, since GitHub only registers a workflow for dispatch once it is on the default branch. yamllint, actionlint and zizmor pass with the repo's pinned tools.

Two jobs on push to main, weekly, and after a release publishes, so the red
X says what to do: the release job scans the last published binary (red
means cut a release) and the main job scans a fresh build of the commit
(red means bump the dependency). rootfs mode because fs mode does not read
go binaries; unfixed findings are skipped and anything triaged out goes in
.github/trivyignore. Same workflow as katbyte/tctest#146 and #147.
… a new one

A workflow_run rescan attaches as new check runs beside the original push
failure, so the commit stays red (seen on katbyte/tctest after v1.3.4). Only
a rerun replaces a check run in place. The release workflow now reruns the
failed jobs of any binary scan on main's head; that one job gets actions: write.
@katbyte
katbyte merged commit bca20f3 into main Sep 22, 2026
11 checks passed
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