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