Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/actions/trivy-scan/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Trivy image scan
description: >-
Scan a container image with aquasecurity/trivy-action, installing Trivy and
its vulnerability DB through hack/scripts/setup-trivy.sh first. The script
retries transient network failures with exponential backoff, which
trivy-action's built-in installer does not. Requires the repository to be
checked out.
inputs:
image-ref:
description: Image to scan.
required: true
severity:
description: Comma-separated severities to report.
required: false
default: CRITICAL,HIGH
exit-code:
description: Exit code when findings at the given severities are present.
required: false
default: "1"
trivyignores:
description: Comma-separated list of .trivyignore files.
required: false
default: ""
outputs:
setup-outcome:
description: Outcome of the Trivy setup step (success, failure, or skipped).
value: ${{ steps.setup.outcome }}
scan-outcome:
description: Outcome of the Trivy scan step (success, failure, or skipped).
value: ${{ steps.scan.outcome }}
runs:
using: composite
steps:
# Idempotent: reuses the binary when already installed in this job, and
# Trivy skips the DB download when the cached DB is fresh.
- name: Set up Trivy
id: setup
shell: bash
env:
TRIVY_CACHE_DIR: ${{ runner.temp }}/trivy-cache
TRIVY_INSTALL_DIR: ${{ runner.temp }}/trivy-bin
run: timeout --kill-after=10s 1800s ./hack/scripts/setup-trivy.sh

# skip-setup-trivy and cache: false keep trivy-action from downloading
# anything itself. setup-trivy.sh exported TRIVY_SKIP_DB_UPDATE=true, so
# the scan uses the DB downloaded above.
- name: Scan with Trivy
id: scan
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: ${{ inputs['image-ref'] }}
format: table
severity: ${{ inputs.severity }}
exit-code: ${{ inputs['exit-code'] }}
trivyignores: ${{ inputs.trivyignores }}
skip-setup-trivy: "true"
cache: "false"
cache-dir: ${{ runner.temp }}/trivy-cache
15 changes: 5 additions & 10 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -405,10 +405,9 @@ jobs:
cache-to: type=gha,scope=net-controller-${{ matrix.arch }},mode=max

- name: Scan controller with Trivy
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: ./.github/actions/trivy-scan
with:
image-ref: scan/unbounded-net-controller:${{ needs.version.outputs.tag }}-${{ matrix.arch }}
format: table
severity: CRITICAL,HIGH
exit-code: "1"

Expand All @@ -431,10 +430,9 @@ jobs:
cache-to: type=gha,scope=net-node-${{ matrix.arch }},mode=max

- name: Scan node with Trivy (CRITICAL, gating)
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: ./.github/actions/trivy-scan
with:
image-ref: scan/unbounded-net-node:${{ needs.version.outputs.tag }}-${{ matrix.arch }}
format: table
severity: CRITICAL
exit-code: "1"

Expand All @@ -444,10 +442,9 @@ jobs:
# regressions surface in the workflow log; promote back to gating once
# upstream ships a clean toolchain.
- name: Scan node with Trivy (HIGH, report-only)
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: ./.github/actions/trivy-scan
with:
image-ref: scan/unbounded-net-node:${{ needs.version.outputs.tag }}-${{ matrix.arch }}
format: table
severity: HIGH
exit-code: "0"

Expand Down Expand Up @@ -763,10 +760,9 @@ jobs:
tags: scan/metalman:${{ needs.version.outputs.tag }}

- name: Scan with Trivy
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: ./.github/actions/trivy-scan
with:
image-ref: scan/metalman:${{ needs.version.outputs.tag }}
format: table
severity: CRITICAL,HIGH
exit-code: "1"
trivyignores: images/metalman/.trivyignore
Expand Down Expand Up @@ -956,10 +952,9 @@ jobs:

- name: Scan with Trivy
if: matrix.component.trivy
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: ./.github/actions/trivy-scan
with:
image-ref: scan/${{ matrix.component.name }}:${{ needs.version.outputs.tag }}
format: table
severity: CRITICAL,HIGH
exit-code: "1"

