From d996dad6ee1ed568b4a28de5e402c3bad2cb9b26 Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 12 Oct 2026 17:13:17 -0600 Subject: [PATCH 1/8] feat: decouple trivy from release to enable multiple image scans Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 84 ++++++++++++++++--- README.md | 22 +++-- actions/discover-ghcr-images/README.md | 31 +++++++ actions/discover-ghcr-images/action.yml | 106 ++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 19 deletions(-) create mode 100644 actions/discover-ghcr-images/README.md create mode 100644 actions/discover-ghcr-images/action.yml diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index dd6a4e6..92be325 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -3,22 +3,25 @@ name: trivy-image-scan -# Reusable workflow that scans an already-built and -pushed container image -# with Trivy. Emits SARIF and uploads it to GitHub Advanced Security so -# findings land in the caller's Security tab. +# Reusable workflow that scans already-pushed container images with Trivy. +# Emits SARIF and uploads it to GitHub Advanced Security so findings land in +# the caller's Security tab. # -# Expects the image to already exist (either in a registry or as a local -# `docker save` tar at `image-path`). To run as a build-time gate inside -# docker-build-release, call this workflow after the build step with the -# fully-qualified `/@` ref. +# Scans the caller's GHCR images at the release tag (the tag that triggered the +# run, the triggering run's tag under `workflow_run`, or `pr-` on pull +# requests), one job per image, by digest. GITHUB_TOKEN can't list packages, so +# image names come from `images`, else the ghcr.io entries in the GoReleaser +# config (`dockers_v2[].images`), else the repository name (see +# actions/discover-ghcr-images). on: workflow_call: inputs: - image-ref: - description: 'Image to scan (e.g., ghcr.io/openchami/foo@sha256:...)' - required: true + images: + description: 'Space- or newline-separated GHCR package names to scan (default: from the GoReleaser config, else the repository name)' + required: false type: string + default: '' severity: description: 'Comma-separated severities to report (default: HIGH,CRITICAL)' required: false @@ -37,11 +40,68 @@ on: permissions: contents: read # baseline for checkout + packages: read # read image versions security-events: write # for SARIF upload to GHAS jobs: + discover: + runs-on: ubuntu-slim + outputs: + images: ${{ steps.images.outputs.images }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Discover images + id: discover + # TODO: pin to the commit that adds actions/discover-ghcr-images + uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@0000000000000000000000000000000000000000 + with: + images: ${{ inputs.images }} + + # TODO: IF: Candidate for deduplication into another reusable action + # IFF another workflow needs image digests. + - name: Find image digests + id: images + env: + GH_TOKEN: ${{ github.token }} + OWNER: ${{ github.repository_owner }} + NAMES: ${{ steps.discover.outputs.names }} + # PR builds are tagged pr- by build-release-goreleaser. + TAG: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.event.workflow_run.head_branch || github.ref_name }} + run: | + set -euo pipefail + registry="ghcr.io/${OWNER,,}" + images='[]' + failed=false + # shellcheck disable=SC2086 # intentional word splitting + for package in $NAMES; do + if ! versions=$(gh api --paginate "/orgs/${OWNER}/packages/container/${package}/versions"); then + echo "::error::Can't read versions of ghcr.io package '${package}'." + failed=true + continue + fi + digest=$(jq -r --arg tag "$TAG" '[.[] | select((.metadata.container.tags // []) | index($tag)) | .name][0] // empty' <<< "$versions") + if [[ -z "$digest" ]]; then + echo "::notice::${package} has no image tagged ${TAG}; skipping" + continue + fi + images=$(jq -c --arg name "${registry}/${package}" --arg digest "$digest" \ + '. + [{name: $name, digest: $digest}]' <<< "$images") + done + [[ "$failed" == false ]] || exit 1 + echo "images=${images}" + echo "images=${images}" >> "$GITHUB_OUTPUT" + trivy: + needs: discover + if: ${{ needs.discover.outputs.images != '[]' }} runs-on: ubuntu-slim + strategy: + fail-fast: false + matrix: + image: ${{ fromJSON(needs.discover.outputs.images) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -50,7 +110,7 @@ jobs: - name: Run Trivy uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: - image-ref: ${{ inputs.image-ref }} + image-ref: ${{ matrix.image.name }}@${{ matrix.image.digest }} format: sarif output: trivy-results.sarif severity: ${{ inputs.severity }} @@ -62,4 +122,4 @@ jobs: uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: sarif_file: trivy-results.sarif - category: trivy-image-scan + category: trivy-image-scan/${{ matrix.image.name }} # one category per image diff --git a/README.md b/README.md index 9899461..e03dc3d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Reusable GitHub Actions for CI/CD. - `actions/gpg-configure-release-keys`: **Deprecated** - use nfpm package signing in `build-release-goreleaser` instead. Generates and certifies a per-run ephemeral GPG key through the repo's release key chain - `actions/gpg-sign-rpm`: **Deprecated** - use nfpm package signing in `build-release-goreleaser` instead. RPM signing with ephemeral keys - `actions/gpg-check-key-expiration`: Fails CI if a signing key is expired or expiring soon +- `actions/discover-ghcr-images`: Finds and verifies a repo's GHCR image names (`images` input, GoReleaser config, or repo name) - `actions/gpg-verify-trust-chain`: **Deprecated** - use the `rpm -K` check in `validate-packages` instead. Verifies the master/repo-cert/ephemeral trust chain and optionally checksigs RPMs - `.github/workflows/go-build-release.yml`: **Deprecated** - use `build-release-goreleaser` (build-only: `build-check-goreleaser`) instead. Reusable workflow for GoReleaser builds - `.github/workflows/docker-build-release.yml`: **Deprecated** - use `build-release-goreleaser` (build-only: `build-check-goreleaser`) instead. Reusable workflow for multi-arch container image builds @@ -331,7 +332,7 @@ jobs: ``` ### trivy-image-scan (Reusable Workflow) -Scans an already-pushed container image with Trivy and uploads SARIF findings to GitHub Advanced Security. Designed to chain after `build-release-goreleaser`. +Scans already-pushed container images with Trivy and uploads SARIF findings to GitHub Advanced Security. It scans each image at the release tag (`pr-` on pull requests), one job per image, by digest. GitHub doesn't let `GITHUB_TOKEN` list packages, so image names come from `images`, else the `ghcr.io` entries in the GoReleaser config (`dockers_v2[].images`), else the repository name (see `discover-ghcr-images`). Every name must be an existing package; all bad names are reported, then the run fails. Run it after `build-release-goreleaser`. **Usage:** ```yaml @@ -342,12 +343,16 @@ jobs: scan: needs: build uses: OpenCHAMI/github-actions/.github/workflows/trivy-image-scan.yml@v4.0 - with: - image-ref: ghcr.io/openchami/foo@ # TODO(#44): scan finds image digests itself - # Optional overrides: - # severity: CRITICAL - # ignore-unfixed: true - # exit-code: '0' # report only + permissions: + contents: read + packages: read + security-events: write + # Optional overrides: + # with: + # images: foo foo-init # default: from the GoReleaser config, else the repo name + # severity: CRITICAL + # ignore-unfixed: true + # exit-code: '0' # report only ``` ### scorecard (Reusable Workflow) @@ -592,6 +597,9 @@ Signs an RPM using a provided GPG fingerprint (works with the ephemeral key outp ### gpg-check-key-expiration Fails CI if the provided signing key is expired or expiring within a threshold. See the [action README](actions/gpg-check-key-expiration/README.md). +### discover-ghcr-images +Finds a repo's GHCR image names from the `images` input, else the GoReleaser config, else the repo name, and verifies each one exists. Used by `trivy-image-scan`. See the [action README](actions/discover-ghcr-images/README.md). + ### gpg-verify-trust-chain (Deprecated) > [!CAUTION] diff --git a/actions/discover-ghcr-images/README.md b/actions/discover-ghcr-images/README.md new file mode 100644 index 0000000..2730af9 --- /dev/null +++ b/actions/discover-ghcr-images/README.md @@ -0,0 +1,31 @@ + + +# discover-ghcr-images + +Finds and verifies the caller's GHCR package names. `GITHUB_TOKEN` can't list an +organization's packages, so names come from exactly one source: + +1. the `images` input, if set +2. else the `ghcr.io` entries in the GoReleaser config's `dockers_v2[].images` + (found the same way GoReleaser finds it) +3. else the repository name, lowercased + +Every name must be an existing package; all bad names are reported, then the +step fails. Check out the repository first, and grant the job `packages: read`. + +```yaml +- uses: actions/checkout@ + with: + persist-credentials: false +- id: discover + uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@ + # with: + # images: foo foo-init +- run: echo "${{ steps.discover.outputs.names }} (from ${{ steps.discover.outputs.source }})" +``` + +Outputs `names` (space-separated, without registry or owner) and `source` +(`input`, `goreleaser`, or `repo`). diff --git a/actions/discover-ghcr-images/action.yml b/actions/discover-ghcr-images/action.yml new file mode 100644 index 0000000..44afa7a --- /dev/null +++ b/actions/discover-ghcr-images/action.yml @@ -0,0 +1,106 @@ +# SPDX-FileCopyrightText: 2026 OpenCHAMI a Series of LF Projects, LLC +# SPDX-License-Identifier: MIT + +name: 'Discover GHCR images' +author: 'OpenCHAMI' +branding: { icon: 'search', color: 'blue' } +description: 'Finds and verifies the GHCR package names for a repository' + +inputs: + images: + description: 'Space- or newline-separated GHCR package names (overrides discovery)' + required: false + default: '' + +outputs: + names: + description: 'Space-separated GHCR package names (without registry or owner)' + value: ${{ steps.verify.outputs.names }} + source: + description: 'Where the names came from: input, goreleaser, or repo' + value: ${{ steps.source.outputs.source }} + +runs: + using: composite + steps: + - name: Select image source + id: source + shell: bash + env: + IMAGES: ${{ inputs.images }} + run: | + set -euo pipefail + config="" + # Same lookup order as GoReleaser itself. + for f in .config/goreleaser.yml .config/goreleaser.yaml .goreleaser.yml .goreleaser.yaml goreleaser.yml goreleaser.yaml; do + [[ -f "$f" ]] && { config=$f; break; } + done + if [[ -n "$IMAGES" ]]; then + source=input + elif [[ -n "$config" ]] && grep -q '^dockers_v2:' "$config"; then + source=goreleaser + else + source=repo + fi + echo "Image names from: ${source}" + { + echo "source=${source}" + echo "config=${config}" + } >> "$GITHUB_OUTPUT" + + - name: Read image names from input + id: input + if: ${{ steps.source.outputs.source == 'input' }} + shell: bash + env: + IMAGES: ${{ inputs.images }} + run: echo "names=$(xargs <<< "$IMAGES")" >> "$GITHUB_OUTPUT" + + - name: Read image names from GoReleaser config + id: goreleaser + if: ${{ steps.source.outputs.source == 'goreleaser' }} + shell: bash + env: + CONFIG: ${{ steps.source.outputs.config }} + run: | + set -euo pipefail + names=$(yq -r '.dockers_v2[].images[] | select(test("^ghcr\\.io/")) | sub("^ghcr\\.io/[^/]+/"; "")' "$CONFIG" | xargs) + if [[ -z "$names" ]]; then + echo "::error::No ghcr.io images in ${CONFIG} dockers_v2. Set the images input." + exit 1 + fi + if [[ "$names" == *"{{"* ]]; then + echo "::error::Templated image names in ${CONFIG} can't be resolved. Set the images input." + exit 1 + fi + echo "names=${names}" >> "$GITHUB_OUTPUT" + + - name: Guess image name from repository + id: repo + if: ${{ steps.source.outputs.source == 'repo' }} + shell: bash + env: + REPO_NAME: ${{ github.event.repository.name }} + run: echo "names=${REPO_NAME,,}" >> "$GITHUB_OUTPUT" + + - name: Check packages exist + id: verify + shell: bash + env: + GH_TOKEN: ${{ github.token }} + OWNER: ${{ github.repository_owner }} + SOURCE: ${{ steps.source.outputs.source }} + NAMES: ${{ steps.input.outputs.names || steps.goreleaser.outputs.names || steps.repo.outputs.names }} + run: | + set -euo pipefail + # shellcheck disable=SC2086 # intentional word splitting + names=$(printf '%s\n' $NAMES | sort -u | xargs) + failed=false + for package in $names; do + if ! gh api "/orgs/${OWNER}/packages/container/${package}" --silent; then + echo "::error::No ghcr.io package '${package}' (name from ${SOURCE}). Set the images input to the right package names." + failed=true + fi + done + [[ "$failed" == false ]] || exit 1 + echo "names=${names}" >> "$GITHUB_OUTPUT" From 47c0b6c21453ed8701959f48511d098d3da0a528 Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Tue, 13 Oct 2026 13:13:58 -0600 Subject: [PATCH 2/8] fix: retrofit stable hash for local action in trivy Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index 92be325..0caf980 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -55,8 +55,7 @@ jobs: - name: Discover images id: discover - # TODO: pin to the commit that adds actions/discover-ghcr-images - uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@0000000000000000000000000000000000000000 + uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@26748ab38b9b17fa895919ef937aca32376a23e2 with: images: ${{ inputs.images }} From 6ec27beead9b3e7939b77ee6d569a61d5eebb333 Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 09:21:05 -0600 Subject: [PATCH 3/8] docs: add output example for actions/discover-ghcr-images Signed-off-by: Sean Tronsen --- actions/discover-ghcr-images/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/actions/discover-ghcr-images/README.md b/actions/discover-ghcr-images/README.md index 2730af9..8ab0e7e 100644 --- a/actions/discover-ghcr-images/README.md +++ b/actions/discover-ghcr-images/README.md @@ -28,4 +28,21 @@ step fails. Check out the repository first, and grant the job `packages: read`. ``` Outputs `names` (space-separated, without registry or owner) and `source` -(`input`, `goreleaser`, or `repo`). +(`input`, `goreleaser`, or `repo`). For example, in `OpenCHAMI/foo` with this +GoReleaser config: + +```yaml +dockers_v2: + - images: + - ghcr.io/openchami/foo + - docker.io/openchami/foo + - images: + - ghcr.io/openchami/foo-init +``` + +the outputs are: + +```text +names=foo foo-init +source=goreleaser +``` From 5fee180a2b761d936ccd3730695b6d79816a363d Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 09:22:54 -0600 Subject: [PATCH 4/8] fix: add missing version comment to discover action call in trivy workflow Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index 0caf980..abae4fe 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -55,7 +55,7 @@ jobs: - name: Discover images id: discover - uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@26748ab38b9b17fa895919ef937aca32376a23e2 + uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@d996dad6ee1ed568b4a28de5e402c3bad2cb9b26 # v4.0 with: images: ${{ inputs.images }} From 808d374fb8f57497583818913921ac05e6bc4a4e Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 09:33:07 -0600 Subject: [PATCH 5/8] fix: ensure trivy checkout uses the revision ref, not the default Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index abae4fe..80781d8 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -51,6 +51,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + # Under workflow_run, github.sha is the default branch; read the built revision's config instead. + ref: ${{ github.event.workflow_run.head_sha || github.sha }} persist-credentials: false - name: Discover images @@ -83,7 +85,8 @@ jobs: fi digest=$(jq -r --arg tag "$TAG" '[.[] | select((.metadata.container.tags // []) | index($tag)) | .name][0] // empty' <<< "$versions") if [[ -z "$digest" ]]; then - echo "::notice::${package} has no image tagged ${TAG}; skipping" + echo "::error::${package} has no image tagged ${TAG}" + failed=true continue fi images=$(jq -c --arg name "${registry}/${package}" --arg digest "$digest" \ @@ -104,6 +107,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + ref: ${{ github.event.workflow_run.head_sha || github.sha }} persist-credentials: false - name: Run Trivy From 1bcb6a89c847927a24c6abcde3b88df4d61f79a0 Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 09:40:10 -0600 Subject: [PATCH 6/8] fix: use url-encoding for package names Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 4 +++- actions/discover-ghcr-images/action.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index 80781d8..be84d9d 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -78,7 +78,9 @@ jobs: failed=false # shellcheck disable=SC2086 # intentional word splitting for package in $NAMES; do - if ! versions=$(gh api --paginate "/orgs/${OWNER}/packages/container/${package}/versions"); then + # Nested package names (tools/foo) need their slash encoded. + encoded=$(jq -rn --arg name "$package" '$name | @uri') + if ! versions=$(gh api --paginate "/orgs/${OWNER}/packages/container/${encoded}/versions"); then echo "::error::Can't read versions of ghcr.io package '${package}'." failed=true continue diff --git a/actions/discover-ghcr-images/action.yml b/actions/discover-ghcr-images/action.yml index 44afa7a..9bb27cb 100644 --- a/actions/discover-ghcr-images/action.yml +++ b/actions/discover-ghcr-images/action.yml @@ -97,7 +97,9 @@ runs: names=$(printf '%s\n' $NAMES | sort -u | xargs) failed=false for package in $names; do - if ! gh api "/orgs/${OWNER}/packages/container/${package}" --silent; then + # Nested package names (tools/foo) need their slash encoded. + encoded=$(jq -rn --arg name "$package" '$name | @uri') + if ! gh api "/orgs/${OWNER}/packages/container/${encoded}" --silent; then echo "::error::No ghcr.io package '${package}' (name from ${SOURCE}). Set the images input to the right package names." failed=true fi From 37fef01b50cab0658ce9ae129bec3aeb55324c83 Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 09:59:35 -0600 Subject: [PATCH 7/8] fix: resolve trivy image tag under workflow_run Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 24 ++++++++++++++++-------- README.md | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index be84d9d..915eafc 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -7,12 +7,12 @@ name: trivy-image-scan # Emits SARIF and uploads it to GitHub Advanced Security so findings land in # the caller's Security tab. # -# Scans the caller's GHCR images at the release tag (the tag that triggered the -# run, the triggering run's tag under `workflow_run`, or `pr-` on pull -# requests), one job per image, by digest. GITHUB_TOKEN can't list packages, so -# image names come from `images`, else the ghcr.io entries in the GoReleaser -# config (`dockers_v2[].images`), else the repository name (see -# actions/discover-ghcr-images). +# Scans the caller's GHCR images at the build's tag (the pushed tag, or `pr-` +# on pull requests; under `workflow_run`, those of the triggering build), one +# job per image, by digest. Fork PRs publish nothing and are skipped. +# GITHUB_TOKEN can't list packages, so image names come from `images`, else the +# ghcr.io entries in the GoReleaser config (`dockers_v2[].images`), else the +# repository name (see actions/discover-ghcr-images). on: workflow_call: @@ -69,10 +69,18 @@ jobs: GH_TOKEN: ${{ github.token }} OWNER: ${{ github.repository_owner }} NAMES: ${{ steps.discover.outputs.names }} - # PR builds are tagged pr- by build-release-goreleaser. - TAG: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.event.workflow_run.head_branch || github.ref_name }} + # Direct trigger, else the build run that triggered this one (workflow_run). + # Fork PRs don't publish images (build-release-goreleaser's SKIP_PUBLISH). + FORK: ${{ (github.event.pull_request.head.repo.full_name || github.event.workflow_run.head_repository.full_name || github.repository) != github.repository }} + # Match build-release-goreleaser's tags: pr- on PRs, else the pushed tag. + TAG: ${{ (github.event_name == 'pull_request' || github.event.workflow_run.event == 'pull_request') && format('pr-{0}', github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number) || github.event.workflow_run.head_branch || github.ref_name }} run: | set -euo pipefail + if [[ "$FORK" == true ]]; then + echo "::notice::Fork PR; no images published, nothing to scan." + echo "images=[]" >> "$GITHUB_OUTPUT" + exit 0 + fi registry="ghcr.io/${OWNER,,}" images='[]' failed=false diff --git a/README.md b/README.md index e03dc3d..5f268c7 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ jobs: ``` ### trivy-image-scan (Reusable Workflow) -Scans already-pushed container images with Trivy and uploads SARIF findings to GitHub Advanced Security. It scans each image at the release tag (`pr-` on pull requests), one job per image, by digest. GitHub doesn't let `GITHUB_TOKEN` list packages, so image names come from `images`, else the `ghcr.io` entries in the GoReleaser config (`dockers_v2[].images`), else the repository name (see `discover-ghcr-images`). Every name must be an existing package; all bad names are reported, then the run fails. Run it after `build-release-goreleaser`. +Scans already-pushed container images with Trivy and uploads SARIF findings to GitHub Advanced Security. It scans each image at the build's tag (the pushed tag, or `pr-` on pull requests; also when run from `workflow_run`), one job per image, by digest. Fork PRs publish no images and are skipped. GitHub doesn't let `GITHUB_TOKEN` list packages, so image names come from `images`, else the `ghcr.io` entries in the GoReleaser config (`dockers_v2[].images`), else the repository name (see `discover-ghcr-images`). Every name must be an existing package; all bad names are reported, then the run fails. Run it after `build-release-goreleaser`. **Usage:** ```yaml From dfb5b936f042dfab0d6cff1fa9d1f6a1b8a656ad Mon Sep 17 00:00:00 2001 From: Sean Tronsen Date: Mon, 19 Oct 2026 10:07:39 -0600 Subject: [PATCH 8/8] chore: update sha pinning Signed-off-by: Sean Tronsen --- .github/workflows/trivy-image-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trivy-image-scan.yml b/.github/workflows/trivy-image-scan.yml index 915eafc..043f4e9 100644 --- a/.github/workflows/trivy-image-scan.yml +++ b/.github/workflows/trivy-image-scan.yml @@ -57,7 +57,7 @@ jobs: - name: Discover images id: discover - uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@d996dad6ee1ed568b4a28de5e402c3bad2cb9b26 # v4.0 + uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@1bcb6a89c847927a24c6abcde3b88df4d61f79a0 # v4.0 with: images: ${{ inputs.images }}