From 6476b939eabc74a8cbd2f6dceb44968c3187134c Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 20 Feb 2026 18:04:32 +0600 Subject: [PATCH] feat: support for YAML ignore file Signed-off-by: Nikita Pivkin --- .gitignore | 5 +- Makefile | 59 +++- README.md | 2 +- entrypoint.sh | 56 +++- test/data/with-trivy-yaml-cfg/trivy.yaml | 4 +- .../with-yaml-ignore-file/.trivyignore.yaml | 3 + test/data/with-yaml-ignore-file/report | 102 +++++++ test/test.bats | 277 ++++++++++++------ 8 files changed, 386 insertions(+), 122 deletions(-) create mode 100644 test/data/with-yaml-ignore-file/.trivyignore.yaml create mode 100644 test/data/with-yaml-ignore-file/report diff --git a/.gitignore b/.gitignore index 2c0ef83..cd9db72 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ trivyignores .vscode/ -.cache \ No newline at end of file +.cache + +# Local tools +.bin/ diff --git a/Makefile b/Makefile index c9e9058..27944a4 100644 --- a/Makefile +++ b/Makefile @@ -8,30 +8,65 @@ else BATS_LIB_PATH ?= /usr/local/lib/ endif +LOCAL_BIN := $(CURDIR)/.bin +LOCAL_TRIVY := $(LOCAL_BIN)/trivy + +ifeq ($(shell [ -f $(LOCAL_TRIVY) ] && [ -z "$(CI)" ] && echo yes),yes) +TRIVY_CMD := $(LOCAL_TRIVY) +else +TRIVY_CMD ?= trivy +endif + +CACHE_DIR := '.cache' + +TRIVY_VERSION_FILE := .github/workflows/test.yaml +CURRENT_TRIVY_VERSION := $(shell awk '/TRIVY_VERSION:/ {print $$2}' $(TRIVY_VERSION_FILE)) + BATS_ENV := BATS_LIB_PATH=$(BATS_LIB_PATH) \ GITHUB_REPOSITORY_OWNER=aquasecurity \ - TRIVY_CACHE_DIR=.cache \ - TRIVY_DISABLE_VEX_NOTICE=true \ + TRIVY_CACHE_DIR=$(CACHE_DIR) \ TRIVY_DEBUG=true -BATS_FLAGS := --recursive --timing --verbose-run . +BATS_FLAGS := --timing --verbose-run test/test.bats .PHONY: test -test: init-cache - $(BATS_ENV) bats $(BATS_FLAGS) +test: + TRIVY_CMD=$(TRIVY_CMD) $(BATS_ENV) bats $(BATS_FLAGS) .PHONY: update-golden -update-golden: init-cache - UPDATE_GOLDEN=1 $(BATS_ENV) bats $(BATS_FLAGS) +update-golden: + UPDATE_GOLDEN=1 TRIVY_CMD=$(TRIVY_CMD) $(BATS_ENV) bats $(BATS_FLAGS) .PHONY: init-cache init-cache: - mkdir -p .cache - rm -f .cache/fanal/fanal.db + mkdir -p $(CACHE_DIR) + +.PHONY: clean-cache +clean-cache: + $(TRIVY_CMD) clean --scan-cache --cache-dir $(CACHE_DIR) bump-trivy: @[ $$NEW_VERSION ] || ( echo "env 'NEW_VERSION' is not set"; exit 1 ) - @CURRENT_VERSION=$$(grep "TRIVY_VERSION:" .github/workflows/test.yaml | awk '{print $$2}');\ - echo Current version: $$CURRENT_VERSION ;\ + @echo Current version: $(CURRENT_TRIVY_VERSION) ;\ echo New version: $$NEW_VERSION ;\ - $(SED) -i -e "s/$$CURRENT_VERSION/$$NEW_VERSION/g" README.md action.yaml .github/workflows/test.yaml ;\ + $(SED) -i -e "s/$(CURRENT_TRIVY_VERSION)/$$NEW_VERSION/g" \ + README.md action.yaml $(TRIVY_VERSION_FILE) + +.PHONY: ensure-trivy +ensure-trivy: + @set -e; \ + mkdir -p $(LOCAL_BIN); \ + if [ -x $(LOCAL_TRIVY) ]; then \ + CURRENT_VERSION="$$( $(LOCAL_TRIVY) version -f json | jq -r '.Version' )"; \ + else \ + CURRENT_VERSION=none; \ + fi; \ + echo "Required: $(CURRENT_TRIVY_VERSION)"; \ + echo "Current: $$CURRENT_VERSION"; \ + if [ "$$CURRENT_VERSION" != "$(CURRENT_TRIVY_VERSION)" ]; then \ + echo "Installing Trivy $(CURRENT_TRIVY_VERSION) locally..."; \ + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | \ + sh -s -- -b $(LOCAL_BIN) v$(CURRENT_TRIVY_VERSION); \ + else \ + echo "Trivy $(CURRENT_TRIVY_VERSION) already present."; \ + fi \ No newline at end of file diff --git a/README.md b/README.md index 791b7b4..3c9e9aa 100644 --- a/README.md +++ b/README.md @@ -886,7 +886,7 @@ Following inputs can be used as `step.with` keys: | `hide-progress` | String | `false` | Suppress progress bar and log output | | `list-all-pkgs` | String | | Output all packages regardless of vulnerability | | `scanners` | String | `vuln,secret` | comma-separated list of what security issues to detect (`vuln`,`secret`,`misconfig`,`license`) | -| `trivyignores` | String | | comma-separated list of relative paths in repository to one or more `.trivyignore` files | +| `trivyignores` | String | | comma-separated list of relative paths in repository to one or more `.trivyignore` or `.trivyignore.yaml` files. | | `trivy-config` | String | | Path to trivy.yaml config | | `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** | diff --git a/entrypoint.sh b/entrypoint.sh index 2af9d0e..4bdfe7e 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,9 @@ #!/bin/bash set -euo pipefail +# Allow overriding trivy binary via env +TRIVY_CMD="${TRIVY_CMD:-trivy}" + # Read TRIVY_* envs from file, previously they were written to the GITHUB_ENV file but GitHub Actions automatically # injects those into subsequent job steps which means inputs from one trivy-action invocation were leaking over to # any subsequent invocation which led to unexpected/undesireable behaviour from a user perspective @@ -18,22 +21,55 @@ fi # Handle trivy ignores if [ -n "${INPUT_TRIVYIGNORES:-}" ]; then - ignorefile="./trivyignores" - # Clear the ignore file if it exists, or create a new empty file - : > "$ignorefile" + yaml_count=0 + plain_count=0 + # Validate files and detect types for f in ${INPUT_TRIVYIGNORES//,/ }; do - if [ -f "$f" ]; then - echo "Found ignorefile '${f}':" - cat "${f}" - cat "${f}" >> "$ignorefile" - else + if [ ! -f "$f" ]; then echo "ERROR: cannot find ignorefile '${f}'." >&2 exit 1 fi + + case "$f" in + *.yml|*.yaml) yaml_count=$((yaml_count + 1)) ;; + *) plain_count=$((plain_count + 1)) ;; + esac done - export TRIVY_IGNOREFILE="$ignorefile" + + # Mixed types are not allowed + if [ "$yaml_count" -gt 0 ] && [ "$plain_count" -gt 0 ]; then + echo "ERROR: Cannot mix YAML and plain trivy ignore files." >&2 + exit 1 + fi + + # YAML mode + if [ "$yaml_count" -gt 0 ]; then + if [ "$yaml_count" -gt 1 ]; then + echo "ERROR: Multiple YAML ignore files provided. Only one YAML file is supported." >&2 + exit 1 + fi + + # Use the single YAML file + yaml_file=$(echo ${INPUT_TRIVYIGNORES//,/ } | awk '{print $1}') + echo "Using YAML ignorefile '$yaml_file':" + cat "$yaml_file" + export TRIVY_IGNOREFILE="$yaml_file" + + else + # Plain mode (old behaviour) + ignorefile="./trivyignores" + : > "$ignorefile" + + for f in ${INPUT_TRIVYIGNORES//,/ }; do + echo "Found ignorefile '$f':" + cat "$f" + cat "$f" >> "$ignorefile" + done + + export TRIVY_IGNOREFILE="$ignorefile" + fi fi # Handle SARIF @@ -47,7 +83,7 @@ if [ "${TRIVY_FORMAT:-}" = "sarif" ]; then fi # Run Trivy -cmd=(trivy "$scanType" "$scanRef") +cmd=("$TRIVY_CMD" "$scanType" "$scanRef") echo "Running Trivy with options: ${cmd[*]}" "${cmd[@]}" returnCode=$? diff --git a/test/data/with-trivy-yaml-cfg/trivy.yaml b/test/data/with-trivy-yaml-cfg/trivy.yaml index 33fdd4e..88b7ea5 100644 --- a/test/data/with-trivy-yaml-cfg/trivy.yaml +++ b/test/data/with-trivy-yaml-cfg/trivy.yaml @@ -1,5 +1,3 @@ -format: json severity: CRITICAL vulnerability: - type: os -output: yamlconfig.json \ No newline at end of file + type: os \ No newline at end of file diff --git a/test/data/with-yaml-ignore-file/.trivyignore.yaml b/test/data/with-yaml-ignore-file/.trivyignore.yaml new file mode 100644 index 0000000..52df0d3 --- /dev/null +++ b/test/data/with-yaml-ignore-file/.trivyignore.yaml @@ -0,0 +1,3 @@ +vulnerabilities: + - id: CVE-2018-14618 + - id: CVE-2018-16839 diff --git a/test/data/with-yaml-ignore-file/report b/test/data/with-yaml-ignore-file/report new file mode 100644 index 0000000..6fdc99e --- /dev/null +++ b/test/data/with-yaml-ignore-file/report @@ -0,0 +1,102 @@ + +Report Summary + +┌──────────────────────────────────────────┬────────┬─────────────────┬─────────┐ +│ Target │ Type │ Vulnerabilities │ Secrets │ +├──────────────────────────────────────────┼────────┼─────────────────┼─────────┤ +│ knqyf263/vuln-image:1.2.3 (alpine 3.7.1) │ alpine │ 16 │ - │ +├──────────────────────────────────────────┼────────┼─────────────────┼─────────┤ +│ rust-app/Cargo.lock │ cargo │ 4 │ - │ +└──────────────────────────────────────────┴────────┴─────────────────┴─────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + + +knqyf263/vuln-image:1.2.3 (alpine 3.7.1) +======================================== +Total: 16 (CRITICAL: 16) + +┌─────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ curl │ CVE-2018-16840 │ CRITICAL │ fixed │ 7.61.0-r0 │ 7.61.1-r1 │ curl: Use-after-free when closing "easy" handle in │ +│ │ │ │ │ │ │ Curl_close() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-16840 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2018-16842 │ │ │ │ │ curl: Heap-based buffer over-read in the curl tool warning │ +│ │ │ │ │ │ │ formatting │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-16842 │ +│ ├────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-3822 │ │ │ │ 7.61.1-r2 │ curl: NTLMv2 type-3 header stack buffer overflow │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-3822 │ +│ ├────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-5481 │ │ │ │ 7.61.1-r3 │ curl: double free due to subsequent call of realloc() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-5481 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-5482 │ │ │ │ │ curl: heap buffer overflow in function tftp_receive_packet() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-5482 │ +├─────────────┼────────────────┤ │ ├───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ git │ CVE-2018-17456 │ │ │ 2.15.2-r0 │ 2.15.3-r0 │ git: arbitrary code execution via .gitmodules │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-17456 │ +│ ├────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-1353 │ │ │ │ 2.15.4-r0 │ git: NTFS protections inactive when running Git in the │ +│ │ │ │ │ │ │ Windows Subsystem for... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-1353 │ +├─────────────┼────────────────┤ │ ├───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ libbz2 │ CVE-2019-12900 │ │ │ 1.0.6-r6 │ 1.0.6-r7 │ bzip2: bzip2: Data integrity error when decompressing (with │ +│ │ │ │ │ │ │ data integrity tests fail).... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-12900 │ +├─────────────┼────────────────┤ │ ├───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ libcurl │ CVE-2018-16840 │ │ │ 7.61.1-r0 │ 7.61.1-r1 │ curl: Use-after-free when closing "easy" handle in │ +│ │ │ │ │ │ │ Curl_close() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-16840 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2018-16842 │ │ │ │ │ curl: Heap-based buffer over-read in the curl tool warning │ +│ │ │ │ │ │ │ formatting │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-16842 │ +│ ├────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-3822 │ │ │ │ 7.61.1-r2 │ curl: NTLMv2 type-3 header stack buffer overflow │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-3822 │ +│ ├────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-5481 │ │ │ │ 7.61.1-r3 │ curl: double free due to subsequent call of realloc() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-5481 │ +│ ├────────────────┤ │ │ │ ├──────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-5482 │ │ │ │ │ curl: heap buffer overflow in function tftp_receive_packet() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-5482 │ +├─────────────┼────────────────┤ │ ├───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ musl │ CVE-2019-14697 │ │ │ 1.1.18-r3 │ 1.1.18-r4 │ musl libc through 1.1.23 has an x87 floating-point stack │ +│ │ │ │ │ │ │ adjustment im ...... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-14697 │ +├─────────────┤ │ │ │ │ │ │ +│ musl-utils │ │ │ │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ │ │ │ │ +├─────────────┼────────────────┤ │ ├───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ sqlite-libs │ CVE-2019-8457 │ │ │ 3.21.0-r1 │ 3.25.3-r1 │ sqlite: heap out-of-bound read in function rtreenode() │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-8457 │ +└─────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴──────────────────────────────────────────────────────────────┘ + +rust-app/Cargo.lock (cargo) +=========================== +Total: 4 (CRITICAL: 4) + +┌───────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├───────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤ +│ rand_core │ CVE-2020-25576 │ CRITICAL │ fixed │ 0.4.0 │ 0.4.2, 0.3.1 │ An issue was discovered in the rand_core crate before 0.4.2 │ +│ │ │ │ │ │ │ for Rust.... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-25576 │ +├───────────┼────────────────┤ │ ├───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤ +│ smallvec │ CVE-2019-15551 │ │ │ 0.6.9 │ 0.6.10 │ An issue was discovered in the smallvec crate before 0.6.10 │ +│ │ │ │ │ │ │ for Rust.... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-15551 │ +│ ├────────────────┤ │ │ │ ├─────────────────────────────────────────────────────────────┤ +│ │ CVE-2019-15554 │ │ │ │ │ An issue was discovered in the smallvec crate before 0.6.10 │ +│ │ │ │ │ │ │ for Rust.... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-15554 │ +│ ├────────────────┤ │ │ ├───────────────┼─────────────────────────────────────────────────────────────┤ +│ │ CVE-2021-25900 │ │ │ │ 0.6.14, 1.6.1 │ An issue was discovered in the smallvec crate before 0.6.14 │ +│ │ │ │ │ │ │ and 1.x... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-25900 │ +└───────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴─────────────────────────────────────────────────────────────┘ diff --git a/test/test.bats b/test/test.bats index 0857699..70c1e0d 100644 --- a/test/test.bats +++ b/test/test.bats @@ -1,41 +1,39 @@ #!/usr/bin/env bats +bats_load_library bats-support +bats_load_library bats-assert +bats_load_library bats-file + setup_file() { - local owner=$GITHUB_REPOSITORY_OWNER - export TRIVY_DB_REPOSITORY=ghcr.io/${owner}/trivy-db-act:latest - export TRIVY_JAVA_DB_REPOSITORY=ghcr.io/${owner}/trivy-java-db-act:latest - export TRIVY_CHECKS_BUNDLE_REPOSITORY=ghcr.io/${owner}/trivy-checks-act:latest - export TRIVY_LIST_ALL_PKGS=false + setup_trivy_env + docker pull knqyf263/vuln-image:1.2.3 1>&3 2>&3 + trivy image --download-db-only 1>&3 2>&3 } setup() { - bats_load_library bats-support - bats_load_library bats-assert - bats_load_library bats-file + export TRIVY_OUTPUT="$BATS_TEST_TMPDIR/output.test" + export TRIVY_SKIP_DB_UPDATE=true + export TRIVY_SKIP_JAVA_DB_UPDATE=true } -function remove_json_fields() { - local file="$1" - if [[ "$file" == *.json ]]; then - jq 'del(.CreatedAt, .ReportID)' "$file" > tmp && mv tmp "$file" - fi +teardown() { + reset_envs } -function remove_sarif_fields() { - local file="$1" - if [[ "$file" == *.sarif ]]; then - jq 'del(.runs[].tool.driver.version) | del(.runs[].originalUriBaseIds)' "$file" > tmp && mv tmp "$file" - fi +setup_trivy_env() { + local owner="${GITHUB_REPOSITORY_OWNER:-aquasecurity}" + + export TRIVY_DB_REPOSITORY="ghcr.io/${owner}/trivy-db-act:latest" + export TRIVY_JAVA_DB_REPOSITORY="ghcr.io/${owner}/trivy-java-db-act:latest" + export TRIVY_CHECKS_BUNDLE_REPOSITORY="ghcr.io/${owner}/trivy-checks-act:latest" + + export TRIVY_LIST_ALL_PKGS=false + export TRIVY_DISABLE_VEX_NOTICE=true + export TRIVY_SKIP_VERSION_CHECK=true + export TRIVY_DISABLE_TELEMETRY=true } -function remove_github_fields() { - local file="$1" - if [[ "$file" == *.gsbom ]]; then - jq 'del(.detector.version) | del(.scanned) | del(.job) | del(.ref) | del(.sha)' "$file" > tmp && mv tmp "$file" - fi -} - -function reset_envs() { +reset_envs() { local var for var in $(env | grep '^TRIVY_\|^INPUT_' | cut -d= -f1); do unset "$var" @@ -43,133 +41,161 @@ function reset_envs() { rm -f trivy_envs.txt } -function compare_files() { - local file1="$1" - local file2="$2" +compare_files() { + local actual="$1" + local expected="$2" # Some fields should be removed as they are environment dependent # and may cause undesirable results when comparing files. - remove_json_fields "$file1" - remove_json_fields "$file2" - - remove_sarif_fields "$file1" - remove_sarif_fields "$file2" - - remove_github_fields "$file1" - remove_github_fields "$file2" + normalize_report "$actual" + normalize_report "$expected" if [ "${UPDATE_GOLDEN}" = "1" ]; then - cp "$file1" "$file2" - echo "Updated golden file: $file2" + cp "$actual" "$expected" + echo "Updated golden file: $expected" else - run diff "$file1" "$file2" + run diff "$actual" "$expected" echo "$output" - assert_files_equal "$file1" "$file2" + assert_files_equal "$actual" "$expected" fi - rm -f "$file1" + rm -f "$actual" +} + + +normalize_report() { + local file="$1" + + case "$TRIVY_FORMAT" in + json) + apply_jq_filter "$file" \ + 'del(.CreatedAt, .ReportID)' + ;; + sarif) + apply_jq_filter "$file" \ + 'del(.runs[].tool.driver.version) + | del(.runs[].originalUriBaseIds)' + ;; + github) + apply_jq_filter "$file" \ + 'del(.detector.version) + | del(.scanned) + | del(.job) + | del(.ref) + | del(.sha)' + ;; + esac +} + +apply_jq_filter() { + local file="$1" + local filter="$2" + local tmp="$BATS_TEST_TMPDIR/jq.tmp" + + jq "$filter" "$file" > "$tmp" && mv "$tmp" "$file" +} + +run_test_case_compare() { + local expected_file="$1" + + run ./entrypoint.sh + assert_success + + compare_files "$TRIVY_OUTPUT" "$expected_file" +} + +run_test_case_fails() { + local expected_msg="$1" + + run ./entrypoint.sh + assert_failure + + if [ -n "$expected_msg" ]; then + assert_output --partial "$expected_msg" + fi } @test "trivy repo with securityCheck secret only" { # trivy repo -f json -o repo.test --scanners=secret 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 + export TRIVY_FORMAT=json TRIVY_SCANNERS=secret INPUT_SCAN_TYPE=repo INPUT_SCAN_REF="https://github.com/krol3/demo-trivy/" + run_test_case_compare ./test/data/secret-scan/report.json } @test "trivy image" { # trivy image --severity CRITICAL -o image.test knqyf263/vuln-image:1.2.3 - 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 + export TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 + run_test_case_compare ./test/data/image-scan/report } @test "trivy config sarif report" { # trivy config -f sarif -o config-sarif.test ./test/data/config-sarif-report - 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 + export TRIVY_FORMAT=sarif INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/config-sarif-report + run_test_case_compare ./test/data/config-sarif-report/report.sarif } @test "trivy config" { # trivy config -f json -o config.json ./test/data/config-scan - 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 + export TRIVY_FORMAT=json INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/config-scan + run_test_case_compare ./test/data/config-scan/report.json } @test "trivy rootfs" { # trivy rootfs --output rootfs.test ./test/data/rootfs-scan # TODO: add data - 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 + export INPUT_SCAN_TYPE=rootfs INPUT_SCAN_REF=./test/data/rootfs-scan + run_test_case_compare ./test/data/rootfs-scan/report } @test "trivy fs" { # trivy fs --output fs.test ./test/data/fs-scan # TODO: add data - 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 + export INPUT_SCAN_TYPE=fs INPUT_SCAN_REF=./test/data/fs-scan + run_test_case_compare ./test/data/fs-scan/report } @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 - 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 + export 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" + run_test_case_compare ./test/data/with-ignore-files/report +} + +@test "trivy image with .trivyignore.yaml" { + # trivy image --severity CRITICAL --output with-yaml-ignore-file.test --ignorefile ./test/data/with-yaml-ignore-file/.trivyignore.yaml + export TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_IMAGE_REF=knqyf263/vuln-image:1.2.3 INPUT_TRIVYIGNORES=./test/data/with-yaml-ignore-file/.trivyignore.yaml + run_test_case_compare ./test/data/with-yaml-ignore-file/report } @test "trivy image with sbom output" { # 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 + export TRIVY_FORMAT=github INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 + run_test_case_compare ./test/data/github-dep-snapshot/report.gsbom } @test "trivy image with trivy.yaml config" { # trivy --config=./test/data/with-trivy-yaml-cfg/trivy.yaml image 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 + export TRIVY_CONFIG=./test/data/with-trivy-yaml-cfg/trivy.yaml TRIVY_FORMAT=json INPUT_SCAN_TYPE=image INPUT_SCAN_REF=alpine:3.10 + run_test_case_compare ./test/data/with-trivy-yaml-cfg/report.json } @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 - 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 + export TRIVY_SEVERITY=CRITICAL INPUT_SCAN_TYPE=image INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3 TRIVY_DOCKER_HOST=unix:///var/run/docker.sock + run_test_case_compare ./test/data/image-scan/report } @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 - 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 + export TRIVY_FORMAT=json TRIVY_SEVERITY=MEDIUM INPUT_SCAN_TYPE=config INPUT_SCAN_REF=./test/data/with-tf-vars/main.tf TRIVY_TF_VARS=./test/data/with-tf-vars/dev.tfvars + run_test_case_compare ./test/data/with-tf-vars/report.json } @test "trivy image via environment file" { # trivy image --severity CRITICAL --output image.test knqyf263/vuln-image:1.2.3 # Action injects inputs into the script via environment variables - echo "export TRIVY_OUTPUT=image.test" >> trivy_envs.txt echo "export TRIVY_SEVERITY=CRITICAL" >> trivy_envs.txt echo "export INPUT_SCAN_TYPE=image" >> trivy_envs.txt echo "export INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3" >> trivy_envs.txt - ./entrypoint.sh - compare_files image.test ./test/data/image-scan/report - reset_envs + run_test_case_compare ./test/data/image-scan/report } @test "trivy image via environment file overrides env leakages" { @@ -178,11 +204,72 @@ function compare_files() { # If caller mixes old and new trivy-action version they could still have env leakage so verify that env vars already # in the env are overridden by those from the envs file export INPUT_SCAN_REF=no/such-image:1.2.3 - echo "export TRIVY_OUTPUT=image.test" >> trivy_envs.txt echo "export TRIVY_SEVERITY=CRITICAL" >> trivy_envs.txt echo "export INPUT_SCAN_TYPE=image" >> trivy_envs.txt echo "export INPUT_SCAN_REF=knqyf263/vuln-image:1.2.3" >> trivy_envs.txt - ./entrypoint.sh - compare_files image.test ./test/data/image-scan/report - reset_envs -} \ No newline at end of file + run_test_case_compare ./test/data/image-scan/report +} + +@test "error if ignorefile does not exist" { + missing_file="$BATS_TEST_TMPDIR/missing.ignore" + + export INPUT_TRIVYIGNORES="$missing_file" \ + INPUT_SCAN_TYPE=fs \ + INPUT_SCAN_REF=./test/data/fs-scan + + run_test_case_fails "cannot find ignorefile '$missing_file'" +} + +@test "error with mixed yaml and plain ignore files" { + plain_ignore="$BATS_TEST_TMPDIR/ignore-plain" + yaml_ignore="$BATS_TEST_TMPDIR/ignore.yaml" + + touch "$plain_ignore" "$yaml_ignore" + + export INPUT_TRIVYIGNORES="$plain_ignore,$yaml_ignore" \ + INPUT_SCAN_TYPE=fs \ + INPUT_SCAN_REF=./test/data/fs-scan + + run_test_case_fails "Cannot mix YAML and plain trivy ignore files" +} + +@test "error if multiple YAML files provided" { + yaml1="$BATS_TEST_TMPDIR/ignore1.yaml" + yaml2="$BATS_TEST_TMPDIR/ignore2.yaml" + touch "$yaml1" "$yaml2" + + export INPUT_TRIVYIGNORES="$yaml1,$yaml2" \ + INPUT_SCAN_TYPE=fs \ + INPUT_SCAN_REF=./test/data/fs-scan + + run_test_case_fails "Multiple YAML ignore files provided" +} + +@test "works with a single YAML file" { + yaml="$BATS_TEST_TMPDIR/ignore.yaml" + touch "$yaml" + + export INPUT_TRIVYIGNORES="$yaml" \ + INPUT_SCAN_TYPE=fs \ + INPUT_SCAN_REF=./test/data/fs-scan + + run ./entrypoint.sh + assert_output --partial "Using YAML ignorefile '$yaml'" +} + +@test "works with multiple plain ignore files" { + plain1="$BATS_TEST_TMPDIR/ignore1" + plain2="$BATS_TEST_TMPDIR/ignore2" + echo "CVE-1" > "$plain1" + echo "CVE-2" > "$plain2" + + trivy_output="$BATS_TEST_TMPDIR/trivy-output.test" + + export INPUT_TRIVYIGNORES="$plain1,$plain2" \ + INPUT_SCAN_TYPE=fs \ + INPUT_SCAN_REF=./test/data/fs-scan + + run ./entrypoint.sh + assert_output --partial "Found ignorefile '$plain1'" + assert_output --partial "Found ignorefile '$plain2'" +}