Skip to content

Commit

Permalink
Stop using the upstream Trivy action
Browse files Browse the repository at this point in the history
It lacks sufficient settings to control its cache and setup steps.
Download Trivy data in a separate job and limit its concurrency.

Issue: PGO-1893
  • Loading branch information
cbandy committed Nov 17, 2024
1 parent 2112c3c commit 2c3d3d0
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 57 deletions.
99 changes: 99 additions & 0 deletions .github/actions/trivy/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Trivy
description: Scan this project using Trivy

# The Trivy team maintains an action, but it has trouble caching its vulnerability data:
# https://github.com/aquasecurity/trivy-action/issues/389
#
# The action below uses any recent cache matching `cache-prefix` and calculates a cache key
# derived from the data Trivy downloads.

inputs:
cache:
default: restore,success,use
description: >-
What Trivy data to cache; one or more of restore, save, success, or use.
setup:
default: v0.57.0,cache
description: >-
How to install Trivy; one or more of version, none, or cache.
cache-directory:
default: ${{ github.workspace }}/.cache/trivy

cache-prefix:
default: cache-trivy

scan-target:
default: .

scan-type:
default: filesystem

runs:
using: composite
steps:
# Parse list inputs as separated by commas and spaces.
# Select the maximum version-looking string from `inputs.setup`.
- id: parsed
shell: bash
run: |
# Validate inputs
(
<<< '${{ inputs.cache }}' jq -rRsS '"cache=\(split("[,\\s]+"; "") - [""])"'
<<< '${{ inputs.setup }}' jq -rRsS '
"setup=\(split("[,\\s]+"; "") - [""])",
"version=\(split("[,\\s]+"; "") | max_by(split("[v.]"; "") | map(tonumber?)))"
'
) | tee --append $GITHUB_OUTPUT
# Install Trivy as requested.
- if: ${{ ! contains(fromJSON(steps.parsed.outputs.setup), 'none') }}
uses: aquasecurity/[email protected]
with:
cache: ${{ contains(fromJSON(steps.parsed.outputs.setup), 'cache') }}
version: ${{ steps.parsed.outputs.version }}

# Restore a recent cache beginning with the prefix.
- id: restore
if: ${{ contains(fromJSON(steps.parsed.outputs.cache), 'restore') }}
uses: actions/cache/restore@v4
with:
path: ${{ inputs.cache-directory }}
key: ${{ inputs.cache-prefix }}-

- id: trivy
shell: bash
env:
TRIVY_CACHE_DIR: >-
${{ contains(fromJSON(steps.parsed.outputs.cache), 'use') && inputs.cache-directory || '' }}
run: |
# Run Trivy
trivy '${{ inputs.scan-type }}' '${{ inputs.scan-target }}' || result=$?
checksum=$([[ -z "${TRIVY_CACHE_DIR}" ]] || cat "${TRIVY_CACHE_DIR}/"*/metadata.json | sha256sum)
echo 'cache-key=${{ inputs.cache-prefix }}-'"${checksum%% *}" >> $GITHUB_OUTPUT
exit "${result-0}"
# Save updated data to the cache when requested.
- if: >-
${{
steps.restore.outcome == 'success' &&
steps.restore.outputs.cache-matched-key == steps.trivy.outputs.cache-key
}}
shell: bash
run: |
# Cache hit on ${{ steps.restore.outputs.cache-matched-key }}
- if: >-
${{
steps.restore.outputs.cache-matched-key != steps.trivy.outputs.cache-key &&
(
(contains(fromJSON(steps.parsed.outputs.cache), 'save') && !cancelled()) ||
(contains(fromJSON(steps.parsed.outputs.cache), 'success') && success())
)
}}
uses: actions/cache/save@v4
with:
key: ${{ steps.trivy.outputs.cache-key }}
path: ${{ inputs.cache-directory }}
81 changes: 24 additions & 57 deletions .github/workflows/trivy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,19 @@ env:
# https://github.com/actions/setup-go/issues/457
GOTOOLCHAIN: local

