From fa6d59a2131f34e366baddf21bd78728f37cdbda Mon Sep 17 00:00:00 2001 From: Neil Galvin Date: Fri, 18 Sep 2026 21:52:56 +0100 Subject: [PATCH] fix(trivy-repo): install Trivy explicitly so setup failures name themselves trivy-action installs Trivy and immediately scans in one step, so a setup that half-works surfaces as entrypoint.sh: line 88: trivy: command not found Process completed with exit code 127 from the scan, naming neither the cause nor the step responsible. Not hypothetical. On a self-hosted runner actions/cache restored the binary to /home/runner/.local/bin/trivy-bin, logged "Cache restored successfully", ran the $GITHUB_PATH step -- and the binary still was not there. That host had a doubled /home/runner/runner/_work layout while its sibling in the SAME run had /home/runner/_work. The pool is not uniform and the cached path derives from that layout, so the restore reported success while putting the binary somewhere PATH never looked. Now installed by an explicit setup-trivy step with `cache: false`, and `trivy --version` proves it before any scan runs. That trades a ~45MB download per run for a restore path that cannot silently no-op, and moves the failure to setup where it says what broke. setup-trivy is pinned to v0.2.6 deliberately -- the exact SHA trivy-action@0.36.0 pins internally -- so the explicit step installs what the action would have installed itself. Verified the SHA against the upstream tag list rather than trusting the comment I first wrote, which said v0.2.3 and was wrong. Applied to both the table-scan and SARIF jobs; they shared the failure mode, and only one being fixed would have been worse than neither. Also adds a `trivy-version` input (default v0.70.0) so the binary is pinned rather than tracking whatever upstream moves to. actionlint clean. --- .github/workflows/trivy-repo.yml | 69 ++++++++++++++++++++++++++++++++ CHANGELOG.md | 26 ++++++++++++ 2 files changed, 95 insertions(+) diff --git a/.github/workflows/trivy-repo.yml b/.github/workflows/trivy-repo.yml index 6589739..5738ef6 100644 --- a/.github/workflows/trivy-repo.yml +++ b/.github/workflows/trivy-repo.yml @@ -76,6 +76,13 @@ on: description: "Pinned version of aquasecurity/trivy-action" type: string default: "0.36.0" + trivy-version: + description: | + Trivy binary version installed by the explicit setup step. Pinned + rather than left to the action's own default so a scan cannot start + reporting differently because upstream moved. + type: string + default: "v0.70.0" timeout-minutes: type: number default: 15 @@ -100,9 +107,41 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + # Install Trivy explicitly, with the binary cache OFF, and prove it + # landed before anything tries to scan with it. + # + # trivy-action installs Trivy itself and immediately scans, so a setup + # that half-works surfaces as `trivy: command not found` (exit 127) from + # the scan, naming neither the cause nor the step responsible. That is + # not hypothetical: it was hit on a self-hosted runner where + # actions/cache restored the binary to /home/runner/.local/bin/trivy-bin + # and reported "Cache restored successfully", the PATH step ran, and the + # binary still was not there. The host had a doubled + # /home/runner/runner/_work layout where its sibling in the same run had + # /home/runner/_work -- the pool is not uniform, and the cached path is + # derived from that layout. + # + # `cache: false` trades a ~45MB download per run for a restore path that + # cannot silently no-op. `trivy --version` then fails AT SETUP, loudly, + # instead of as a mystery 127 mid-scan. + - name: Install Trivy + # v0.2.6 deliberately, not the newer v0.3.x: this is the exact SHA + # trivy-action@0.36.0 pins internally, so the explicit step installs + # what the action would have installed itself. Bump the two together. + uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 # v0.2.6 + with: + version: ${{ inputs.trivy-version }} + cache: false + + - name: Verify Trivy is on PATH + run: trivy --version + - name: Trivy scan (table) uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: + # Setup already happened above, verified. Letting the action do it + # again would restore the same unreliable cache path. + skip-setup-trivy: true scan-type: ${{ inputs.scan-type }} scan-ref: ${{ inputs.scan-ref }} format: table @@ -157,9 +196,39 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + # Install Trivy explicitly, with the binary cache OFF, and prove it + # landed before anything tries to scan with it. + # + # trivy-action installs Trivy itself and immediately scans, so a setup + # that half-works surfaces as `trivy: command not found` (exit 127) from + # the scan, naming neither the cause nor the step responsible. That is + # not hypothetical: it was hit on a self-hosted runner where + # actions/cache restored the binary to /home/runner/.local/bin/trivy-bin + # and reported "Cache restored successfully", the PATH step ran, and the + # binary still was not there. The host had a doubled + # /home/runner/runner/_work layout where its sibling in the same run had + # /home/runner/_work -- the pool is not uniform, and the cached path is + # derived from that layout. + # + # `cache: false` trades a ~45MB download per run for a restore path that + # cannot silently no-op. `trivy --version` then fails AT SETUP, loudly, + # instead of as a mystery 127 mid-scan. + - name: Install Trivy + # v0.2.6 deliberately, not the newer v0.3.x: this is the exact SHA + # trivy-action@0.36.0 pins internally, so the explicit step installs + # what the action would have installed itself. Bump the two together. + uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 # v0.2.6 + with: + version: ${{ inputs.trivy-version }} + cache: false + + - name: Verify Trivy is on PATH + run: trivy --version + - name: Trivy scan (SARIF) uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: + skip-setup-trivy: true scan-type: ${{ inputs.scan-type }} scan-ref: ${{ inputs.scan-ref }} format: sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index 98080cc..f099acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,32 @@ project uses [SemVer](https://semver.org/) for the `vMAJOR.MINOR.PATCH` tags. ### Fixed +- `trivy-repo.yml` — install Trivy in an explicit, verified step instead of + letting `trivy-action` do it inline, and pass `skip-setup-trivy: true`. + + `trivy-action` installs Trivy and immediately scans, so a setup that + half-works surfaces as `trivy: command not found` (exit 127) from the scan, + naming neither the cause nor the step responsible. Hit on a self-hosted + runner where `actions/cache` restored the binary to + `/home/runner/.local/bin/trivy-bin`, logged *"Cache restored successfully"*, + ran the `$GITHUB_PATH` step — and the binary still was not there. That host + had a doubled `/home/runner/runner/_work` layout while its sibling in the + same run had `/home/runner/_work`; the pool is not uniform and the cached + path derives from that layout. + + The new step sets `cache: false`, trading a ~45MB download per run for a + restore path that cannot silently no-op, and `trivy --version` then fails at + setup, loudly, rather than as a mystery 127 mid-scan. Applied to both the + table-scan and SARIF jobs, which shared the failure mode. + +### Added + +- `trivy-repo.yml` — `trivy-version` input (string, default `v0.70.0`), + pinning the Trivy binary the new setup step installs so a scan cannot start + reporting differently because upstream moved. + +### Fixed + - **`auto-revert-on-main-failure.yml` no longer fails outright when the bad commit touched a workflow file.** It pushes with `GITHUB_TOKEN`, which GitHub categorically forbids from creating or updating anything under