Skip to content

chore(ci): scan released images with Trivy - #8162

Merged
Vligai merged 6 commits into
mainfrom
chore/trivy-release-image-scan
Sep 18, 2026
Merged

Vligai merged 6 commits into
mainfrom
chore/trivy-release-image-scan

Conversation

@Vligai

@Vligai Vligai commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Context

This adds a Trivy scan of each published image. Fixable CRITICAL and HIGH findings go to this repo's code scanning, under Security -> Code scanning filtered by tool "Trivy".

The scan cannot fail a release. It is continue-on-error with exit-code: 0, the upload is gated on the scan having succeeded, and if either step fails the job emits a warning annotation. The image is already pushed by the time these steps run, so a red job would flag the problem too late to prevent it.

Most of the choices below are hard to read off the diff:

  • Scans by digest. The build steps now carry an id, and the scan targets image@${{ steps.build.outputs.digest }}. Scanning by tag leaves a window where the report could describe something else.
  • Both the action and the scanner are pinned. The action is pinned by commit SHA like everything else in this file. The Trivy binary is pinned separately through TRIVY_VERSION, because the action's own default lags it (v0.70.0 at the pinned SHA).
  • Results upload to refs/heads/main. This workflow runs only on tag pushes, and the code scanning alerts UI is scoped to branches, so results left on refs/tags/* land where nobody reads them and never reconcile against the next release. This assumes release tags are cut from main. A tag that is not gets rejected by the API, and the guard step reports it.
  • The SARIF category carries the release channel. Code scanning reconciles per (ref, category), closing any alert the newest analysis omits. Nightlies share this trigger and this ref, so without the suffix tonight's nightly would close the alerts describing the stable image users are running.
  • amd64 only. Both images publish amd64 and arm64, but the OS packages are pinned to identical versions for both arches (Dockerfile.standalone-infisical:226-243), and Debian advisories match on package version, so arm64's findings are amd64's. Scanning both mostly produces duplicate alerts to dismiss twice.
  • ignore-unfixed: true keeps the list to what can be acted on, which is what the Debian pin refreshes in the Dockerfiles already do.
  • The vulnerability DB comes from the ECR mirror. Trivy defaults to GHCR, which rate-limits anonymous pulls from the shared Actions egress IPs.

Screenshots

Not applicable, CI only.

Steps to verify the change

Static, runnable now:

  1. actionlint .github/workflows/release-standalone-docker-img-postgres-offical.yml reports only the four issues that predate this change: two deprecated ::set-output calls and two steps.version.* references to a step that does not exist.
  2. The workflow parses and all five jobs survive, including infisical-fips-standalone, which generate-upgrade-impact depends on.
  3. The pinned SHAs resolve to their claimed tags. aquasecurity/trivy-action@ed142fd is v0.36.0 and github/codeql-action@b96794f is v4.38.0.
  4. Every with: key exists in trivy-action's action.yaml at the pinned SHA. limit-severities-for-sarif matters most, since severity does not apply to SARIF output without it.

On the next tag, after merge:

  1. Both build jobs show a scan step and an upload step, and the job is green whatever the scan found.
  2. Security -> Code scanning lists analyses under trivy-infisical-core and trivy-infisical-fips, attributed to main.
  3. A nightly tag lands under the -nightly categories and leaves the stable alerts open.
  4. For the failure path, point image-ref at a nonexistent digest on a branch build. The scan should fail, the upload should be skipped, the job should stay green, and the run should carry a warning annotation.

Type

  • Fix
  • Feature
  • Improvement
  • Breaking
  • Docs
  • Chore

Checklist

  • Title follows the conventional commit format: type(scope): short description (scope is optional, e.g., fix: prevent crash on sync or fix(api): handle null response).
  • Tested locally
  • Updated docs (if needed)
  • Updated CLAUDE.md files (if needed)
  • Read the contributing guide

Adds a non-blocking Trivy scan of each image the release pipeline
publishes, reporting fixable CRITICAL and HIGH findings to code
scanning. Runs alongside the existing Snyk monitor step.

Both the action and the scanner binary are pinned, the latter because
the action's own default lags. Each image is scanned by the digest the
build just produced rather than by tag, so the report cannot describe
something other than what was released.

Nothing here can fail a release: the scan is continue-on-error with
exit-code 0, the upload is gated on the scan succeeding, and a failure
of either emits a warning annotation rather than passing silently.

Two details that are easy to get wrong. Results upload to refs/heads/main
because this workflow only runs on tag pushes and the alerts UI is scoped
to branches, so results left on refs/tags/* would land where nobody reads
them. And the category carries the release channel, because code scanning
reconciles per (ref, category) by closing any alert the newest analysis
omits, which would let a nightly close the alerts describing the stable
image users are running.

arm64 is published but deliberately not scanned. The OS packages are
pinned to the same versions for both arches and Debian advisories match
on version rather than arch, so its findings are amd64's.
@infisical-review-police

Copy link
Copy Markdown

💬 Discussion in Slack: #pr-review-infisical-8162-chore-ci-scan-released-images-with-trivy

Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel.

@greptile-apps

greptile-apps Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The PR should not merge until released-image findings are sent to a durable reporting system rather than retained only as expiring workflow artifacts.

Findings

  1. P1 Vulnerability Alerts Become Temporary ▶
Summary

This PR adds digest-pinned Trivy scans for the released core and FIPS container images.

  • Pins the Trivy action and CLI versions and scans the amd64 manifests.
  • Retains JSON reports as workflow artifacts and writes vulnerability counts to job summaries.
  • Keeps scan and upload failures non-blocking while emitting warning annotations.
  • The latest revision removes the SARIF Code scanning integration, leaving no durable consumer for the generated reports.

Reviews (2) · Last reviewed commit: "chore(ci): keep Trivy findings inside th..."

Replaces the code scanning upload with a JSON report retained as a run
artifact, so nothing leaves the pipeline ahead of the secure portal
ingestion work that will consume these reports.

JSON rather than SARIF because it is Trivy's richest format, carrying
CVSS vectors per vendor, installed and fixed versions, layer attribution
and PURLs. `trivy convert` regenerates SARIF or a table from a stored
report offline, so nothing is foreclosed and no rescan is needed to
change format later.

Two consequences worth noting. The security-events permission is gone
from both jobs, and with the SARIF upload go the category and ref
semantics it needed, including the nightly channel suffix and the
assumption that release tags are cut from main.

Since nothing here touches job status, a report nobody opens would make
a release shipping twenty criticals look identical to a clean one. Each
job now writes its counts to the job summary and raises a warning
annotation when the count is non-zero.

The scanner pin moves out of Trivy's own TRIVY_* environment namespace,
where a workflow-level variable of that name would otherwise sit.

The artifact holds fixable findings only, since ignore-unfixed filters
the rest, and the comment says so rather than calling it a record of
everything the release shipped.
@Vligai

Vligai commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment thread .github/workflows/release-standalone-docker-img-postgres-offical.yml Outdated
Comment thread .github/workflows/release-standalone-docker-img-postgres-offical.yml Outdated
Addresses review feedback on #8162.

The scan, artifact upload and summary were duplicated between the core
and FIPS jobs, differing only in the image name. They move to
.github/actions/trivy-image-scan, alongside the existing
generate-openapi-spec action, so the scan configuration is defined once
and each job is left with a call and a guard.

The DB repository override was a regression. Trivy already defaults to
the GCR mirror followed by GHCR and falls back between them, but only
for temporary transport errors, which is what a rate limit is
(pkg/oci/artifact.go, shouldTryOtherRepo). Pointing the override at a
single ECR repository replaced that with one point of failure, and the
comment justifying it was wrong: GHCR is the fallback in this version,
not the default. ECR now sits in front of both rather than in place of
them.

The guard also missed the summary step, so a summary that failed left no
trace. Collapsing the three steps behind one composite call means any
failure inside it, scan, upload or summary alike, surfaces as that
step's outcome, and there is no longer a condition to keep in sync as
steps are added.

Reports are still kept in the pipeline rather than sent to code
scanning, pending the portal ingestion work.
@victorvhs017
victorvhs017 self-requested a review September 17, 2026 23:33
@Vligai
Vligai merged commit fdd6d52 into main Sep 18, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants