A companion action to security-container-scan that consolidates per-image Grype reports from an entire workflow run into a single summary table.
Follows the same pattern as publish-test-results: the individual scan jobs do not post their own summaries, and this aggregator runs once after all scans complete to produce:
- A single consolidated table in
$GITHUB_STEP_SUMMARYon the aggregator job page - (Optional) a sticky PR comment on
pull-request/NNNbranches created by copy-pr-bot
- Your workflow scans multiple images in one run (typically via matrix or a fan-out of reusable workflow calls) and you want one summary per PR instead of one per image.
- You are OK with the per-image scan jobs also writing their own summary (the default of
security-container-scan). If you do not want that, passwrite-summary: 'false'to eachsecurity-container-scaninvocation.
- Each upstream
security-container-scanjob must upload a per-image artifact whose name matches the pattern passed viaartifact-pattern(defaultgrype-*). The built-in convention isgrype-<service>-<run_id>-<run_attempt>; the aggregator strips those trailing numeric segments to display a clean service name. - Each artifact must contain
grype-results.jsonat its root (this is whatsecurity-container-scanuploads by default). - If
post-pr-comment: trueis used, the caller job must grantpull-requests: writepermission. A defaultGITHUB_TOKENis used unless an override is supplied viagithub-token.
This action only posts PR comments on push events that target the pull-request/NNN branch pattern produced by copy-pr-bot. The native pull_request event is intentionally not supported, matching the policy that all PR CI on these repos must be driven by copy-pr-bot.
On any other ref (main, tags, feat/**, fix/**, etc.) the PR-comment step is a no-op.
jobs:
build-and-scan:
# ... your per-service build job with security-container-scan ...
container-scan-summary:
name: Container Scan Summary
needs: build-and-scan
if: always() # still summarise if some services failed
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # required for post-pr-comment: true
steps:
- uses: NVIDIA/dsx-github-actions/.github/actions/security-container-scan-aggregate@main
with:
post-pr-comment: 'true'- uses: NVIDIA/dsx-github-actions/.github/actions/security-container-scan-aggregate@main
with:
artifact-pattern: 'scan-report-*' # if your callers name artifacts differently
post-pr-comment: 'true'| Input | Description | Required | Default |
|---|---|---|---|
artifact-pattern |
Glob pattern forwarded to actions/download-artifact to pick which artifacts to aggregate. |
No | grype-* |
download-path |
Directory the artifacts are downloaded into. | No | .grype-aggregate |
post-pr-comment |
Post/update a sticky PR comment on copy-pr-bot pull-request/NNN branches. No-op on other refs. |
No | false |
github-token |
Token for listing, creating, and patching PR comments. | No | ${{ github.token }} |
| Output | Description |
|---|---|
summary-path |
Absolute path to the rendered markdown summary file on the runner. |
pr-number |
PR number extracted from a pull-request/NNN ref; empty string on other refs. |
Rendered table columns:
| Service | Total | Critical | High | Medium | Low | Other |
Other merges the Negligible and Unknown severity buckets so the main table stays narrow; detail lives in the per-service artifacts.
By design, the summary contains only severity counts — no CVE IDs, packages, or versions — to avoid turning a public workflow run into an attacker roadmap. Drill-down into the per-service grype-* artifact (JSON + SARIF) is collaborator-only.
The PR comment is marked with the HTML comment <!-- grype-scan-summary --> so successive runs on the same PR update the same comment in place rather than appending new ones. Do not include this marker in other bot comments on the same PR.