From 0882d0a93103da7c2f7e27879f5effcb57691928 Mon Sep 17 00:00:00 2001 From: "Benjamin R. J. Schwedler" Date: Tue, 11 Aug 2026 13:34:42 -0500 Subject: [PATCH 1/2] Add opt-in Trivy scanning to PR builds Re-adds the PR-build Scan step split out of #722, behind a scan-image input defaulting to false. A scan costs roughly as long again as the build it follows -- ~4 minutes per job measured on images-connect content builds -- so imposing it on every caller's every PR is not a default anyone should inherit silently. Adds scan-fail-on-severity, unset by default. Without it the step could not fail a build even in principle, which is what made the previous always-on version pure cost: no --fail-on-severity, plus continue-on-error, means the result was a table in a collapsed log group. A caller that opts in can now also choose to gate on it. Pins trivy-version rather than tracking latest. setup-trivy logs "doesn't currently support caching the 'latest' version", so the default re-downloaded the binary on every job. Not wired to code scanning. Fork PRs get a read-only token and could not be granted security-events: write, and main only analyses latest versions, so PR-time uploads of older versions would have no baseline and would report every finding as new. --- .github/workflows/bakery-build-pr.yml | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/.github/workflows/bakery-build-pr.yml b/.github/workflows/bakery-build-pr.yml index 36f21a42..f747ec5a 100644 --- a/.github/workflows/bakery-build-pr.yml +++ b/.github/workflows/bakery-build-pr.yml @@ -35,6 +35,21 @@ on: default: "exclude" required: false type: string + scan-image: + description: "Scan built images with Trivy [default: false]" + default: false + required: false + type: boolean + scan-fail-on-severity: + description: "Comma-separated severities that fail the scan if found (e.g. CRITICAL). Empty means findings never fail." + default: "" + required: false + type: string + trivy-version: + description: "Trivy release to install (e.g. v0.73.0). 'latest' disables binary caching in setup-trivy." + default: "v0.73.0" + required: false + type: string retry: description: "Number of times to retry a failed build" default: 1 @@ -284,6 +299,44 @@ jobs: "${CACHE_FLAGS[@]}" \ --context "$BAKERY_CONTEXT" + - name: Setup trivy + if: ${{ inputs.scan-image }} + uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 + with: + version: ${{ inputs.trivy-version }} + cache: true + + # Opt-in per caller. This runs on every PR build for a repo that enables + # it, and a scan costs roughly as long again as the build it follows, so + # the default stays off until a caller decides the signal is worth it. + - name: Scan + if: ${{ inputs.scan-image }} + continue-on-error: true + env: + IMAGE_NAME: ${{ matrix.img.image }} + IMAGE_VERSION: ${{ matrix.img.version }} + NORMALIZED_PLATFORM: ${{ steps.normalize-platform.outputs.platform }} + IMG_DEV: ${{ matrix.img.dev }} + MATRIX_VERSIONS: ${{ inputs.matrix-versions }} + BAKERY_CONTEXT: ${{ inputs.context }} + FAIL_ON_SEVERITY: ${{ inputs.scan-fail-on-severity }} + run: | + if [ "$IMG_DEV" = "true" ]; then + DEV_VERSIONS=only + else + DEV_VERSIONS=exclude + fi + FAIL_FLAGS=() + [[ -n "$FAIL_ON_SEVERITY" ]] && FAIL_FLAGS=(--fail-on-severity "$FAIL_ON_SEVERITY") + bakery trivy scan \ + --image-name "^${IMAGE_NAME}$" \ + --image-version "$IMAGE_VERSION" \ + --image-platform "$NORMALIZED_PLATFORM" \ + --dev-versions "$DEV_VERSIONS" \ + --matrix-versions "$MATRIX_VERSIONS" \ + "${FAIL_FLAGS[@]}" \ + --context "$BAKERY_CONTEXT" + - name: Test env: IMAGE_NAME: ${{ matrix.img.image }} From 9c59d69ba59f6128c08117e68fd62a5e25256ad2 Mon Sep 17 00:00:00 2001 From: "Benjamin R. J. Schwedler" Date: Tue, 11 Aug 2026 14:10:00 -0500 Subject: [PATCH 2/2] Run the PR-build scan after Test and rename it Same placement bug the native workflow had. PR builds also use `--strategy build --pull --load`, so only the last target of an image stays addressable by tag, and this workflow passes no --metadata-file to fall back on digests. Scanning before Test resolved stale tags and silently scanned published images. Renames to `Trivy Scan` to match the native workflow, where it has to be distinct from #715's Wiz scan. --- .github/workflows/bakery-build-pr.yml | 54 +++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/bakery-build-pr.yml b/.github/workflows/bakery-build-pr.yml index f747ec5a..79f909b0 100644 --- a/.github/workflows/bakery-build-pr.yml +++ b/.github/workflows/bakery-build-pr.yml @@ -299,67 +299,67 @@ jobs: "${CACHE_FLAGS[@]}" \ --context "$BAKERY_CONTEXT" - - name: Setup trivy - if: ${{ inputs.scan-image }} - uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 - with: - version: ${{ inputs.trivy-version }} - cache: true - - # Opt-in per caller. This runs on every PR build for a repo that enables - # it, and a scan costs roughly as long again as the build it follows, so - # the default stays off until a caller decides the signal is worth it. - - name: Scan - if: ${{ inputs.scan-image }} - continue-on-error: true + - name: Test env: IMAGE_NAME: ${{ matrix.img.image }} IMAGE_VERSION: ${{ matrix.img.version }} - NORMALIZED_PLATFORM: ${{ steps.normalize-platform.outputs.platform }} + IMAGE_PLATFORM: ${{ matrix.img.platform }} IMG_DEV: ${{ matrix.img.dev }} MATRIX_VERSIONS: ${{ inputs.matrix-versions }} BAKERY_CONTEXT: ${{ inputs.context }} - FAIL_ON_SEVERITY: ${{ inputs.scan-fail-on-severity }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if [ "$IMG_DEV" = "true" ]; then DEV_VERSIONS=only else DEV_VERSIONS=exclude fi - FAIL_FLAGS=() - [[ -n "$FAIL_ON_SEVERITY" ]] && FAIL_FLAGS=(--fail-on-severity "$FAIL_ON_SEVERITY") - bakery trivy scan \ + GOSS_PATH=${GITHUB_WORKSPACE}/tools/goss \ + DGOSS_PATH=${GITHUB_WORKSPACE}/tools/dgoss \ + bakery dgoss run \ --image-name "^${IMAGE_NAME}$" \ --image-version "$IMAGE_VERSION" \ - --image-platform "$NORMALIZED_PLATFORM" \ + --image-platform "$IMAGE_PLATFORM" \ --dev-versions "$DEV_VERSIONS" \ --matrix-versions "$MATRIX_VERSIONS" \ - "${FAIL_FLAGS[@]}" \ --context "$BAKERY_CONTEXT" - - name: Test + - name: Setup trivy + if: ${{ inputs.scan-image }} + uses: aquasecurity/setup-trivy@81e514348e19b6112ce2a7e3ecbafe19c1e1f567 # v0.3.1 + with: + version: ${{ inputs.trivy-version }} + cache: true + + # After Test: only Test's `docker run` makes every target addressable + # locally. Scanning earlier resolves stale tags and silently scans the + # published image instead of the one just built. + - name: Trivy Scan + if: ${{ inputs.scan-image }} + continue-on-error: true env: IMAGE_NAME: ${{ matrix.img.image }} IMAGE_VERSION: ${{ matrix.img.version }} - IMAGE_PLATFORM: ${{ matrix.img.platform }} + NORMALIZED_PLATFORM: ${{ steps.normalize-platform.outputs.platform }} IMG_DEV: ${{ matrix.img.dev }} MATRIX_VERSIONS: ${{ inputs.matrix-versions }} BAKERY_CONTEXT: ${{ inputs.context }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FAIL_ON_SEVERITY: ${{ inputs.scan-fail-on-severity }} run: | if [ "$IMG_DEV" = "true" ]; then DEV_VERSIONS=only else DEV_VERSIONS=exclude fi - GOSS_PATH=${GITHUB_WORKSPACE}/tools/goss \ - DGOSS_PATH=${GITHUB_WORKSPACE}/tools/dgoss \ - bakery dgoss run \ + FAIL_FLAGS=() + [[ -n "$FAIL_ON_SEVERITY" ]] && FAIL_FLAGS=(--fail-on-severity "$FAIL_ON_SEVERITY") + bakery trivy scan \ --image-name "^${IMAGE_NAME}$" \ --image-version "$IMAGE_VERSION" \ - --image-platform "$IMAGE_PLATFORM" \ + --image-platform "$NORMALIZED_PLATFORM" \ --dev-versions "$DEV_VERSIONS" \ --matrix-versions "$MATRIX_VERSIONS" \ + "${FAIL_FLAGS[@]}" \ --context "$BAKERY_CONTEXT" build-test-result: