name: CI on: pull_request: jobs: test-setup-db: name: Test Setup DB runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup DB id: setup-db uses: ./setup-db - name: Verify vulnerability DB in cache run: | set -euo pipefail cache="${{ steps.setup-db.outputs.cache-dir }}" db="$cache/db/trivy.db" meta="$cache/db/metadata.json" test -f "$meta" || { echo "FAIL: $meta missing (DB not downloaded?)"; exit 1; } test -f "$db" || { echo "FAIL: $db missing (DB not downloaded?)"; exit 1; } size=$(stat -c%s "$db") min=$((3 * 1024 * 1024)) if [ "$size" -lt "$min" ]; then echo "FAIL: trivy.db too small ($size bytes; expected at least $min bytes, i.e. a few MiB)" exit 1 fi echo "OK: trivy.db is present ($size bytes) and metadata.json exists." test-scan-config: name: Test scan-config runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Trivy DB cache id: db uses: ./setup-db - name: Create ephemeral config fixture id: fixture run: | set -euo pipefail scan="${{ github.workspace }}/.ci-trivy-scan-config" reports="${{ github.workspace }}/.ci-trivy-reports-config" mkdir -p "$scan" "$reports" printf '%s\n' 'FROM alpine:3.20' > "$scan/Dockerfile" echo "scan-path=$scan" >> "$GITHUB_OUTPUT" echo "reports=$reports" >> "$GITHUB_OUTPUT" - name: Run scan-config id: scan uses: ./scan-config with: scan-path: ${{ steps.fixture.outputs.scan-path }} cache-dir: ${{ steps.db.outputs.cache-dir }} output-dir: ${{ steps.fixture.outputs.reports }} output-file: report.sarif - name: Check output file exists run: test -f "${{ steps.scan.outputs.output-path }}" test-scan-fs: name: Test scan-fs runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Trivy DB cache id: db uses: ./setup-db - name: Create ephemeral filesystem fixture id: fixture run: | set -euo pipefail scan="${{ github.workspace }}/.ci-trivy-scan-fs" reports="${{ github.workspace }}/.ci-trivy-reports-fs" mkdir -p "$scan" "$reports" printf '%s\n' '{"private":true,"name":"trivy-ci-fixture"}' > "$scan/package.json" echo "scan-path=$scan" >> "$GITHUB_OUTPUT" echo "reports=$reports" >> "$GITHUB_OUTPUT" - name: Run scan-fs id: scan uses: ./scan-fs with: scan-path: ${{ steps.fixture.outputs.scan-path }} cache-dir: ${{ steps.db.outputs.cache-dir }} output-dir: ${{ steps.fixture.outputs.reports }} output-file: report.sarif - name: Check output file exists run: test -f "${{ steps.scan.outputs.output-path }}" test-scan-image: name: Test scan-image runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Trivy DB cache id: db uses: ./setup-db - name: Prepare report directory id: fixture run: | set -euo pipefail reports="${{ github.workspace }}/.ci-trivy-reports-image" mkdir -p "$reports" echo "reports=$reports" >> "$GITHUB_OUTPUT" - name: Run scan-image id: scan uses: ./scan-image with: image: ghcr.io/aquasecurity/trivy:0.69.3@sha256:bcc376de8d77cfe086a917230e818dc9f8528e3c852f7b1aff648949b6258d1c cache-dir: ${{ steps.db.outputs.cache-dir }} output-dir: ${{ steps.fixture.outputs.reports }} output-file: report.sarif - name: Check output file exists run: test -f "${{ steps.scan.outputs.output-path }}" test-get-images-from-files: name: Test Get Images From Files runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - id: giff uses: ./get-images-from-files with: files: | - get-images-from-files/test.Dockerfile - get-images-from-files/test-deployment.yaml - get-images-from-files/test-compose.yaml - get-images-from-files/test-values-helmfile.yaml - name: Check image formats extracted run: | images='${{ steps.giff.outputs.images }}' echo "JSON array (for manual inspection):" echo "$images" | jq . echo "" check() { echo -n " $1: "; echo "$images" | jq -e --arg ref "$2" 'index($ref) != null' >/dev/null && echo "OK" || { echo "FAIL (not found)"; exit 1; }; } # Dockerfile-only refs check "Dockerfile registry+tag (nginx:v1)" "example.com/library/nginx:v1" check "Dockerfile registry+digest (base@sha256:...)" "example.com/library/base@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # K8s-only refs check "K8s registry+tag (app:v2)" "example.com/library/app:v2" check "K8s registry+digest (helper@sha256:...)" "example.com/myproject/helper@sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" # Compose-only refs check "Compose registry+tag (web:v3)" "example.com/compose/web:v3" check "Compose registry+tag (worker:v3)" "example.com/compose/worker:v3" # Helmfile values (repository + tag, optional registry) check "Helmfile image (repository+tag)" "example.com/helmfile/app:v4" check "Helmfile images.worker (repository+tag)" "example.com/helmfile/worker:v5" check "Helmfile images.helper (repository+tag with digest)" "example.com/myproject/helper:2.0@sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" # Shared ref (in both files) — must appear exactly once check "Shared ref present (distroless/static:nonroot)" "example.com/distroless/static:nonroot" count=$(echo "$images" | jq '[.[] | select(. == "example.com/distroless/static:nonroot")] | length') echo -n " Shared ref appears once (no duplicates): " [ "$count" -eq 1 ] && echo "OK (count=$count)" || { echo "FAIL (count=$count, expected 1)"; exit 1; } total=$(echo "$images" | jq 'length') echo -n " Total unique refs: " [ "$total" -eq 10 ] && echo "OK ($total)" || { echo "FAIL (got $total, expected 10)"; exit 1; } echo "" echo "All checks passed." test-merge-sarif-files: name: Test Merge SARIF Files runs-on: - ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Merge SARIF Files uses: ./merge-sarif-files with: files: | - merge-sarif-files/test_sarif1.json - merge-sarif-files/test_sarif2.json output-file: merged.sarif - name: Check merged SARIF file run: | # Structure: version, schema, 2 runs run_count=$(jq '.runs | length' merged.sarif) [ "$run_count" -eq 2 ] || { echo "FAIL: expected 2 runs, got $run_count"; exit 1; } echo "Merged SARIF has $run_count runs." jq -e '.version and .["$schema"] and (.runs | length > 0)' merged.sarif >/dev/null || { echo "FAIL: invalid SARIF structure"; exit 1; } # Content: results from test_sarif1.json (ruleId KSV-0014) and test_sarif2.json (ruleId CVE-2026-26019) must be present rule_ids=$(jq -r '[.runs[].results[].ruleId] | unique[]' merged.sarif) echo "$rule_ids" | grep -q 'KSV-0014' || { echo "FAIL: merged file missing result from test_sarif1.json (ruleId KSV-0014)"; exit 1; } echo "$rule_ids" | grep -q 'CVE-2026-26019' || { echo "FAIL: merged file missing result from test_sarif2.json (ruleId CVE-2026-26019)"; exit 1; } echo "Merged results contain ruleIds from both input files." echo "All checks passed."