# Manage the Trivy data directory until upstream can do it reliably
# https://github.com/aquasecurity/trivy-action/issues/389
#
# NOTE: This must match the default "cache-dir" upstream:
# https://github.com/aquasecurity/trivy-action/blob/-/action.yaml
TRIVY_CACHE_DIR: ${{ github.workspace }}/.cache/trivy

jobs:
cache:
# Run only one of these jobs at a time across the entire project.
concurrency: { group: trivy-cache }

runs-on: ubuntu-latest
steps:
- uses: aquasecurity/[email protected]
with:
cache: true
version: v0.57.0

# The "aquasecurity/trivy-action" looks for data in the GitHub action
# cache under a key with today's date.
# - https://github.com/actions/cache/blob/-/restore#readme
# - https://github.com/aquasecurity/trivy-action/blob/-/action.yaml
- id: values
run: |
(
date +'date=%Y-%m-%d'
echo "glob=${TRIVY_CACHE_DIR}/*/metadata.json"
) |
tee --append $GITHUB_OUTPUT
- id: restore
uses: actions/cache/restore@v4
with:
key: cache-trivy-${{ steps.values.outputs.date }}
path: ${{ env.TRIVY_CACHE_DIR }}
restore-keys: cache-trivy-

# Validate or update the Trivy data cache.
- id: validate
- uses: actions/checkout@v4
- uses: ./.github/actions/trivy
env:
METADATA_HASH: ${{ hashFiles(steps.values.outputs.glob) }}
run: |
<<< "before=${METADATA_HASH}" tee --append $GITHUB_OUTPUT
trivy filesystem --download-db-only --scanners license,secret,vuln --quiet
# Save any successful changes back to the GitHub action cache.
# - https://github.com/actions/cache/blob/-/save#readme
- if: ${{ hashFiles(steps.values.outputs.glob) != steps.validate.outputs.before }}
uses: actions/cache/save@v4
with:
key: ${{ steps.restore.outputs.cache-primary-key }}
path: ${{ env.TRIVY_CACHE_DIR }}
TRIVY_DB_DOWNLOAD_ONLY: true
TRIVY_DB_NO_PROGRESS: true
TRIVY_SCANNERS: license,secret,vuln

licenses:
needs: [cache]
Expand All @@ -75,13 +39,13 @@ jobs:

# Report success only when detected licenses are listed in [/trivy.yaml].
- name: Scan licenses
uses: aquasecurity/[email protected]
uses: ./.github/actions/trivy
env:
TRIVY_DEBUG: true
TRIVY_EXIT_CODE: 1
TRIVY_SCANNERS: license
with:
scan-type: filesystem
scanners: license
exit-code: 1
cache: restore,use

vulnerabilities:
if: ${{ github.repository == 'CrunchyData/postgres-operator' }}
Expand All @@ -97,21 +61,24 @@ jobs:
# human consumption. This step fails only when Trivy is unable to scan.
# A later step uploads results to GitHub as a pull request check.
- name: Log detected vulnerabilities
uses: aquasecurity/[email protected]
uses: ./.github/actions/trivy
env:
TRIVY_SCANNERS: secret,vuln
with:
scan-type: filesystem
scanners: secret,vuln
cache: restore,use

# Produce a SARIF report of actionable results. This step fails only when
# Trivy is unable to scan.
- name: Report actionable vulnerabilities
uses: aquasecurity/[email protected]
uses: ./.github/actions/trivy
env:
TRIVY_IGNORE_UNFIXED: true
TRIVY_FORMAT: 'sarif'
TRIVY_OUTPUT: 'trivy-results.sarif'
TRIVY_SCANNERS: secret,vuln
with:
scan-type: filesystem
ignore-unfixed: true
format: 'sarif'
output: 'trivy-results.sarif'
scanners: secret,vuln
cache: use
setup: none

# Submit the SARIF report to GitHub code scanning. Pull requests checks
# succeed or fail according to branch protection rules.
Expand Down

0 comments on commit 2c3d3d0

Please sign in to comment.