Adopt Trivy for Container Image Vulnerability Scanning in CI/CD¶
Status¶
Proposed — Trivy will be introduced as the standard container image and filesystem vulnerability scanner, integrated into the CI/CD pipeline for all platform-built images.
1. Context¶
The platform produces several container images as deployable artefacts, including the hybridops-tech frontend (Node.js/Astro SSR) and the entitlements-api backend (Node.js/Express). As these images are deployed into Kubernetes and interact with external services (Stripe, Keycloak, PostgreSQL), CVEs in OS packages, runtime dependencies, or base images represent a concrete risk surface.
Currently no image scanning is performed before push to the container registry. There is no automated mechanism to detect when a base image (node:22-slim, node:22-alpine) receives a known CVE, or when a dependency introduced in package.json carries a vulnerability.
The platform requires a scanning approach that:
- Integrates into GitHub Actions without requiring an external SaaS account or paid tier.
- Covers both OS packages (Debian/Alpine) and language-level dependencies (node_modules).
- Produces structured output usable in CI gates and developer feedback loops.
- Scales cost-effectively as the number of images grows.
2. Decision¶
Adopt Trivy (by Aqua Security, open source) as the standard tool for container image vulnerability scanning. Trivy will be integrated as a GitHub Actions step that runs against each built image before it is pushed to the container registry.
The initial integration scope:
- Scan target: built container image (post docker build, pre docker push)
- Scanner: vuln (OS packages + language dependencies)
- Fail threshold: CRITICAL severity by default; HIGH configurable per image
- Output format: table for PR annotations, sarif for GitHub Security tab upload
- Scope: all images built by CI — hybridops-tech and entitlements-api as first targets
Trivy's database is updated on each scan run from Aqua's public vulnerability DB (no account required).
3. Rationale¶
Why Trivy over alternatives:
- Snyk provides stronger developer-IDE integration and auto-fix PRs, but requires an account and has dependency on SaaS availability. It is better suited to dependency-level scanning earlier in the development cycle, not as a gate on the final image. It may be added later for
package.jsonscanning at the branch level. - Wiz is an agentless cloud posture tool suited to organisations running multiple cloud accounts with a dedicated security team. It is out of scope at the current platform scale.
- Grype (Anchore) is a comparable open-source alternative. Trivy is preferred here because it covers both OS and language ecosystems in a single invocation and has a well-maintained GitHub Actions integration.
- Docker Scout is available natively in Docker Hub workflows but less portable to self-hosted or GHCR-based pipelines.
Trivy satisfies the core requirement: zero-cost, zero-account, single-tool coverage of OS + language CVEs, running in CI at image build time.
4. Consequences¶
4.1 Positive consequences¶
- CVEs in base images and
node_modulesare surfaced automatically before any image reaches the registry. - SARIF upload to the GitHub Security tab provides a persistent, searchable record of vulnerability state per branch.
- CI gate on
CRITICALseverity prevents shipping known-critical images accidentally. - No external account or SaaS dependency — Trivy operates entirely within the GitHub Actions runner.
- Consistent scan output format enables future tooling (dashboards, trend analysis) without vendor lock-in.
4.2 Negative consequences / risks¶
- Trivy does not verify image signatures or perform SBOM attestation. Supply chain provenance is out of scope for this ADR.
- Trivy's vulnerability database has a propagation lag — a newly published CVE may not appear in the database for several hours. This is an acceptable trade-off for a free, pull-based model.
- False positives are possible, particularly for OS packages where the vendor has backported a patch without bumping the version string. These will require manual suppression via a
.trivyignorefile. - A pipeline scanning step adds build time (~30–60 seconds per image). This is acceptable given the security benefit.
- Trivy does not replace JWKS signature validation, mTLS, or runtime policy enforcement — it is a build-time control only.
5. Alternatives considered¶
- Snyk — rejected as primary image scanner due to SaaS account requirement and per-image rate limits on the free tier. Retained as a candidate for dependency scanning at the source level (a separate future ADR).
- Wiz — rejected as out of scope; aimed at cloud posture across multi-account environments with dedicated security teams.
- Grype — valid alternative. Not chosen over Trivy because Trivy covers more ecosystems in one tool and has broader community adoption in GitHub Actions contexts.
- Docker Scout — rejected due to tighter coupling with Docker Hub and less flexible CI integration for GHCR-based workflows.
6. Implementation notes¶
The Trivy scan step will be added to the GitHub Actions workflow for each image build. Example step pattern:
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/hybridops-studio/hybridops-tech:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: "1"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
A .trivyignore file at the repository root will be used to record accepted false positives with justification comments.
Images affected by this ADR:
- hybridops.tech/deploy/Dockerfile — node:22-slim base
- control/backend/entitlements-api/Dockerfile — node:22-alpine base
Scan step is added after docker build and before docker push in all relevant workflows.
7. Operational impact and validation¶
- A failing Trivy scan blocks the push step; the PR cannot merge until either the vulnerability is resolved or an explicit suppression is added to
.trivyignorewith justification. - SARIF results in the GitHub Security tab provide an audit trail of what was scanned and when.
- Periodic base image updates (
node:22-slim,node:22-alpinepatch releases) should be tracked as part of routine dependency maintenance, prompted by Trivy alerts appearing on the main branch.
8. References¶
- Trivy — Aqua Security open source scanner
- aquasecurity/trivy-action — GitHub Actions integration
- ADR-0301 — pfSense as Firewall for Flow Control
- ADR-0302 — Fortigate Variant for Edge Firewall
Maintainer: HybridOps.Studio License: MIT-0 for code, CC-BY-4.0 for documentation unless otherwise stated.