From e1963ffe3c973d3e9e6f3a95316f5c6a3f83cc0e Mon Sep 17 00:00:00 2001 From: Bernhard Windisch Date: Tue, 21 Jul 2026 17:54:02 +0200 Subject: [PATCH] fix(ci): pin Trivy scan to the matrix platform so the arm64 release gate passes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first real run of the signed release pipeline (v0.7.0) failed: the arm64 build's Trivy scan errored with 'no child with platform linux/amd64 in index', which skipped the release gate and therefore ALL publishing (NuGet, Docker, docs, signing). Nothing shipped. Root cause: on a real release the build pushes by digest with SBOM + provenance (mode=max), so buildx wraps each single-arch image in an index (the image manifest plus attestation manifests). Given an index reference, Trivy resolves to its default platform linux/amd64 regardless of the runner architecture — so the arm64 job (on a native arm64 runner) asked for a linux/amd64 child that an arm64-only index does not contain. The amd64 job passed only because its default happened to match. The dry-run never caught this: it loads a single-platform image into the local daemon (type=docker, no attestations, no index), a different code path than the pushed-by-digest index the real release scans. Fix: set TRIVY_PLATFORM to the matrix platform so each job scans its own arch. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/cd-release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/cd-release.yml b/.github/workflows/cd-release.yml index e45da4d1..cdda5180 100644 --- a/.github/workflows/cd-release.yml +++ b/.github/workflows/cd-release.yml @@ -266,6 +266,16 @@ jobs: # so both platforms' package sets are actually scanned. - name: Scan image (Trivy — blocks release on fixable CRITICAL/HIGH) uses: aquasecurity/trivy-action@v0.36.0 + # Pin the platform to this arch. On a real release the build pushes + # by digest with SBOM + provenance (mode=max), so buildx wraps the + # single-arch image in an index (image manifest + attestation + # manifests). Given an index, Trivy resolves to its default platform + # linux/amd64 REGARDLESS of the runner arch — so the arm64 job asked + # for a linux/amd64 child that an arm64-only index doesn't have and + # failed ("no child with platform linux/amd64 in index"). amd64 passed + # only by coincidence. TRIVY_PLATFORM makes each job scan its own arch. + env: + TRIVY_PLATFORM: ${{ matrix.platform }} with: image-ref: ${{ (github.event_name == 'release' || !inputs.dry_run) && format('{0}/{1}@{2}', env.REGISTRY, env.IMAGE_NAME, steps.build.outputs.digest) || 'modgud:trivy-scan' }} format: table