How do you integrate Trivy into a CI/CD pipeline (GitHub Actions, Jenkins, GitLab CI)?
Quick Answer
Trivy integrates into CI/CD pipelines by running as a scanning step after the Docker image build phase, using exit codes to fail the pipeline when vulnerabilities above a specified severity threshold are detected. Each platform has native integration patterns including the official aquasecurity/trivy-action for GitHub Actions, the Trivy Jenkins plugin, and inline script commands for GitLab CI.
Detailed Answer
Think of Trivy in a CI/CD pipeline like a quality inspector on a factory assembly line. Every product (container image) must pass through the inspector's station before it can be packaged and shipped. If the inspector finds a defect above a certain severity, the line stops and the product is sent back for rework. Without this inspection gate, defective products reach customers and cause costly recalls. Trivy serves as that automated inspector, examining every image before it enters a container registry.
Trivy integrates into CI/CD pipelines as a scanning step that runs after the Docker image build phase but before the image push phase. The fundamental mechanism is straightforward: Trivy accepts an image reference, decomposes the image layers to identify OS packages and application dependencies, matches them against vulnerability databases including NVD, GitHub Advisory Database, and distribution-specific trackers, and produces a report with findings categorized by severity. The critical configuration is the --exit-code flag, which determines whether the pipeline passes or fails. Setting --exit-code 1 with --severity CRITICAL,HIGH means the pipeline fails only when critical or high vulnerabilities are found, allowing medium and low findings to pass through as warnings.
In GitHub Actions, the recommended approach uses the official aquasecurity/trivy-action maintained by Aqua Security. This action handles Trivy installation, database caching between runs, and output formatting. For the payments-api service, you would add a scan step after the docker build step that targets the locally built image. The action supports multiple output formats including table for human-readable console output, JSON for programmatic processing, and SARIF for integration with GitHub's Security tab under Code Scanning. The SARIF integration is particularly valuable because it surfaces vulnerabilities as inline annotations on pull requests, enabling developers to see exactly which dependency introduced the vulnerability without leaving the PR review interface. GitHub Actions caching can store the Trivy vulnerability database between workflow runs to reduce scan times from minutes to seconds.
For Jenkins, integration follows two patterns depending on team preference. The first uses the Aqua Security Trivy plugin, which adds a dedicated build step type to Freestyle and Pipeline jobs. The second, more common approach uses a shell step in a Jenkinsfile that invokes Trivy directly from the command line. In a typical order-processing-service pipeline, the Jenkinsfile would include a stage called Security Scan that runs trivy image with the appropriate severity flags after the Build stage and before the Push stage. Jenkins can archive the JSON report as a build artifact, and teams often use the HTML Publisher plugin to render scan results as a browsable report attached to each build. For GitLab CI, Trivy integrates as a job in the .gitlab-ci.yml file, typically placed in a security stage that runs after the build stage. GitLab has native support for ingesting Trivy's GitLab-formatted JSON output through the artifacts:reports:container_scanning directive, which populates the Security Dashboard accessible from the project's sidebar.
A common gotcha when integrating Trivy into CI/CD is failing to cache the vulnerability database. Without caching, every pipeline run downloads a fresh database, adding 30-60 seconds of latency and creating reliability issues if the download server is unavailable. In GitHub Actions, use the actions/cache action to persist the Trivy database directory between runs. In Jenkins, use the stash/unstash mechanism or a shared volume on the build agent. Another trap is setting the severity threshold too aggressively on day one. If you immediately fail on all HIGH findings in a legacy codebase with hundreds of existing vulnerabilities, the pipeline becomes permanently blocked. Instead, start with CRITICAL only, fix those, then progressively tighten to HIGH. Use the .trivyignore file to temporarily suppress known false positives or vulnerabilities with no available fix so that the pipeline remains actionable rather than noisy.