From bc4d65daaa306ba5026e7aa1bca481657887d8c5 Mon Sep 17 00:00:00 2001 From: Neil Galvin Date: Thu, 17 Sep 2026 10:41:42 +0100 Subject: [PATCH] fix(docker-build): skip QEMU for native builds, gate the SARIF upload Two faults found while clearing red mains across the HordiaLabs consumers. setup-qemu-action ran unconditionally. QEMU exists only to emulate a foreign architecture, the runners are all X64, and `platforms` defaults to linux/amd64 -- so for most consumers the step installed binfmt handlers that nothing then used. It cost 16m18s on one observed extractor-llm run, ahead of a build that never needed it, on a three-runner pool where queueing is the dominant cost. Now skipped when `platforms` is exactly linux/amd64. The two consumers that really cross-build, scraper-proxy-router always and store-s3 on main, request linux/arm64 and still get it. The SARIF upload had no opt-out. trivy-repo.yml has carried an `upload-sarif` input for exactly this since the Free-plan private repos cannot use code scanning, but docker-build.yml uploaded unconditionally, so `Upload SARIF` failed with "Advanced Security must be enabled for this repository to use code scanning" on every push to main while the Trivy scan immediately above it passed. A permanently red check reporting an entitlement rather than a finding. Adds the matching input, defaulting true so nothing changes for consumers that do have Advanced Security, and gates the SARIF generation step on it too so nothing is produced that cannot be uploaded. Affects the two consumers that pass `run-trivy-scan: true`, extractor-llm and store-postgres; both need `upload-sarif: false` once this is released. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01EoicTZniGXry3W7YFZBsSM --- .github/workflows/docker-build.yml | 30 ++++++++++++++++++++++++++++-- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 6e0df06..29cb0c6 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -70,6 +70,16 @@ on: trivy-ignore-unfixed: type: boolean default: true + upload-sarif: + description: >- + Upload the Trivy SARIF report to code scanning. Requires GitHub + Advanced Security, so private repos on the Free plan must pass false — + otherwise the upload step fails with "Advanced Security must be + enabled for this repository to use code scanning" while the scan + itself passes. Mirrors the input of the same name on trivy-repo.yml. + Defaults true to preserve existing behaviour. + type: boolean + default: true sign-image: description: "Sign the pushed image with cosign keyless OIDC. Requires push: true." type: boolean @@ -115,7 +125,17 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + # QEMU only exists to emulate a foreign architecture. The runners are all + # X64 and `platforms` defaults to linux/amd64, so for most consumers this + # step installs binfmt handlers that nothing then uses — while costing real + # wall-clock on a contended pool: 16m18s observed on one extractor-llm + # run, ahead of a build that never needed it. + # + # Skipped when the requested platforms are exactly the native arch. The + # two consumers that do cross-build (scraper-proxy-router always, store-s3 + # on main) pass a platforms list containing linux/arm64 and still get it. - uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 + if: inputs.platforms != 'linux/amd64' - uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 # Mint a scoped App token for private modules pulled during the build. @@ -226,8 +246,14 @@ jobs: severity: ${{ inputs.trivy-severity }} ignore-unfixed: ${{ inputs.trivy-ignore-unfixed }} + # Guarded by `upload-sarif` for the same reason trivy-repo.yml is: uploading + # to code scanning needs GitHub Advanced Security, which private repos on + # the Free plan do not have. Without the guard the step fails with + # "Advanced Security must be enabled for this repository to use code + # scanning" on every push to main, while the scan above passes — a + # permanently red check reporting an entitlement rather than a finding. - name: Trivy scan (SARIF) - if: inputs.run-trivy-scan && inputs.push && github.event_name != 'pull_request' + if: inputs.run-trivy-scan && inputs.push && inputs.upload-sarif && github.event_name != 'pull_request' uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: image-ref: ${{ steps.imageref.outputs.repo }}@${{ steps.build.outputs.digest }} @@ -237,7 +263,7 @@ jobs: ignore-unfixed: ${{ inputs.trivy-ignore-unfixed }} - name: Upload SARIF - if: inputs.run-trivy-scan && inputs.push && github.event_name != 'pull_request' + if: inputs.run-trivy-scan && inputs.push && inputs.upload-sarif && github.event_name != 'pull_request' uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: sarif_file: trivy.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index fceb802..e8ccd5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,33 @@ project uses [SemVer](https://semver.org/) for the `vMAJOR.MINOR.PATCH` tags. ## [Unreleased] +### Added + +- **`docker-build.yml` gained an `upload-sarif` input** (boolean, default + `true`, mirroring the input of the same name on `trivy-repo.yml`). Uploading + a SARIF report to code scanning requires GitHub Advanced Security, which + private repos on the Free plan do not have, so the `Upload SARIF` step failed + with `Advanced Security must be enabled for this repository to use code + scanning` on every push to `main` while the Trivy scan immediately above it + passed. That is a permanently red check reporting an entitlement rather than + a security finding. Consumers on the Free plan pass `upload-sarif: false`; + the SARIF generation step is gated on the same input, so nothing is produced + that cannot be uploaded. Default is `true`, so existing behaviour is + unchanged for anyone who has Advanced Security. + +### Fixed + +- **`docker-build.yml` no longer runs `docker/setup-qemu-action` for + single-architecture builds.** QEMU exists only to emulate a foreign + architecture; the runners are all X64 and `platforms` defaults to + `linux/amd64`, so for most consumers the step installed binfmt handlers that + nothing subsequently used. It is not free: **16m18s** on one observed + `extractor-llm` run, ahead of a build that never needed it, on a three-runner + pool where queueing is the dominant cost. The step is now skipped when + `platforms` is exactly `linux/amd64`. The two consumers that genuinely + cross-build — `scraper-proxy-router` (always) and `store-s3` (on `main`) — + request `linux/arm64` and still get QEMU. + ### Changed - **`claude-code-review.yml` now defaults to a GitHub-hosted runner**