Files
HealthLog/.github/workflows/trivy.yml
T
Marc-André Bombeck 314f35b2ee ci: move every codeql-action pin to v4.37.9 in one commit
init, analyze and upload-sarif are the same release pinned in three
workflows. Dependabot opened them as three separate pull requests, so each
run mixed two versions and analyze rejected the config init had written:
"Loaded a configuration file for version 4.37.7, but running version
4.37.9". None of the three could go green alone, and the code-scanning
analysis stayed red while they waited on each other.

Bump all five references together and group the action in dependabot.yml so
the next release arrives as one pull request.
2026-08-30 20:20:31 +02:00

165 lines
6.9 KiB
YAML

name: Trivy Scheduled Scan
# Two scans that the per-change gates cannot do, on a daily cadence.
#
# What already exists and is NOT repeated here:
# - `security.yml` → `dependency-audit` runs `pnpm audit --prod` on every
# push and pull request, blocking on HIGH/CRITICAL.
# - `security.yml` → `docker-security` builds the image on a push to `main`
# and runs `trivy image` against it, blocking on HIGH/CRITICAL.
#
# Both are change-triggered, and both answer "is this change safe". Neither
# answers "is what we shipped last week still safe", because an advisory
# published today lands against an image nobody is about to rebuild. That is
# what the schedule is for. There is deliberately no push or pull_request
# trigger: adding one would run the same scan the `docker-security` job
# already ran, minutes later, on the same tree.
on:
schedule:
# Daily, 05:17 UTC.
- cron: "17 5 * * *"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: trivy-scheduled
cancel-in-progress: true
jobs:
filesystem:
name: Lockfile (including dev dependencies)
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# `pnpm audit --prod` is the blocking gate and it is scoped to
# production dependencies on purpose: a dev-only advisory should not
# stop a release. The gap that scoping leaves is that "dev dependency"
# and "not in the image" are not the same statement.
#
# `pdfjs-dist` is the worked example. It sits in `devDependencies`,
# and `src/lib/documents/rasterize-pdf.ts` imports it at runtime, so
# Next's standalone output tracing copies it into the production
# image. `pnpm audit --prod` cannot see it. This scan can: without
# the flag Trivy reads 627 packages out of `pnpm-lock.yaml`, with it
# 1455, and `pdfjs-dist` is only in the second set.
#
# Trivy's own `--help` lists the flag as supported for npm, yarn and
# gradle. It works on `pnpm-lock.yaml` too; the help text is behind
# the parser. Verified against this repository before this workflow
# was written, and worth re-checking if the package count ever
# collapses back to the production figure.
#
# Report-only, and that is a deliberate choice rather than a soft
# one. The findings this widening surfaces are overwhelmingly
# transitive dev-tool advisories with fixes available upstream;
# failing the run on them from day one produces a red badge that gets
# muted within a week, and a muted signal is worse than none. The
# SARIF upload puts every finding in the repository's code-scanning
# alerts, which persist, notify, and can be triaged one at a time.
# The blocking answer to "does this ship" stays where it is, in
# `security.yml`.
- name: Trivy filesystem scan
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
env:
# No action input maps to `--include-dev-deps`; Trivy reads every
# flag from a `TRIVY_`-prefixed environment variable, so this is
# the documented way to reach it through the action.
TRIVY_INCLUDE_DEV_DEPS: "true"
with:
scan-type: fs
scan-ref: .
scanners: vuln
format: sarif
output: trivy-filesystem.sarif
severity: "CRITICAL,HIGH,MEDIUM"
limit-severities-for-sarif: true
exit-code: "0"
# Generated Prisma client. Nobody edits it, the fix for anything
# found in it is `pnpm prisma generate`, and it is ~9 MB.
skip-dirs: src/generated
- name: Upload results
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
sarif_file: trivy-filesystem.sarif
category: trivy-filesystem
published-image:
name: Published image
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
packages: read
security-events: write
steps:
# The `docker-security` job scans an image it just built from the
# current `main`. This one scans the image operators actually pull,
# which is the one built from the last release tag and unchanged
# since. The two answer different questions and the gap between them
# widens every day a release stays out.
#
# Trivy resolves the multi-arch manifest to the runner's platform, so
# this covers `linux/amd64`. The arm64 manifest shares every
# application layer and differs only in native binaries.
- name: Log in to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# `.trivyignore` lives at the repository root and Trivy reads it
# automatically, so the suppressions the blocking gate already
# carries apply here too and the two scans cannot disagree about
# what is accepted.
- name: Checkout for .trivyignore
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# Fails on CRITICAL only. A critical advisory against the image
# self-hosters are running right now is worth a red badge and a
# notification; HIGH goes to code scanning with everything else,
# because the release pipeline already refuses to publish an image
# carrying one and anything that appears here appeared after the
# fact.
- name: Trivy published-image scan
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: image
image-ref: ghcr.io/mbombeck/healthlog:latest
scanners: vuln
format: sarif
output: trivy-published-image.sarif
severity: "CRITICAL,HIGH,MEDIUM"
limit-severities-for-sarif: true
exit-code: "0"
- name: Upload results
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
sarif_file: trivy-published-image.sarif
category: trivy-published-image
# Separate table pass so the SARIF upload above always runs, even
# when this one fails the job. A scan whose failure suppresses its
# own report is a scan you have to re-run by hand to read.
- name: Fail on a critical finding in the published image
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: image
image-ref: ghcr.io/mbombeck/healthlog:latest
scanners: vuln
format: table
severity: "CRITICAL"
exit-code: "1"