From a20de5420d57c4102486cdd9578b45609c99d7eb Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 9 Oct 2024 00:20:38 +0400 Subject: [PATCH] feat: store artifacts in cache by default (#399) * feat: migrate to a composite action Signed-off-by: knqyf263 * Fix tests Signed-off-by: knqyf263 * Delete an unused input Signed-off-by: knqyf263 * test: expect status code 0 Signed-off-by: knqyf263 * test: not use run https://bats-core.readthedocs.io/en/stable/writing-tests.html#when-not-to-use-run Signed-off-by: knqyf263 * feat: add 'cache' input Signed-off-by: knqyf263 * docs: update README Signed-off-by: knqyf263 * feat: pin Trivy version Signed-off-by: knqyf263 * fix: bump trivy version Signed-off-by: knqyf263 * feat: use date for cache key Signed-off-by: knqyf263 * chore: delete a comment Signed-off-by: knqyf263 * docs: update README Signed-off-by: knqyf263 * refactor: resolve conflicts and use envs Signed-off-by: knqyf263 --------- Signed-off-by: knqyf263 --- .github/workflows/bump-trivy.yaml | 3 +- .github/workflows/test.yaml | 10 +- Dockerfile | 5 - README.md | 158 +++++++++++++-------- action.yaml | 104 +++++++++----- entrypoint.sh | 225 +++++------------------------- test/test.bats | 55 ++++++-- 7 files changed, 252 insertions(+), 308 deletions(-) delete mode 100644 Dockerfile diff --git a/.github/workflows/bump-trivy.yaml b/.github/workflows/bump-trivy.yaml index 626f8f7d..25f282ab 100644 --- a/.github/workflows/bump-trivy.yaml +++ b/.github/workflows/bump-trivy.yaml @@ -17,8 +17,9 @@ jobs: - uses: actions/checkout@v4 - name: Update Trivy versions run: | - sed -r -i "s/ghcr.io\/aquasecurity\/trivy:[0-9]+\.[0-9]+\.[0-9]+/ghcr.io\/aquasecurity\/trivy:${{ inputs.trivy_version }}/" Dockerfile find test/data -type f -name '*.test' | xargs sed -r -i 's/"version": "[0-9]+\.[0-9]+\.[0-9]+"/"version": "${{ inputs.trivy_version }}"/' + sed -r -i '/^\| `version`/ s/[0-9]+\.[0-9]+\.[0-9]+/${{ inputs.trivy_version }}/g' README.md + sed -r -i 's/(default:[ ]*'"'"')v[0-9]+\.[0-9]+\.[0-9]+/\1v${{ inputs.trivy_version }}/' action.yaml - name: Create PR id: create-pr diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f9919c29..04755f47 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -24,8 +24,8 @@ jobs: trivy --version - name: Test - run: | - chmod +x entrypoint.sh - GITHUB_REPOSITORY_OWNER=aquasecurity\ - TRIVY_CACHE_DIR=.cache TRIVY_DISABLE_VEX_NOTICE=true TRIVY_DEBUG=true\ - bats --recursive --timing --verbose-run . + run: bats --recursive --timing --verbose-run . + env: + TRIVY_CACHE_DIR: .cache + TRIVY_DISABLE_VEX_NOTICE: true + TRIVY_DEBUG: true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 740b7e6a..00000000 --- a/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ghcr.io/aquasecurity/trivy:0.56.1 -COPY entrypoint.sh / -RUN apk --no-cache add bash curl npm -RUN chmod +x /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md index 54498d5e..2f2fa2cf 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,22 @@ ## Table of Contents -- [Usage](#usage) - - [Workflow](#workflow) - - [Docker Image Scanning](#using-trivy-with-github-code-scanning) - - [Git Repository Scanning](#using-trivy-to-scan-your-git-repo) -- [Customizing](#customizing) - - [Inputs](#inputs) +* [Usage](#usage) + * [Scan CI Pipeline](#scan-ci-pipeline) + * [Scan CI Pipeline (w/ Trivy Config)](#scan-ci-pipeline-w-trivy-config) + * [Cache](#cache) + * [Scanning a Tarball](#scanning-a-tarball) + * [Using Trivy with GitHub Code Scanning](#using-trivy-with-github-code-scanning) + * [Using Trivy to scan your Git repo](#using-trivy-to-scan-your-git-repo) + * [Using Trivy to scan your rootfs directories](#using-trivy-to-scan-your-rootfs-directories) + * [Using Trivy to scan Infrastructure as Code](#using-trivy-to-scan-infrastructure-as-code) + * [Using Trivy to generate SBOM](#using-trivy-to-generate-sbom) + * [Using Trivy to scan your private registry](#using-trivy-to-scan-your-private-registry) + * [Using Trivy if you don't have code scanning enabled](#using-trivy-if-you-dont-have-code-scanning-enabled) +* [Customizing](#customizing) + * [inputs](#inputs) + * [Environment variables](#environment-variables) + * [Trivy config file](#trivy-config-file) ## Usage @@ -36,8 +46,7 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - name: Build an image from Dockerfile - run: | - docker build -t docker.io/my-organization/my-app:${{ github.sha }} . + run: docker build -t docker.io/my-organization/my-app:${{ github.sha }} . - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@0.20.0 with: @@ -95,6 +104,86 @@ Trivy uses [Viper](https://github.com/spf13/viper) which has a defined precedenc - Config file - Default +### Cache +The action has a built-in functionality for caching and restoring [the vulnerability DB](https://github.com/aquasecurity/trivy-db), [the Java DB](https://github.com/aquasecurity/trivy-java-db) and [the checks bundle](https://github.com/aquasecurity/trivy-checks) if they are downloaded during the scan. +The cache is stored in the `$GITHUB_WORKSPACE/.cache/trivy` directory by default. +The cache is restored before the scan starts and saved after the scan finishes. + +It uses [actions/cache](https://github.com/actions/cache) under the hood but requires less configuration settings. +The cache input is optional, and caching is turned on by default. + +#### Disabling caching +If you want to disable caching, set the `cache` input to `false`, but we recommend keeping it enabled to avoid rate limiting issues. + +```yaml + - name: Run Trivy scanner without cache + uses: aquasecurity/trivy-action@0.20.0 + with: + scan-type: 'fs' + scan-ref: '.' + cache: 'false' +``` + +#### Updating caches in the default branch +Please note that there are [restrictions on cache access](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache) between branches in GitHub Actions. +By default, a workflow can access and restore a cache created in either the current branch or the default branch (usually `main` or `master`). +If you need to share caches across branches, you may need to create a cache in the default branch and restore it in the current branch. + +To optimize your workflow, you can set up a cron job to regularly update the cache in the default branch. +This allows subsequent scans to use the cached DB without downloading it again. + +```yaml +# Note: This workflow only updates the cache. You should create a separate workflow for your actual Trivy scans. +# In your scan workflow, set TRIVY_SKIP_DB_UPDATE=true and TRIVY_SKIP_JAVA_DB_UPDATE=true. +name: Update Trivy Cache + +on: + schedule: + - cron: '0 0 * * *' # Run daily at midnight UTC + workflow_dispatch: # Allow manual triggering + +jobs: + update-trivy-db: + runs-on: ubuntu-latest + steps: + - name: Get current date + id: date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Download and extract the vulnerability DB + run: | + mkdir -p $GITHUB_WORKSPACE/.cache/trivy/db + oras pull ghcr.io/aquasecurity/trivy-db:2 + tar -xzf db.tar.gz -C $GITHUB_WORKSPACE/.cache/trivy/db + rm db.tar.gz + + - name: Download and extract the Java DB + run: | + mkdir -p $GITHUB_WORKSPACE/.cache/trivy/java-db + oras pull ghcr.io/aquasecurity/trivy-java-db:1 + tar -xzf javadb.tar.gz -C $GITHUB_WORKSPACE/.cache/trivy/java-db + rm javadb.tar.gz + + - name: Cache DBs + uses: actions/cache/save@v4 + with: + path: ${{ github.workspace }}/.cache/trivy + key: cache-trivy-${{ steps.date.outputs.date }} +``` + +When running a scan, set the environment variables `TRIVY_SKIP_DB_UPDATE` and `TRIVY_SKIP_JAVA_DB_UPDATE` to skip the download process. + +```yaml + - name: Run Trivy scanner without downloading DBs + uses: aquasecurity/trivy-action@0.20.0 + with: + scan-type: 'image' + scan-ref: 'myimage' + env: + TRIVY_SKIP_DB_UPDATE: true + TRIVY_SKIP_JAVA_DB_UPDATE: true +``` + ### Scanning a Tarball ```yaml name: build @@ -123,56 +212,6 @@ jobs: severity: 'CRITICAL,HIGH' ``` -### Using cache for Trivy databases -Recently, there has been an increase in cases of receiving the `TOOMANYREQUESTS` error when downloading the Trivy databases (`trivy-db`, `trivy-java-db` and `trivy-checks`). - -If you’re performing multiple scans, it makes sense to use [action/cache](https://github.com/actions/cache) to cache one or more databases. - -The example below saves the `trivy-db` for each day in the cache: - -```yaml -name: build -on: - push: - branches: - - main - pull_request: - -jobs: - build: - name: Build - runs-on: ubuntu-20.04 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - ## To avoid the trivy-db becoming outdated, we save the cache for one day - - name: Get data - id: date - run: echo "date=$(date +%Y-%m-%d)" >> $GITHUB_OUTPUT - - - name: Restore trivy cache - uses: actions/cache@v4 - with: - path: cache/db - key: trivy-cache-${{ steps.date.outputs.date }} - restore-keys: - trivy-cache- - - - name: Run Trivy vulnerability scanner in fs mode - uses: aquasecurity/trivy-action@0.24.0 - with: - scan-type: 'fs' - scan-ref: '.' - cache-dir: "./cache" - - ## Trivy-db uses `0600` permissions. - ## But `action/cache` use `runner` user by default - ## So we need to change the permissions before caching the database. - - name: change permissions for trivy.db - run: sudo chmod 0644 ./cache/db/trivy.db -``` - ### Using Trivy with GitHub Code Scanning If you have [GitHub code scanning](https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/about-code-scanning) available you can use Trivy as a scanning tool as follows: ```yaml @@ -630,7 +669,7 @@ Following inputs can be used as `step.with` keys: | `severity` | String | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | Severities of vulnerabilities to scanned for and displayed | | `skip-dirs` | String | | Comma separated list of directories where traversal is skipped | | `skip-files` | String | | Comma separated list of files where traversal is skipped | -| `cache-dir` | String | | Cache directory | +| `cache-dir` | String | `$GITHUB_WORKSPACE/.cache/trivy` | Cache directory | | `timeout` | String | `5m0s` | Scan timeout duration | | `ignore-policy` | String | | Filter vulnerabilities with OPA rego language | | `hide-progress` | String | `false` | Suppress progress bar and log output | @@ -641,6 +680,7 @@ Following inputs can be used as `step.with` keys: | `github-pat` | String | | Authentication token to enable sending SBOM scan results to GitHub Dependency Graph. Can be either a GitHub Personal Access Token (PAT) or GITHUB_TOKEN | | `limit-severities-for-sarif` | Boolean | false | By default *SARIF* format enforces output of all vulnerabilities regardless of configured severities. To override this behavior set this parameter to **true** | | `docker-host` | String | | By default it is set to `unix://var/run/docker.sock`, but can be updated to help with containerized infrastructure values | +| `version` | String | `v0.56.1` | Trivy version to use, e.g. `latest` or `v0.56.1` | ### Environment variables You can use [Trivy environment variables][trivy-env] to set the necessary options (including flags that are not supported by [Inputs](#inputs), such as `--secret-config`). diff --git a/action.yaml b/action.yaml index f13a5aac..bbc90f8b 100644 --- a/action.yaml +++ b/action.yaml @@ -1,6 +1,7 @@ name: 'Aqua Security Trivy' description: 'Scans container images for vulnerabilities with Trivy' author: 'Aqua Security' + inputs: scan-type: description: 'Scan type to use for scanning vulnerability' @@ -24,7 +25,7 @@ inputs: description: 'ignore unfixed vulnerabilities' required: false default: 'false' - vuln-type: + vuln-type: # TODO: rename to pkg-types description: 'comma-separated list of vulnerability types (os,library)' required: false default: 'os,library' @@ -55,7 +56,7 @@ inputs: cache-dir: description: 'specify where the cache is stored' required: false - default: '' + default: '${{ github.workspace }}/.cache/trivy' timeout: description: 'timeout (default 5m0s)' required: false @@ -79,9 +80,6 @@ inputs: description: 'comma-separated list of relative paths in repository to one or more .trivyignore files' required: false default: '' - artifact-type: - description: 'input artifact type (image, fs, repo, archive) for SBOM generation' - required: false github-pat: description: 'GitHub Personal Access Token (PAT) for submitting SBOM to GitHub Dependency Snapshot API' required: false @@ -97,33 +95,73 @@ inputs: docker-host: description: 'unix domain socket path to use for docker scanning, ex. unix:///var/run/docker.sock' required: false + version: + description: 'Trivy version to use' + required: false + default: 'v0.56.1' + cache: + description: 'Used to specify whether caching is needed. Set to false, if you would like to disable caching.' + required: false + default: 'true' runs: - using: 'docker' - image: "Dockerfile" - args: - - '-a ${{ inputs.scan-type }}' - - '-b ${{ inputs.format }}' - - '-c ${{ inputs.template }}' - - '-d ${{ inputs.exit-code }}' - - '-e ${{ inputs.ignore-unfixed }}' - - '-f ${{ inputs.vuln-type }}' - - '-g ${{ inputs.severity }}' - - '-h ${{ inputs.output }}' - - '-i ${{ inputs.image-ref }}' - - '-j ${{ inputs.scan-ref }}' - - '-k ${{ inputs.skip-dirs }}' - - '-l ${{ inputs.input }}' - - '-m ${{ inputs.cache-dir }}' - - '-n ${{ inputs.timeout }}' - - '-o ${{ inputs.ignore-policy }}' - - '-p ${{ inputs.hide-progress }}' - - '-q ${{ inputs.skip-files }}' - - '-r ${{ inputs.list-all-pkgs }}' - - '-s ${{ inputs.scanners }}' - - '-t ${{ inputs.trivyignores }}' - - '-u ${{ inputs.github-pat }}' - - '-v ${{ inputs.trivy-config }}' - - '-x ${{ inputs.tf-vars }}' - - '-z ${{ inputs.limit-severities-for-sarif }}' - - '-y ${{ inputs.docker-host }}' + using: 'composite' + steps: + - name: Install Trivy + shell: bash + run: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin ${{ inputs.version }} + + - name: Get current date + id: date + shell: bash + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Restore DB from cache + if: ${{ inputs.cache == 'true' }} + uses: actions/cache@v4 + with: + path: ${{ inputs.cache-dir }} + key: cache-trivy-${{ steps.date.outputs.date }} + restore-keys: cache-trivy- + + - name: Set GitHub Path + run: echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH + shell: bash + env: + GITHUB_ACTION_PATH: ${{ github.action_path }} + + - name: Run Trivy + shell: bash + run: entrypoint.sh + env: + # For shell script + # > If the action is written using a composite, then it will not automatically get INPUT_ + # cf. https://docs.github.com/en/actions/sharing-automations/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs + INPUT_SCAN_TYPE: ${{ inputs.scan-type }} + INPUT_IMAGE_REF: ${{ inputs.image-ref }} + INPUT_SCAN_REF: ${{ inputs.scan-ref }} + INPUT_TRIVYIGNORES: ${{ inputs.trivyignores }} + INPUT_GITHUB_PAT: ${{ inputs.github-pat }} + INPUT_LIMIT_SEVERITIES_FOR_SARIF: ${{ inputs.limit-severities-for-sarif }} + + # For Trivy + # cf. https://aquasecurity.github.io/trivy/latest/docs/configuration/#environment-variables + TRIVY_INPUT: ${{ inputs.input }} + TRIVY_EXIT_CODE: ${{ inputs.exit-code }} + TRIVY_IGNORE_UNFIXED: ${{ inputs.ignore-unfixed }} + TRIVY_PKG_TYPES: ${{ inputs.vuln-type }} + TRIVY_SEVERITY: ${{ inputs.severity }} + TRIVY_FORMAT: ${{ inputs.format }} + TRIVY_TEMPLATE: ${{ inputs.template }} + TRIVY_OUTPUT: ${{ inputs.output }} + TRIVY_SKIP_DIRS: ${{ inputs.skip-dirs }} + TRIVY_SKIP_FILES: ${{ inputs.skip-files }} + TRIVY_CACHE_DIR: ${{ inputs.cache-dir }} + TRIVY_TIMEOUT: ${{ inputs.timeout }} + TRIVY_IGNORE_POLICY: ${{ inputs.ignore-policy }} + TRIVY_QUIET: ${{ inputs.hide-progress }} + TRIVY_LIST_ALL_PKGS: ${{ inputs.list-all-pkgs }} + TRIVY_SCANNERS: ${{ inputs.scanners }} + TRIVY_CONFIG: ${{ inputs.trivy-config }} + TRIVY_TF_VARS: ${{ inputs.tf-vars }} + TRIVY_DOCKER_HOST: ${{ inputs.docker-host }} diff --git a/entrypoint.sh b/entrypoint.sh index 79fd708e..3f72462a 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,216 +1,57 @@ #!/bin/bash -set -e -while getopts "a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:x:y:z:" o; do - case "${o}" in - a) - export scanType=${OPTARG} - ;; - b) - export format=${OPTARG} - ;; - c) - export template=${OPTARG} - ;; - d) - export exitCode=${OPTARG} - ;; - e) - export ignoreUnfixed=${OPTARG} - ;; - f) - export vulnType=${OPTARG} - ;; - g) - export severity=${OPTARG} - ;; - h) - export output=${OPTARG} - ;; - i) - export imageRef=${OPTARG} - ;; - j) - export scanRef=${OPTARG} - ;; - k) - export skipDirs=${OPTARG} - ;; - l) - export input=${OPTARG} - ;; - m) - export cacheDir=${OPTARG} - ;; - n) - export timeout=${OPTARG} - ;; - o) - export ignorePolicy=${OPTARG} - ;; - p) - export hideProgress=${OPTARG} - ;; - q) - export skipFiles=${OPTARG} - ;; - r) - export listAllPkgs=${OPTARG} - ;; - s) - export scanners=${OPTARG} - ;; - t) - export trivyIgnores=${OPTARG} - ;; - u) - export githubPAT=${OPTARG} - ;; - v) - export trivyConfig=${OPTARG} - ;; - x) - export tfVars=${OPTARG} - ;; - y) - export dockerHost=${OPTARG} - ;; - z) - export limitSeveritiesForSARIF=${OPTARG} - ;; - esac -done +set -euo pipefail - -scanType=$(echo $scanType | tr -d '\r') -export artifactRef="${imageRef}" -if [ "${scanType}" = "repo" ] || [ "${scanType}" = "fs" ] || [ "${scanType}" = "filesystem" ] || [ "${scanType}" = "config" ] || [ "${scanType}" = "rootfs" ] || [ "${scanType}" = "sbom" ];then - artifactRef=$(echo $scanRef | tr -d '\r') -fi -input=$(echo $input | tr -d '\r') -if [ $input ]; then - artifactRef="--input $input" +# Set artifact reference +scanType="${INPUT_SCAN_TYPE:-image}" +scanRef="${INPUT_SCAN_REF:-.}" +if [ -n "${INPUT_IMAGE_REF:-}" ]; then + scanRef="${INPUT_IMAGE_REF}" # backwards compatibility fi -#trim leading spaces for boolean params -ignoreUnfixed=$(echo $ignoreUnfixed | tr -d '\r') -hideProgress=$(echo $hideProgress | tr -d '\r') -limitSeveritiesForSARIF=$(echo $limitSeveritiesForSARIF | tr -d '\r') -GLOBAL_ARGS="" -if [ $cacheDir ];then - GLOBAL_ARGS="$GLOBAL_ARGS --cache-dir $cacheDir" -fi +# Handle trivy ignores +if [ -n "${INPUT_TRIVYIGNORES:-}" ]; then + ignorefile="./trivyignores" -SARIF_ARGS="" -ARGS="" -format=$(echo $format | xargs) -if [ $format ];then - ARGS="$ARGS --format $format" -fi -if [ $template ] ;then - ARGS="$ARGS --template $template" -fi -if [ $exitCode ];then - ARGS="$ARGS --exit-code $exitCode" - SARIF_ARGS="$SARIF_ARGS --exit-code $exitCode" -fi -if [ "$ignoreUnfixed" == "true" ] && [ "$scanType" != "config" ];then - ARGS="$ARGS --ignore-unfixed" - SARIF_ARGS="$SARIF_ARGS --ignore-unfixed" -fi -if [ $vulnType ] && [ "$scanType" != "config" ] && [ "$scanType" != "sbom" ];then - ARGS="$ARGS --vuln-type $vulnType" - SARIF_ARGS="$SARIF_ARGS --vuln-type $vulnType" -fi -if [ $scanners ];then - ARGS="$ARGS --scanners $scanners" - SARIF_ARGS="$SARIF_ARGS --scanners $scanners" -fi -if [ $severity ];then - ARGS="$ARGS --severity $severity" -fi -if [ $output ];then - ARGS="$ARGS --output $output" -fi -if [ $skipDirs ];then - for i in $(echo $skipDirs | tr "," "\n") - do - ARGS="$ARGS --skip-dirs $i" - SARIF_ARGS="$SARIF_ARGS --skip-dirs $i" - done -fi -if [ $tfVars ] && [ "$scanType" == "config" ];then - ARGS="$ARGS --tf-vars $tfVars" -fi + # Clear the ignore file if it exists, or create a new empty file + : > "$ignorefile" -if [ $trivyIgnores ];then - for f in $(echo $trivyIgnores | tr "," "\n") - do + for f in ${INPUT_TRIVYIGNORES//,/ }; do if [ -f "$f" ]; then echo "Found ignorefile '${f}':" cat "${f}" - cat "${f}" >> ./trivyignores + cat "${f}" >> "$ignorefile" else - echo "ERROR: cannot find ignorefile '${f}'." + echo "ERROR: cannot find ignorefile '${f}'." >&2 exit 1 fi done - ARGS="$ARGS --ignorefile ./trivyignores" -fi -if [ $timeout ];then - ARGS="$ARGS --timeout $timeout" - SARIF_ARGS="$SARIF_ARGS --timeout $timeout" -fi -if [ $ignorePolicy ];then - ARGS="$ARGS --ignore-policy $ignorePolicy" - SARIF_ARGS="$SARIF_ARGS --ignore-policy $ignorePolicy" -fi -if [ "$hideProgress" == "true" ];then - ARGS="$ARGS --quiet" - SARIF_ARGS="$SARIF_ARGS --quiet" -fi -if [ $dockerHost ];then - ARGS="$ARGS --docker-host $dockerHost" + export TRIVY_IGNOREFILE="$ignorefile" fi -listAllPkgs=$(echo $listAllPkgs | tr -d '\r') -if [ "$listAllPkgs" == "true" ];then - ARGS="$ARGS --list-all-pkgs" -fi -if [ "$skipFiles" ];then - for i in $(echo $skipFiles | tr "," "\n") - do - ARGS="$ARGS --skip-files $i" - SARIF_ARGS="$SARIF_ARGS --skip-files $i" - done +# Handle SARIF +if [ "${TRIVY_FORMAT:-}" = "sarif" ]; then + if [ "${INPUT_LIMIT_SEVERITIES_FOR_SARIF:-false,,}" != "true" ]; then + echo "Building SARIF report with all severities" + unset TRIVY_SEVERITY + else + echo "Building SARIF report" + fi fi -trivyConfig=$(echo $trivyConfig | tr -d '\r') -# To make sure that uploda GitHub Dependency Snapshot succeeds, disable the script that fails first. -set +e -if [ "${format}" == "sarif" ] && [ "${limitSeveritiesForSARIF}" != "true" ]; then - # SARIF is special. We output all vulnerabilities, - # regardless of severity level specified in this report. - # This is a feature, not a bug :) - echo "Building SARIF report with options: ${SARIF_ARGS}" "${artifactRef}" - trivy --quiet ${scanType} --format sarif --output ${output} $SARIF_ARGS ${artifactRef} -elif [ $trivyConfig ]; then - echo "Running Trivy with trivy.yaml config from: " $trivyConfig - trivy --config $trivyConfig ${scanType} ${artifactRef} -else - echo "Running trivy with options: trivy ${scanType} ${ARGS}" "${artifactRef}" - echo "Global options: " "${GLOBAL_ARGS}" - trivy $GLOBAL_ARGS ${scanType} ${ARGS} ${artifactRef} -fi +# Run Trivy +cmd=(trivy "$scanType" "$scanRef") +echo "Running Trivy with options: ${cmd[*]}" +"${cmd[@]}" returnCode=$? -set -e -if [[ "${format}" == "github" ]]; then - if [[ "$(echo $githubPAT | xargs)" != "" ]]; then +if [ "${TRIVY_FORMAT:-}" = "github" ]; then + if [ -n "${INPUT_GITHUB_PAT:-}" ]; then printf "\n Uploading GitHub Dependency Snapshot" - curl -H 'Accept: application/vnd.github+json' -H "Authorization: token $githubPAT" 'https://api.github.com/repos/'$GITHUB_REPOSITORY'/dependency-graph/snapshots' -d @./$(echo $output | xargs) + curl -H 'Accept: application/vnd.github+json' -H "Authorization: token ${INPUT_GITHUB_PAT}" \ + "https://api.github.com/repos/$GITHUB_REPOSITORY/dependency-graph/snapshots" -d @"${TRIVY_OUTPUT:-}" else - printf "\n Failing GitHub Dependency Snapshot. Missing github-pat" + printf "\n Failing GitHub Dependency Snapshot. Missing github-pat" >&2 fi fi -exit $returnCode +exit $returnCode \ No newline at end of file diff --git a/test/test.bats b/test/test.bats index 7e1a036f..7b14b53f 100644 --- a/test/test.bats +++ b/test/test.bats @@ -34,6 +34,13 @@ function remove_github_fields() { fi } +function reset_envs() { + local var + for var in $(env | grep '^TRIVY_\|^INPUT_' | cut -d= -f1); do + unset "$var" + done +} + function compare_files() { local file1="$1" local file2="$2" @@ -56,68 +63,90 @@ function compare_files() { @test "trivy repo with securityCheck secret only" { # trivy repo -f json -o repo.test --scanners=secret https://github.com/krol3/demo-trivy/ - run ./entrypoint.sh '-b json' '-h repo.json' '-s secret' '-a repo' '-j https://github.com/krol3/demo-trivy/' + export TRIVY_FORMAT=json TRIVY_OUTPUT=repo.json TRIVY_SCANNERS=secret INPUT_SCAN_TYPE=repo INPUT_SCAN_REF="https://github.com/krol3/demo-trivy/" + ./entrypoint.sh compare_files repo.json ./test/data/secret-scan/report.json + reset_envs } @test "trivy image" { # trivy image --severity CRITICAL -o image.test knqyf263/vuln-image:1.2.3 - run ./entrypoint.sh '-a image' '-i knqyf263/vuln-image:1.2.3' '-h image.test' '-g CRITICAL' + export TRIVY_OUTPUT=image.test TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 + ./entrypoint.sh compare_files image.test ./test/data/image-scan/report + reset_envs } @test "trivy config sarif report" { # trivy config -f sarif -o config-sarif.test ./test/data/config-sarif-report - run ./entrypoint.sh '-a config' '-b sarif' '-h config-sarif.sarif' '-j ./test/data/config-sarif-report/main.tf' + export TRIVY_FORMAT=sarif TRIVY_OUTPUT=config-sarif.sarif INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/config-sarif-report + ./entrypoint.sh compare_files config-sarif.sarif ./test/data/config-sarif-report/report.sarif + reset_envs } @test "trivy config" { # trivy config -f json -o config.json ./test/data/config-scan - run ./entrypoint.sh '-a config' '-b json' '-j ./test/data/config-scan' '-h config.json' + export TRIVY_FORMAT=json TRIVY_OUTPUT=config.json INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/config-scan + ./entrypoint.sh compare_files config.json ./test/data/config-scan/report.json + reset_envs } @test "trivy rootfs" { # trivy rootfs --output rootfs.test ./test/data/rootfs-scan # TODO: add data - run ./entrypoint.sh '-a rootfs' '-j ./test/data/rootfs-scan' '-h rootfs.test' + export TRIVY_OUTPUT=rootfs.test INPUT_SCAN_TYPE=rootfs INPUT_SCAN_REF=./test/data/rootfs-scan + ./entrypoint.sh compare_files rootfs.test ./test/data/rootfs-scan/report + reset_envs } @test "trivy fs" { # trivy fs --output fs.test ./test/data/fs-scan # TODO: add data - run ./entrypoint.sh '-a fs' '-j ./test/data/fs-scan' '-h fs.test' + export TRIVY_OUTPUT=fs.test INPUT_SCAN_TYPE=fs INPUT_SCAN_REF=./test/data/fs-scan + ./entrypoint.sh compare_files fs.test ./test/data/fs-scan/report + reset_envs } @test "trivy image with trivyIgnores option" { # cat ./test/data/with-ignore-files/.trivyignore1 ./test/data/with-ignore-files/.trivyignore2 > ./trivyignores ; trivy image --severity CRITICAL --output image-trivyignores.test --ignorefile ./trivyignores knqyf263/vuln-image:1.2.3 - run ./entrypoint.sh '-a image' '-i knqyf263/vuln-image:1.2.3' '-h image-trivyignores.test' '-g CRITICAL' '-t ./test/data/with-ignore-files/.trivyignore1,./test/data/with-ignore-files/.trivyignore2' + export TRIVY_OUTPUT=image-trivyignores.test TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_IMAGE_REF=knqyf263/vuln-image:1.2.3 INPUT_TRIVYIGNORES="./test/data/with-ignore-files/.trivyignore1,./test/data/with-ignore-files/.trivyignore2" + ./entrypoint.sh compare_files image-trivyignores.test ./test/data/with-ignore-files/report + reset_envs } @test "trivy image with sbom output" { - # trivy image --format github knqyf263/vuln-image:1.2.3 - run ./entrypoint.sh "-a image" "-b github" "-h github-dep-snapshot.gsbom" "-i knqyf263/vuln-image:1.2.3" + # trivy image --format github knqyf263/vuln-image:1.2.3 + export TRIVY_FORMAT=github TRIVY_OUTPUT=github-dep-snapshot.gsbom INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 + ./entrypoint.sh compare_files github-dep-snapshot.gsbom ./test/data/github-dep-snapshot/report.gsbom + reset_envs } @test "trivy image with trivy.yaml config" { # trivy --config=./test/data/with-trivy-yaml-cfg/trivy.yaml image alpine:3.10 - run ./entrypoint.sh "-v ./test/data/with-trivy-yaml-cfg/trivy.yaml" "-a image" "-i alpine:3.10" + export TRIVY_CONFIG=./test/data/with-trivy-yaml-cfg/trivy.yaml INPUT_SCAN_TYPE=image INPUT_SCAN_REF=alpine:3.10 + ./entrypoint.sh compare_files yamlconfig.json ./test/data/with-trivy-yaml-cfg/report.json + reset_envs } @test "trivy image with custom docker-host" { # trivy image --docker-host unix:///var/run/docker.sock --severity CRITICAL --output image.test knqyf263/vuln-image:1.2.3 - run ./entrypoint.sh '-y unix:///var/run/docker.sock' '-a image' '-i knqyf263/vuln-image:1.2.3' '-h image.test' '-g CRITICAL' + export TRIVY_OUTPUT=image.test TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 TRIVY_DOCKER_HOST=unix:///var/run/docker.sock + ./entrypoint.sh compare_files image.test ./test/data/image-scan/report + reset_envs } @test "trivy config with terraform variables" { - # trivy config -f json -o tfvars.json --severity MEDIUM --tf-vars ./test/data/with-tf-vars/dev.tfvars ./test/data/with-tf-vars/main.tf - run ./entrypoint.sh "-a config" "-j ./test/data/with-tf-vars/main.tf" "-h tfvars.json" "-g MEDIUM" "-x ./test/data/with-tf-vars/dev.tfvars" "-b json" + # trivy config -f json -o tfvars.json --severity MEDIUM --tf-vars ./test/data/with-tf-vars/dev.tfvars ./test/data/with-tf-vars/main.tf + export TRIVY_FORMAT=json TRIVY_SEVERITY=MEDIUM TRIVY_OUTPUT=tfvars.json INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/with-tf-vars/main.tf TRIVY_TF_VARS=./test/data/with-tf-vars/dev.tfvars + ./entrypoint.sh compare_files tfvars.json ./test/data/with-tf-vars/report.json + reset_envs } \ No newline at end of file