mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
The Debian base carries HIGH advisories the distribution has not fixed (util-linux, ncurses, systemd, acl, sqlite, perl-base), which no change here can remove. The blocking image scan now runs with --ignore-unfixed, so a finding with a published fix still fails the job, and a separate step before it lists every HIGH and CRITICAL finding without failing. The scheduled scan's critical gate follows the same rule; its SARIF report keeps everything.
168 lines
7.1 KiB
YAML
168 lines
7.1 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 to `main` and once a day, 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 with a fix.
|
|
#
|
|
# 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-24.04
|
|
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@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
with:
|
|
sarif_file: trivy-filesystem.sarif
|
|
category: trivy-filesystem
|
|
|
|
published-image:
|
|
name: Published image
|
|
runs-on: ubuntu-24.04
|
|
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@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.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@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
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"
|
|
# Same rule as the blocking gate in security.yml: a finding with a
|
|
# published fix fails, one without is in the SARIF report above.
|
|
ignore-unfixed: true
|