Repository navigation
feat(workflows)!: step 4, scan every published image with Trivy - #44
seantronsen wants to merge 2 commits into
Conversation
|
Tests: OpenCHAMI/github-actions-testbed#7 (the testbed |
271fd5e to
e249218
Compare
e249218 to
3f48376
Compare
|
Conflicts to be resolved if/when #41 is merged. |
|
Will review once this is rebased. |
Signed-off-by: Sean Tronsen <sean.tronsen@gmail.com>
Signed-off-by: Sean Tronsen <sean.tronsen@gmail.com>
3f48376 to
47c0b6c
Compare
done |
| Outputs `names` (space-separated, without registry or owner) and `source` | ||
| (`input`, `goreleaser`, or `repo`). |
There was a problem hiding this comment.
Can we add a concrete example of what the output would look like?
|
|
||
| - name: Discover images | ||
| id: discover | ||
| uses: OpenCHAMI/github-actions/actions/discover-ghcr-images@26748ab38b9b17fa895919ef937aca32376a23e2 |
There was a problem hiding this comment.
No version comment here yet?
There was a problem hiding this comment.
Good catch, thanks!
Should one be there? Yes absolutely!
Why isn't it there? Pinning a SHA ref requires a commit to pin it to, meaning I had to commit the feature first, then do another commit and switch a zeros todo hash with a proper hash.
I will fix this tomorrow.
| OWNER: ${{ github.repository_owner }} | ||
| NAMES: ${{ steps.discover.outputs.names }} | ||
| # PR builds are tagged pr-<N> 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 }} |
There was a problem hiding this comment.
When this workflow is called by a workflow_run handler after a PR build, github.event_name is workflow_run, so this expression selects workflow_run.head_branch. The build publishes pr-<N>, not the branch name. Consequently, discovery finds no digest, outputs [], and skips every Trivy job while leaving the workflow successful.
Essentially, the scanner confuses the event that started the scanner with the event that started the build.
When scanning in the same caller workflow:
pull_request #44 → build publishes pr-44 → scan selects pr-44
When scanning in a separate workflow:
pull_request #44 → build publishes pr-44
→ workflow_run starts scanner
→ scan selects seantronsen/feat/decouple-trivy
Evidence: This PR's build run (https://github.com/OpenCHAMI/github-actions/actions/runs/38472346439) returns:
{
"event": "pull_request",
"head_branch": "seantronsen/feat/decouple-trivy",
"pull_requests": [44]
}This expression only recognizes a direct pull_request event. For workflow_run, it takes head_branch, which identifies the source branch. The build workflow's tagging convention is pr-44, so the lookup searches for the wrong image tag. The missing tag produces a notice, discovery returns an empty matrix, and the scan job is skipped.
One way to address this is to first resolve the image tag explicitly before looking up digests. Add an optional image-tag input and use this precedence:
| Situation | Tag to use |
|---|---|
Caller supplies image-tag |
Use it |
Direct pull_request event |
pr-<pull_request.number> |
workflow_run from a PR build |
pr-<associated PR number> |
| Direct tag push | ${{ github.ref_name }} |
| Anything else or ambiguous metadata | Fail with a useful error |
An explicit input also gives callers a reliable way to handle release builds or custom tagging conventions.
Second, make missing expected images fail discovery. The existing missing-digest branch can change from:
echo "::notice::${package} has no image tagged ${TAG}; skipping"
continueto:
echo "::error::${package} has no image tagged ${TAG}"
failed=true
continueThe existing final check then fails discovery after reporting all missing images:
[[ "$failed" == false ]] || exit 1| 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 |
There was a problem hiding this comment.
Just for extra safety, we'll need to URL-encode the package name before inserting it into the API path. Discovery preserves nested names such as tools/foo, but this request turns the slash into another path segment. That causes verification to reject an existing nested GHCR package.
We'll also need to address that here too:
We can actually use jq to do this:
encoded_package=$(jq -rn --arg name "$package" '$name | @uri')Then pass this variable to gh api:
gh api "/orgs/${OWNER}/packages/container/${encoded_package}" --silent
gh api --paginate "/orgs/${OWNER}/packages/container/${encoded_package}/versions"| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false |
There was a problem hiding this comment.
Shouldn't we specify which ref to checkout here? I think this might read the default branch's config instead of the build revision's config.
Description
Decouples Trivy image scanning from the build workflows so repos that publish more than one image get every image scanned, without passing outputs between workflows.
trivy-image-scan: finds image names with the newactions/discover-ghcr-imagesaction (theimagesinput, else theghcr.ioentries in the GoReleaser config, else the repo name), verifies they exist, and scans each one at the release tag (pr-<N>on PRs), one job per image, with a SARIF category per image.GITHUB_TOKENcan't list packages, hence the name sources.image-refinput; callers grantpackages: readinstead.Checklist
make test(or equivalent) locally and all tests passgit commit -s) with my real name and email<filename>.licensesidecarLICENSES/directoryType of Change