From 2365001aca322a9a1071f484972cdb44189a16e5 Mon Sep 17 00:00:00 2001 From: Haksung Jang Date: Tue, 7 Jul 2026 11:04:52 +0900 Subject: [PATCH 1/3] fix(ci): install Trivy from a pinned release asset in the SCA self-scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nightly SCA self-scan has failed at the "Install Trivy" step on every run for over a week, leaving the README badge red — with no CVE involved. Root cause: aquasecurity/setup-trivy@v0.2.6 fetches Trivy's contrib/install.sh from Trivy's default branch (a MOVING ref) and executes it. Trivy commit 75c4dc0 ("add client option to install script", #9962) changed that script, breaking the invocation the pinned action makes — the step exits 1 immediately after resolving v0.58.0. This is the second breakage of the same class (the curl | sh installer broke the same way in 2026-05, which is why we moved to the action). Fix the class, not the instance: download the pinned Trivy release tarball directly and verify it with `sha256sum -c` against the published checksums file. No moving ref, no GitHub-API tag lookup / rate-limit surface, and it matches the supply-chain integrity posture TRUSCA itself ships. Verified the grep + `sha256sum -c` pipeline isolates the correct asset line and rejects a tampered file; YAML + actionlint clean. --- .github/workflows/sca-self.yml | 43 ++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sca-self.yml b/.github/workflows/sca-self.yml index 4fffde0a..ac7d4fdb 100644 --- a/.github/workflows/sca-self.yml +++ b/.github/workflows/sca-self.yml @@ -79,16 +79,39 @@ jobs: run: cdxgen -r --no-validate -o sbom.cdx.json . # Trivy is bundled into the worker image at apps/backend/Dockerfile.worker; - # for this workflow we install the standalone CLI via the official - # setup-trivy action (smaller, faster than spinning up the worker - # image just to run trivy sbom, and more reliable than the curl | - # sh installer which started returning non-zero on a clean fetch - # in May 2026). - - name: Install Trivy - uses: aquasecurity/setup-trivy@v0.2.6 - with: - version: v0.58.0 - cache: true + # for this workflow we install the standalone CLI directly from a PINNED + # release asset and verify its checksum. This is deliberately NOT the + # `curl | sh` installer NOR the `aquasecurity/setup-trivy` action — both + # of those execute Trivy's `contrib/install.sh` fetched from a MOVING ref + # (Trivy's default branch), so a change to that script breaks this job + # with no change on our side. That has now happened twice: + # * 2026-05 — the `curl | sh` installer began returning non-zero on a + # clean fetch (we then switched to setup-trivy). + # * 2026-07 — setup-trivy@v0.2.6 broke after Trivy commit 75c4dc0 + # ("add client option to install script", #9962) changed install.sh, + # failing every nightly at the install step (exit 1 right after the + # version resolved) — unrelated to any CVE finding. + # Downloading the pinned tarball + `sha256sum -c` removes the moving-ref + # dependency entirely (and drops the GitHub-API tag lookup, so no rate + # limit surface), which also matches the supply-chain-integrity posture + # TRUSCA itself ships. Bump TRIVY_VERSION deliberately when upgrading. + - name: Install Trivy (pinned release asset + checksum) + env: + TRIVY_VERSION: "0.58.0" + run: | + set -euo pipefail + base="https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}" + tarball="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" + checksums="trivy_${TRIVY_VERSION}_checksums.txt" + # Download to the CANONICAL asset names — `sha256sum -c` verifies the + # file named in the checksum line, so the on-disk name must match. + curl -fsSL -o "$tarball" "${base}/${tarball}" + curl -fsSL -o "$checksums" "${base}/${checksums}" + grep " ${tarball}\$" "$checksums" | sha256sum -c - + tar -xzf "$tarball" trivy + sudo install -m 0755 trivy /usr/local/bin/trivy + rm -f "$tarball" "$checksums" trivy + trivy --version - name: Trivy SBOM scan (CRITICAL + HIGH) # --exit-code 0 — never fail the JOB on findings; the parse step From 33178ac34b9b8a2a9cd5fb5a049f7b93d0fcda20 Mon Sep 17 00:00:00 2001 From: Haksung Jang Date: Tue, 7 Jul 2026 11:09:34 +0900 Subject: [PATCH 2/3] fix(ci): resolve Trivy asset names via API instead of guessing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first attempt hard-coded trivy__Linux-64bit.tar.gz, which 404s for v0.58.0 — Trivy's asset naming has varied. Enumerate the immutable pinned release's assets via the API (token-auth, no rate limit) and match the Linux amd64 tarball + checksums by pattern, then verify with sha256sum -c. Still fully pinned on TRIVY_VERSION; no moving ref, no filename guess. --- .github/workflows/sca-self.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sca-self.yml b/.github/workflows/sca-self.yml index ac7d4fdb..844ff347 100644 --- a/.github/workflows/sca-self.yml +++ b/.github/workflows/sca-self.yml @@ -98,15 +98,28 @@ jobs: - name: Install Trivy (pinned release asset + checksum) env: TRIVY_VERSION: "0.58.0" + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail - base="https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}" - tarball="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" - checksums="trivy_${TRIVY_VERSION}_checksums.txt" - # Download to the CANONICAL asset names — `sha256sum -c` verifies the - # file named in the checksum line, so the on-disk name must match. - curl -fsSL -o "$tarball" "${base}/${tarball}" - curl -fsSL -o "$checksums" "${base}/${checksums}" + tag="v${TRIVY_VERSION}" + # Resolve the exact asset names from the API rather than hard-coding + # them: a published release is IMMUTABLE (deterministic) and the token + # auth avoids the anon rate limit, but Trivy's asset naming has varied + # (Linux-64bit vs linux_amd64), so enumerate and match instead of + # guessing. This keeps the pin on TRIVY_VERSION while removing both the + # moving-ref install.sh AND the filename-guess fragility. + names="$(gh api "repos/aquasecurity/trivy/releases/tags/${tag}" --jq '.assets[].name')" + tarball="$(printf '%s\n' "$names" | grep -iE 'Linux[-_](64bit|amd64)\.tar\.gz$' | head -1)" + checksums="$(printf '%s\n' "$names" | grep -iE 'checksums\.txt$' | head -1)" + if [ -z "$tarball" ] || [ -z "$checksums" ]; then + echo "::error::could not resolve Trivy ${tag} assets (tarball='$tarball' checksums='$checksums')" + printf '%s\n' "$names" + exit 1 + fi + gh release download "$tag" --repo aquasecurity/trivy \ + --pattern "$tarball" --pattern "$checksums" --clobber + # `sha256sum -c` verifies the file named in the checksum line, so the + # on-disk name must match the enumerated asset name (it does). grep " ${tarball}\$" "$checksums" | sha256sum -c - tar -xzf "$tarball" trivy sudo install -m 0755 trivy /usr/local/bin/trivy From 5577a968f0fb1e10ff969238305c4c191ae46774 Mon Sep 17 00:00:00 2001 From: Haksung Jang Date: Tue, 7 Jul 2026 11:14:45 +0900 Subject: [PATCH 3/3] fix(ci): pin SCA self-scan Trivy to 0.72.0 deb (matches worker image) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real root cause: the previously pinned Trivy v0.58.0 GitHub *release* was removed upstream — the git tag remains but its assets 404, so both setup-trivy (which resolved 0.58.0 then failed to download it) and the direct-download attempt failed. Trivy is now at 0.72.0. Install the exact version the worker image ships (0.72.0) from the upstream per-arch .deb, verified against the SHA-256 already vetted in apps/backend/Dockerfile.worker. No runtime version resolution, no moving ref, and the self-scan now dog-foods the same scanner end users run. --- .github/workflows/sca-self.yml | 63 ++++++++++++---------------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/.github/workflows/sca-self.yml b/.github/workflows/sca-self.yml index 844ff347..b6705c2c 100644 --- a/.github/workflows/sca-self.yml +++ b/.github/workflows/sca-self.yml @@ -78,52 +78,33 @@ jobs: FETCH_LICENSE: "true" run: cdxgen -r --no-validate -o sbom.cdx.json . - # Trivy is bundled into the worker image at apps/backend/Dockerfile.worker; - # for this workflow we install the standalone CLI directly from a PINNED - # release asset and verify its checksum. This is deliberately NOT the - # `curl | sh` installer NOR the `aquasecurity/setup-trivy` action — both - # of those execute Trivy's `contrib/install.sh` fetched from a MOVING ref - # (Trivy's default branch), so a change to that script breaks this job - # with no change on our side. That has now happened twice: + # Install the SAME pinned Trivy the worker image ships + # (apps/backend/Dockerfile.worker), from the upstream per-arch .deb with the + # SHA-256 that file already vets. Deliberately NOT `curl | sh` and NOT + # `aquasecurity/setup-trivy`: both resolve Trivy at RUNTIME and this step + # has broken twice on that — # * 2026-05 — the `curl | sh` installer began returning non-zero on a # clean fetch (we then switched to setup-trivy). - # * 2026-07 — setup-trivy@v0.2.6 broke after Trivy commit 75c4dc0 - # ("add client option to install script", #9962) changed install.sh, - # failing every nightly at the install step (exit 1 right after the - # version resolved) — unrelated to any CVE finding. - # Downloading the pinned tarball + `sha256sum -c` removes the moving-ref - # dependency entirely (and drops the GitHub-API tag lookup, so no rate - # limit surface), which also matches the supply-chain-integrity posture - # TRUSCA itself ships. Bump TRIVY_VERSION deliberately when upgrading. - - name: Install Trivy (pinned release asset + checksum) + # * 2026-07 — setup-trivy@v0.2.6 pinned Trivy v0.58.0, whose GitHub + # *release* was later removed upstream (assets 404, though the git tag + # remains). The action "found version 0.58.0" via the tags API then + # failed downloading the vanished asset — red every nightly, no CVE + # involved. + # A pinned .deb + `sha256sum -c` has no moving ref and no version-resolution + # step, and dog-foods the EXACT scanner end users get. ubuntu-2x runners are + # amd64 → Linux-64bit. Keep TRIVY_VERSION and the SHA in lockstep with + # Dockerfile.worker when bumping (the image-scan gate drives those bumps). + - name: Install Trivy (pinned deb, checksum-verified — matches worker image) env: - TRIVY_VERSION: "0.58.0" - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TRIVY_VERSION: "0.72.0" + TRIVY_SHA256_AMD64: 9bf8aba92f524b74f8e83d53b298a7dfc6b4d60aca779217e7817e5433c73eeb run: | set -euo pipefail - tag="v${TRIVY_VERSION}" - # Resolve the exact asset names from the API rather than hard-coding - # them: a published release is IMMUTABLE (deterministic) and the token - # auth avoids the anon rate limit, but Trivy's asset naming has varied - # (Linux-64bit vs linux_amd64), so enumerate and match instead of - # guessing. This keeps the pin on TRIVY_VERSION while removing both the - # moving-ref install.sh AND the filename-guess fragility. - names="$(gh api "repos/aquasecurity/trivy/releases/tags/${tag}" --jq '.assets[].name')" - tarball="$(printf '%s\n' "$names" | grep -iE 'Linux[-_](64bit|amd64)\.tar\.gz$' | head -1)" - checksums="$(printf '%s\n' "$names" | grep -iE 'checksums\.txt$' | head -1)" - if [ -z "$tarball" ] || [ -z "$checksums" ]; then - echo "::error::could not resolve Trivy ${tag} assets (tarball='$tarball' checksums='$checksums')" - printf '%s\n' "$names" - exit 1 - fi - gh release download "$tag" --repo aquasecurity/trivy \ - --pattern "$tarball" --pattern "$checksums" --clobber - # `sha256sum -c` verifies the file named in the checksum line, so the - # on-disk name must match the enumerated asset name (it does). - grep " ${tarball}\$" "$checksums" | sha256sum -c - - tar -xzf "$tarball" trivy - sudo install -m 0755 trivy /usr/local/bin/trivy - rm -f "$tarball" "$checksums" trivy + url="https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.deb" + curl -fsSL -o /tmp/trivy.deb "$url" + echo "${TRIVY_SHA256_AMD64} /tmp/trivy.deb" | sha256sum -c - + sudo dpkg -i /tmp/trivy.deb + rm -f /tmp/trivy.deb trivy --version - name: Trivy SBOM scan (CRITICAL + HIGH)