-
Notifications
You must be signed in to change notification settings - Fork 1
ci: add Trivy security scan to PR pipeline #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
bb5d9b7
80a46bd
077837c
9dd46bf
7ddfa2d
7563a74
cfe4a20
95017b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| name: "Trivy" | ||
| description: "Trivy PR security scans. scan: code = repo dependencies (HIGH/CRITICAL) + Dockerfile base images (CRITICAL), image = image built in the pipeline (HIGH/CRITICAL). Each scan uploads its TSV report as an artifact" | ||
|
|
||
| inputs: | ||
| scan: | ||
| description: "code | image" | ||
| required: true | ||
| maven-token: | ||
| description: "Token for internal GitHub Packages: Maven resolution (scan: code) and docker build secret (scan: image)" | ||
| required: false | ||
| default: ${{ github.token }} | ||
| image-name: | ||
| description: "Service name from the build matrix (scan: image)" | ||
| required: false | ||
| dockerfile: | ||
| description: "Path to the service Dockerfile (scan: image)" | ||
| required: false | ||
| context: | ||
| description: "Docker build context (scan: image)" | ||
| required: false | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Install Trivy | ||
| uses: aquasecurity/setup-trivy@v0.3.1 | ||
| with: | ||
| version: v0.73.0 | ||
| cache: true | ||
|
|
||
| - name: Scan dependencies and Dockerfile base images | ||
| if: inputs.scan == 'code' | ||
| shell: bash | ||
| env: | ||
| GITHUB_TOKEN: ${{ inputs.maven-token }} | ||
| GITHUB_ACTOR: ${{ github.actor }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [ -f pom.xml ]; then # warm ~/.m2 via Google's Central mirror so trivy sees parent-managed versions | ||
| echo '<settings><mirrors><mirror><id>google-central</id><url>https://maven-central.storage-download.googleapis.com/maven2/</url><mirrorOf>central</mirrorOf></mirror></mirrors></settings>' > /tmp/mirror.xml | ||
| mvn -B -q -fn -DskipTests -gs /tmp/mirror.xml $([ -f .mvn/settings.xml ] && echo '-s .mvn/settings.xml') dependency:go-offline | tee /tmp/mvn.log || true | ||
| ! grep -q '\[ERROR\]' /tmp/mvn.log || echo "::warning::Some Maven dependencies could not be resolved; scan depth may be reduced" | ||
| fi | ||
| trivy fs --no-progress --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --offline-scan --format json . | | ||
| jq -r '.Results[]? as $r | $r.Vulnerabilities[]? | [.Severity, .PkgName, .InstalledVersion, (.FixedVersion // "-"), .VulnerabilityID, $r.Target] | @tsv' | sort -u > "trivy-${GITHUB_REPOSITORY##*/}-code-report.tsv" | ||
|
|
||
| out="trivy-${GITHUB_REPOSITORY##*/}-docker-report.tsv"; : > "$out" | ||
| find . -name 'Dockerfile*' -not -path './.git/*' -not -path '*/node_modules/*' -print0 | | ||
| xargs -0 -r awk 'toupper($1)=="FROM" {i=$2; if (i ~ /^--/) i=$3; print i; if (toupper($3)=="AS") print "~"$4; if (toupper($4)=="AS") print "~"$5}' | sort -u > /tmp/from.txt | ||
| for img in $(grep -v '^~' /tmp/from.txt); do | ||
| [ "$img" = scratch ] && continue | ||
| case "$img" in *'$'*) echo "::warning::Skipping base image with unresolved variable: ${img}"; continue ;; esac | ||
| grep -qxF "~$img" /tmp/from.txt && continue | ||
| trivy image --no-progress --scanners vuln --severity CRITICAL --ignore-unfixed --format json "$img" | | ||
| jq -r --arg img "$img" '.Results[]? as $r | $r.Vulnerabilities[]? | [.Severity, .PkgName, .InstalledVersion, (.FixedVersion // "-"), .VulnerabilityID, $img] | @tsv' >> "$out" || | ||
| echo "::warning::Base image ${img} could not be scanned (pull/scan error); it was NOT checked" | ||
| done | ||
| sort -u "$out" -o "$out" | ||
| find . -maxdepth 1 -name 'trivy-*.tsv' -empty -delete | ||
|
|
||
| - name: Scan built image | ||
| if: inputs.scan == 'image' | ||
| shell: bash | ||
| env: | ||
| GITHUB_TOKEN: ${{ inputs.maven-token }} | ||
| GITHUB_ACTOR: ${{ github.actor }} | ||
| run: | | ||
| set -euo pipefail | ||
| docker buildx build --platform linux/amd64 --secret id=GITHUB_TOKEN,env=GITHUB_TOKEN --build-arg GITHUB_ACTOR="$GITHUB_ACTOR" \ | ||
| -f "${{ inputs.dockerfile }}" --output type=oci,dest=/tmp/image.tar "${{ inputs.context }}" | ||
| out="trivy-${GITHUB_REPOSITORY##*/}-image-report-${{ inputs.image-name }}.tsv" | ||
| trivy image --no-progress --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --input /tmp/image.tar --format json | | ||
| jq -r '.Results[]? as $r | $r.Vulnerabilities[]? | [.Severity, .PkgName, .InstalledVersion, (.FixedVersion // "-"), .VulnerabilityID, $r.Target] | @tsv' | sort -u > "$out" | ||
| find . -maxdepth 1 -name 'trivy-*.tsv' -empty -delete | ||
|
|
||
| - name: Upload report | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: ${{ inputs.scan == 'code' && format('trivy-{0}-code-report', github.event.repository.name) || format('trivy-{0}-image-report-{1}', github.event.repository.name, inputs.image-name) }} | ||
| path: trivy-*.tsv | ||
| if-no-files-found: ignore | ||
|
|
||
| - name: Evaluate | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| files=$(ls trivy-*.tsv 2>/dev/null) || { echo "No vulnerabilities found."; exit 0; } | ||
| column -t -s "$(printf '\t')" $files | ||
| echo "::error::Trivy found $(cut -f1,2,5 $files | sort -u | wc -l | tr -d ' ') unique HIGH/CRITICAL vulnerabilities ($(cat $files | wc -l | tr -d ' ') occurrences across modules) in: ${files//$'\n'/, } (full report in the run artifacts)" | ||
| exit 1 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,39 @@ jobs: | |
| !github.event.pull_request.draft | ||
|
|
||
|
|
||
| trivy_code: | ||
| name: "Trivy Code Scan" | ||
| runs-on: ubuntu-latest | ||
| needs: [changes] | ||
| permissions: | ||
| contents: read | ||
| packages: read | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha }} | ||
| persist-credentials: false | ||
|
|
||
| - name: Trivy scan (dependencies + Dockerfile base images) | ||
| uses: ./.github/steps/trivy | ||
|
Comment on lines
+46
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 4 \
'head\.repo|persist-credentials|maven-token|GITHUB_TOKEN|dependency:go-offline' \
.github/workflows/test.yml .github/steps/trivy/action.ymlRepository: flamingo-stack/meshcentral Length of output: 2778 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow relevant lines =="
sed -n '1,110p' .github/workflows/test.yml | cat -n
echo
echo "== trivy action relevant lines =="
sed -n '1,80p' .github/steps/trivy/action.yml | cat -n
echo
echo "== workflow references to head repo / forks / persist-credentials =="
rg -n 'pull_request|fork|persist-credentials|maven-token|GITHUB_TOKEN|actions/checkout|trivy' .github/workflows/test.yml .github/steps/trivy/action.ymlRepository: flamingo-stack/meshcentral Length of output: 10873 Do not run Maven dependency resolution for fork pull requests. The 🧰 Tools🪛 zizmor (1.28.0)[warning] 50-53: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| with: | ||
| scan: code | ||
|
|
||
| trivy_report: | ||
| name: "Trivy Report" | ||
| runs-on: ubuntu-latest | ||
| needs: [trivy_code] | ||
| if: always() | ||
| steps: | ||
| - name: Merge all scan reports into one artifact | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact/merge@v4 | ||
| with: | ||
| name: trivy-${{ github.event.repository.name }}-report | ||
| pattern: trivy-*-report* | ||
| delete-merged: true | ||
|
|
||
| test: | ||
| name: "Test meshcentral" | ||
| needs: [changes] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Vulnerabilities to skip in the Trivy scan: one CVE/GHSA id per line, e.g.: | ||
| # | ||
| # CVE-2026-12345 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: flamingo-stack/meshcentral
Length of output: 164
🏁 Script executed:
Repository: flamingo-stack/meshcentral
Length of output: 2174
🌐 Web query:
aquasecurity setup-trivy advisory GHSA-69fq-xp46-6x23 March 2026 full commit SHA pin recommendation💡 Result:
In response to the supply chain compromise identified as GHSA-69fq-xp46-6x23 (CVE-2026-33634) in March 2026, where a threat actor force-pushed malicious code to all existing tags (v0.2.0–v0.2.6) of the aquasecurity/setup-trivy GitHub Action, users are strongly advised to pin to a verified, safe commit SHA [1][2][3]. The specific commit SHA identified as the safe version for setup-trivy v0.2.6 following the incident is 3fb12ec12f41e471780db15c232d5dd185dcb514 [4][5]. Security best practices for using GitHub Actions, particularly following this incident, include: 1. Pinning to full, immutable commit SHA hashes rather than relying on mutable version tags (e.g., v0.2.6) to prevent similar supply chain attacks where tags are overwritten [6][3]. 2. Treating any pipeline secrets used during the exposure window (March 19, 2026, 17:43 UTC to approximately March 19, 2026, 21:44 UTC for setup-trivy) as compromised and rotating them immediately [1][4][2]. For additional context, aquasecurity restored setup-trivy v0.2.6 with safe content after the incident, but because the attacker force-pushed to the tags, users who had previously cached or pulled the malicious version of v0.2.6 must ensure they update to the corrected SHA [1][2].
Citations:
Pin
aquasecurity/setup-trivyto a full commit SHA.The pin
aquasecurity/setup-trivy@v0.3.1uses a mutable third-party action tag. A changed tag can execute code with the Maven token. Use a reviewed 40-character commit SHA instead.🤖 Prompt for AI Agents