Expand Down
105 changes: 105 additions & 0 deletions .github/workflows/trivy-setup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0

# Exercises the Trivy setup used by release.yaml. Release scans only run on tag
# pushes, so without this workflow a broken setup would first surface during a
# release.

name: Trivy Setup

on:
pull_request:
branches:
- main
- release-*
paths:
- .github/actions/trivy-scan/**
- .github/workflows/trivy-setup.yaml
- hack/scripts/setup-trivy.sh
- hack/scripts/setup-trivy_test.sh
workflow_dispatch:

concurrency:
group: trivy-setup-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
unit:
name: Script tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Run setup-trivy.sh tests
run: timeout --kill-after=10s 300s ./hack/scripts/setup-trivy_test.sh

scan:
name: Scan (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: ubuntu-latest
- arch: arm64
runner: ubuntu-24.04-arm
env:
# Old enough to have known HIGH and CRITICAL findings.
SCAN_IMAGE: mirror.gcr.io/library/alpine:3.10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Pull image
run: timeout --kill-after=10s 300s docker pull "${SCAN_IMAGE}"

- name: Scan (report-only)
uses: ./.github/actions/trivy-scan
with:
image-ref: ${{ env.SCAN_IMAGE }}
exit-code: "0"

# A second scan in the same job reuses the installed binary and DB, as
# the net-images job in release.yaml does.
- name: Scan again (gating)
id: gating
continue-on-error: true
uses: ./.github/actions/trivy-scan
with:
image-ref: ${{ env.SCAN_IMAGE }}
severity: CRITICAL
exit-code: "1"

# Ignoring the only CRITICAL finding must make the same gating scan pass,
# which shows the failure above came from findings, not a scanner error.
- name: Write ignore file
run: printf 'CVE-2021-36159\n' > "${RUNNER_TEMP}/trivyignore"

- name: Scan again (gating, findings ignored)
uses: ./.github/actions/trivy-scan
with:
image-ref: ${{ env.SCAN_IMAGE }}
severity: CRITICAL
exit-code: "1"
trivyignores: ${{ runner.temp }}/trivyignore

- name: Verify gating outcome
env:
SETUP_OUTCOME: ${{ steps.gating.outputs.setup-outcome }}
SCAN_OUTCOME: ${{ steps.gating.outputs.scan-outcome }}
run: |
set -euo pipefail
if [[ "${SETUP_OUTCOME}" != "success" ]]; then
echo "::error::gating setup outcome was '${SETUP_OUTCOME}', want 'success'"
exit 1
fi
if [[ "${SCAN_OUTCOME}" != "failure" ]]; then
echo "::error::gating scan outcome was '${SCAN_OUTCOME}', want 'failure'"
exit 1
fi
test "${TRIVY_SKIP_DB_UPDATE}" = "true"
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,8 @@ inventory-manifests: ## Render inventory deployment manifests into deploy/invent
#
# Knobs (all overridable on the command line or environment):
# TRIVY Enable scanning when non-empty. Default: unset (no scan).
# TRIVY_VERSION Trivy CLI version. Default: 0.69.3 (matches CI).
# TRIVY_VERSION Trivy CLI version. Default: 0.70.0 (matches the TRIVY_VERSION
# default in hack/scripts/setup-trivy.sh, used by CI).
# TRIVY_SEVERITY Comma-separated severities. Default: CRITICAL,HIGH.
# TRIVY_EXIT_CODE Exit code on findings. Default: 1 (fail). Set 0 to warn-only.
# TRIVY_IMAGE Override the trivy container image entirely.
Expand All @@ -990,7 +991,7 @@ inventory-manifests: ## Render inventory deployment manifests into deploy/invent
# Default: $$HOME/.cache/trivy.

TRIVY ?=
TRIVY_VERSION ?= 0.69.3
TRIVY_VERSION ?= 0.70.0
TRIVY_SEVERITY ?= CRITICAL,HIGH
TRIVY_EXIT_CODE ?= 1
TRIVY_IMAGE ?= aquasec/trivy:$(TRIVY_VERSION)
Expand Down
Loading
Loading