Skip to content

[2317] Auth for http(s) proxy #1251

[2317] Auth for http(s) proxy

[2317] Auth for http(s) proxy #1251

Workflow file for this run

name: Go Security scan
on:
push:
branches:
- main
pull_request:
release:
types: [published]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
setup:
name: Shared Setup
runs-on: ubuntu-latest
outputs:
go-version: '1.22'
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Export Go Version
run: echo "go-version=1.22" >> $GITHUB_OUTPUT
gosec_scan:
name: Gosec Security Scan (Full)
needs: setup
runs-on: ubuntu-latest
outputs:
gosec_high_found: ${{ steps.scan.outputs.gosec_high_found }}
gosec_current_count: ${{ steps.gosec_compare.outputs.current_count }}
gosec_baseline_count: ${{ steps.gosec_compare.outputs.baseline_count }}
gosec_added_count: ${{ steps.gosec_compare.outputs.added_count }}
gosec_fixed_count: ${{ steps.gosec_compare.outputs.fixed_count }}
gosec_baseline_method: ${{ steps.gosec_compare.outputs.baseline_method }}
gosec_added_details: ${{ steps.gosec_compare.outputs.added_details }}
gosec_fixed_details: ${{ steps.gosec_compare.outputs.fixed_details }}
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '${{ needs.setup.outputs.go-version }}'
- name: Install gosec
run: |
go install github.com/securego/gosec/v2/cmd/gosec@latest
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Sanitize branch name
run: echo "SAFE_REF_NAME=${GITHUB_REF_NAME//\//-}" >> $GITHUB_ENV
- name: Run Gosec Scan
id: scan
run: |
echo "Running Gosec scan..."
mkdir -p tmp
gosec -fmt=json -severity=high -out=tmp/gosec-report.json ./... || true
cat tmp/gosec-report.json || echo '{"Issues":[]}'
count=$(jq '[.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL")] | length' tmp/gosec-report.json || echo 0)
if [[ "$count" -gt 0 ]]; then
echo "gosec_high_found=true" >> "$GITHUB_OUTPUT"
else
echo "gosec_high_found=false" >> "$GITHUB_OUTPUT"
fi
- name: Upload Gosec Report
uses: actions/upload-artifact@v4
with:
name: gosec-json-${{ env.SAFE_REF_NAME }}
path: tmp/gosec-report.json
- name: Generate PR Body (if vulnerabilities found)
if: ${{ steps.scan.outputs.gosec_high_found == 'true' }}
run: |
echo "# 🚨 Gosec Vulnerability Report for branch \`${GITHUB_REF_NAME}\`" > tmp/pr-body.md
jq -r '
.Issues[]
| select(.severity == "HIGH" or .severity == "CRITICAL")
| "* File: \(.file)\n • Line: \(.line)\n • Rule ID: \(.rule_id)\n • Details: \(.details)\n • Confidence: \(.confidence)\n • Severity: \(.severity)\n"
' tmp/gosec-report.json >> tmp/pr-body.md
- name: Debug - List Available Artifacts
if: github.event_name == 'pull_request'
continue-on-error: true
run: |
echo "Looking for artifacts from base SHA: ${{ github.event.pull_request.base.sha }}"
echo "Expected Gosec artifact: gosec-security-report-${{ github.event.pull_request.base.sha }}"
echo "Base branch: ${{ github.event.pull_request.base.ref }}"
- name: Download Baseline Gosec Report (PR only)
if: github.event_name == 'pull_request'
continue-on-error: true
uses: dawidd6/action-download-artifact@v3
with:
name: gosec-security-report-${{ github.event.pull_request.base.sha }}
path: ./baseline-reports
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: security.yml
branch: ${{ github.event.pull_request.base.ref }}
workflow_conclusion: ""
check_artifacts: true
if_no_artifact_found: warn
repo: ${{ github.repository }}
search_artifacts: true
- name: Compare Vulnerabilities with Baseline (PR only)
if: github.event_name == 'pull_request'
id: gosec_compare
run: |
echo "Comparing Gosec vulnerabilities with baseline..."
# Initialize counts
current_count=0
baseline_count=0
added_count=0
fixed_count=0
baseline_method="none"
# Count current vulnerabilities
if [[ -f "tmp/gosec-report.json" ]]; then
current_count=$(jq '[.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL")] | length' tmp/gosec-report.json || echo 0)
fi
# Try to use artifact baseline first
if [[ -f "baseline-reports/gosec-report.json" ]]; then
echo "✅ Using artifact baseline from main branch"
baseline_method="artifact"
baseline_count=$(jq '[.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL")] | length' baseline-reports/gosec-report.json || echo 0)
# Create unique vulnerability identifiers for comparison
jq -r '.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL") | "\(.file):\(.line):\(.rule_id)"' tmp/gosec-report.json | sort > tmp/current-vulns.txt
jq -r '.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL") | "\(.file):\(.line):\(.rule_id)"' baseline-reports/gosec-report.json | sort > tmp/baseline-vulns.txt
# Calculate added and fixed vulnerabilities
added_count=$(comm -23 tmp/current-vulns.txt tmp/baseline-vulns.txt | wc -l)
fixed_count=$(comm -13 tmp/current-vulns.txt tmp/baseline-vulns.txt | wc -l)
else
echo "⚠️ No baseline artifact found, scanning base branch live..."
baseline_method="live_scan"
# Save current state
cp tmp/gosec-report.json tmp/gosec-report-pr.json
# Checkout and scan base branch
git fetch origin ${{ github.event.pull_request.base.ref }}
git checkout ${{ github.event.pull_request.base.sha }}
# Run baseline Gosec scan
gosec -fmt=json -severity=medium -out=tmp/gosec-report-baseline.json ./... || true
cat tmp/gosec-report-baseline.json || echo '{"Issues":[]}'
baseline_count=$(jq '[.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL")] | length' tmp/gosec-report-baseline.json || echo 0)
# Create comparison files
jq -r '.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL") | "\(.file):\(.line):\(.rule_id)"' tmp/gosec-report-pr.json | sort > tmp/current-vulns.txt
jq -r '.Issues[] | select(.severity == "HIGH" or .severity == "CRITICAL") | "\(.file):\(.line):\(.rule_id)"' tmp/gosec-report-baseline.json | sort > tmp/baseline-vulns.txt
# Calculate differences
added_count=$(comm -23 tmp/current-vulns.txt tmp/baseline-vulns.txt | wc -l)
fixed_count=$(comm -13 tmp/current-vulns.txt tmp/baseline-vulns.txt | wc -l)
# Restore PR state
git checkout ${{ github.sha }}
cp tmp/gosec-report-pr.json tmp/gosec-report.json
fi
echo "Baseline method: $baseline_method"
echo "Current HIGH/CRITICAL vulnerabilities: $current_count"
echo "Baseline HIGH/CRITICAL vulnerabilities: $baseline_count"
echo "Added vulnerabilities: $added_count"
echo "Fixed vulnerabilities: $fixed_count"
# Generate detailed vulnerability lists
added_details=""
fixed_details=""
if [[ -f "tmp/current-vulns.txt" && -f "tmp/baseline-vulns.txt" ]]; then
# Get added vulnerabilities with details
if [[ $added_count -gt 0 ]]; then
added_vulns=$(comm -23 tmp/current-vulns.txt tmp/baseline-vulns.txt)
added_details=""
while IFS= read -r vuln_id; do
if [[ -n "$vuln_id" ]]; then
file_path=$(echo "$vuln_id" | cut -d':' -f1)
line_num=$(echo "$vuln_id" | cut -d':' -f2)
rule_id=$(echo "$vuln_id" | cut -d':' -f3)
details=$(jq -r --arg file "$file_path" --arg line "$line_num" --arg rule "$rule_id" '
.Issues[] | select(.file == $file and (.line | tostring) == $line and .rule_id == $rule and (.severity == "HIGH" or .severity == "CRITICAL")) |
"**File:** `\(.file)` (Line \(.line))\\n**Rule:** \(.rule_id)\\n**Severity:** \(.severity)\\n**Details:** \(.details)\\n"
' tmp/gosec-report.json)
if [[ -n "$details" ]]; then
added_details="${added_details}${details}\\n"
fi
fi
done <<< "$added_vulns"
fi
# Get fixed vulnerabilities with details
if [[ $fixed_count -gt 0 ]]; then
fixed_vulns=$(comm -13 tmp/current-vulns.txt tmp/baseline-vulns.txt)
fixed_details=""
while IFS= read -r vuln_id; do
if [[ -n "$vuln_id" ]]; then
file_path=$(echo "$vuln_id" | cut -d':' -f1)
line_num=$(echo "$vuln_id" | cut -d':' -f2)
rule_id=$(echo "$vuln_id" | cut -d':' -f3)
baseline_report="baseline-reports/gosec-report.json"
if [[ "$baseline_method" == "live_scan" ]]; then
baseline_report="tmp/gosec-report-baseline.json"
fi
details=$(jq -r --arg file "$file_path" --arg line "$line_num" --arg rule "$rule_id" '
.Issues[] | select(.file == $file and (.line | tostring) == $line and .rule_id == $rule and (.severity == "HIGH" or .severity == "CRITICAL")) |
"**File:** `\(.file)` (Line \(.line))\\n**Rule:** \(.rule_id)\\n**Severity:** \(.severity)\\n**Details:** \(.details)\\n"
' "$baseline_report")
if [[ -n "$details" ]]; then
fixed_details="${fixed_details}${details}\\n"
fi
fi
done <<< "$fixed_vulns"
fi
fi
# Set outputs
echo "current_count=$current_count" >> "$GITHUB_OUTPUT"
echo "baseline_count=$baseline_count" >> "$GITHUB_OUTPUT"
echo "added_count=$added_count" >> "$GITHUB_OUTPUT"
echo "fixed_count=$fixed_count" >> "$GITHUB_OUTPUT"
echo "baseline_method=$baseline_method" >> "$GITHUB_OUTPUT"
{
echo "added_details<<EOF"
echo -e "$added_details"
echo "EOF"
} >> "$GITHUB_OUTPUT"
{
echo "fixed_details<<EOF"
echo -e "$fixed_details"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Display Gosec Vulnerability Report
if: ${{ steps.scan.outputs.gosec_high_found == 'true' }}
run: |
echo "=========================================="
echo "Gosec HIGH/CRITICAL Vulnerability Report"
echo "=========================================="
printf "%-60s %-6s %-8s %-10s %s\n" "FILE" "LINE" "RULE" "SEVERITY" "DETAILS"
printf "%-60s %-6s %-8s %-10s %s\n" "----" "----" "----" "--------" "-------"
jq -r '
.Issues[]
| select(.severity == "HIGH" or .severity == "CRITICAL")
| [.file, .line, .rule_id, .severity, .details]
| @tsv
' tmp/gosec-report.json | while IFS=$'\t' read -r file line rule sev details; do
printf "%-60s %-6s %-8s %-10s %s\n" "$file" "$line" "$rule" "$sev" "$details"
done
echo "=========================================="
- name: Store Gosec Report as Artifact (Main/Release)
if: ${{ (github.ref == 'refs/heads/main' && github.event_name == 'push') || github.event_name == 'release' }}
uses: actions/upload-artifact@v4
with:
name: gosec-security-report-${{ github.sha }}
path: tmp/gosec-report.json
retention-days: 90
- name: Save Gosec PR Summary for Comment Workflow
if: github.event_name == 'pull_request'
env:
GOSEC_ADDED_DETAILS: ${{ steps.gosec_compare.outputs.added_details }}
GOSEC_FIXED_DETAILS: ${{ steps.gosec_compare.outputs.fixed_details }}
run: |
mkdir -p tmp/gosec-summary
echo "${{ github.event.pull_request.number }}" > tmp/gosec-summary/pr-number.txt
echo "${{ github.event.pull_request.base.sha }}" > tmp/gosec-summary/base-sha.txt
echo "${{ steps.gosec_compare.outputs.current_count }}" > tmp/gosec-summary/current.txt
echo "${{ steps.gosec_compare.outputs.baseline_count }}" > tmp/gosec-summary/baseline.txt
echo "${{ steps.gosec_compare.outputs.added_count }}" > tmp/gosec-summary/added.txt
echo "${{ steps.gosec_compare.outputs.fixed_count }}" > tmp/gosec-summary/fixed.txt
echo "${{ steps.gosec_compare.outputs.baseline_method }}" > tmp/gosec-summary/method.txt
printf '%s' "$GOSEC_ADDED_DETAILS" > tmp/gosec-summary/added-details.txt
printf '%s' "$GOSEC_FIXED_DETAILS" > tmp/gosec-summary/fixed-details.txt
- name: Upload Gosec PR Summary Artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: security-gosec-summary
path: tmp/gosec-summary/
# - name: Create Pull Request (if vulnerabilities found)
# if: ${{ github.event_name == 'push' && steps.scan.outputs.gosec_high_found == 'true' }}
# continue-on-error: true
# uses: peter-evans/create-pull-request@v5
# with:
# commit-message: 'chore: vulnerabilities detected by Gosec (HIGH/CRITICAL)'
# title: 'Gosec Vulnerability Report for branch ${{ github.ref_name }}'
# body-path: tmp/pr-body.md
# branch: auto/gosec-scan/${{ env.SAFE_REF_NAME }}
# base: ${{ github.ref_name }}
# delete-branch: true
# add-paths: tmp/pr-body.md
# Temporarily disabled: fail on vulnerabilities — fixing existing findings before re-enabling
# - name: Fail Job If Vulnerabilities Found (Push)
# if: ${{ github.event_name != 'pull_request' && steps.scan.outputs.gosec_high_found == 'true' }}
# run: exit 1
#
# - name: Fail Job If New Vulnerabilities Introduced (PR)
# if: ${{ github.event_name == 'pull_request' && steps.gosec_compare.outputs.added_count > 0 }}
# run: |
# echo "New HIGH/CRITICAL vulnerabilities introduced: ${{ steps.gosec_compare.outputs.added_count }}"
# exit 1
trivy_scan:
name: Trivy Security Scan (Full)
needs: setup
runs-on: ubuntu-latest
outputs:
trivy_high_found: ${{ steps.scan.outputs.trivy_high_found }}
trivy_current_count: ${{ steps.trivy_compare.outputs.current_count }}
trivy_baseline_count: ${{ steps.trivy_compare.outputs.baseline_count }}
trivy_added_count: ${{ steps.trivy_compare.outputs.added_count }}
trivy_fixed_count: ${{ steps.trivy_compare.outputs.fixed_count }}
trivy_baseline_method: ${{ steps.trivy_compare.outputs.baseline_method }}
trivy_added_details: ${{ steps.trivy_compare.outputs.added_details }}
trivy_fixed_details: ${{ steps.trivy_compare.outputs.fixed_details }}
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Install Trivy
run: |
TRIVY_VERSION=$(curl -s https://api.github.com/repos/aquasecurity/trivy/releases/latest | jq -r .tag_name | sed 's/v//')
wget https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.deb
sudo dpkg -i trivy_${TRIVY_VERSION}_Linux-64bit.deb
sudo apt install -f -y
sudo apt install -y jq
- name: Sanitize branch name
run: echo "SAFE_REF_NAME=${GITHUB_REF_NAME//\//-}" >> $GITHUB_ENV
- name: Run Trivy Filesystem Scan
id: scan
run: |
echo "Running Trivy scan (HIGH/CRITICAL)..."
mkdir -p tmp
trivy fs --format json --severity HIGH,CRITICAL --output tmp/trivy-report.json .
[[ -f tmp/trivy-report.json ]] || echo '{"Results":[]}' > tmp/trivy-report.json
count=$(jq -e '
(.Results // [])
| map(.Vulnerabilities? // [])
| add
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| length
' tmp/trivy-report.json || echo 0)
if [[ "$count" -gt 0 ]]; then
echo "trivy_high_found=true" >> "$GITHUB_OUTPUT"
else
echo "trivy_high_found=false" >> "$GITHUB_OUTPUT"
fi
- name: Upload Trivy Report
uses: actions/upload-artifact@v4
with:
name: trivy-json-${{ env.SAFE_REF_NAME }}
path: tmp/trivy-report.json
- name: Generate PR Body (if vulnerabilities found)
if: ${{ steps.scan.outputs.trivy_high_found == 'true' }}
run: |
echo "# 🛡️ Trivy Scan Report for branch \`${GITHUB_REF_NAME}\`" > tmp/pr-body.md
jq -r '
(.Results // [])
| .[]
| .Target as $file
| (.Vulnerabilities? // [])
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| .[]
| "* File: \($file)\n • Vulnerability ID: \(.VulnerabilityID)\n • Pkg: \(.PkgName) \(.InstalledVersion)\n • Severity: \(.Severity)\n • Title: \(.Title)\n"
' tmp/trivy-report.json >> tmp/pr-body.md
- name: Debug - List Available Trivy Artifacts
if: github.event_name == 'pull_request'
continue-on-error: true
run: |
echo "Looking for Trivy artifacts from base SHA: ${{ github.event.pull_request.base.sha }}"
echo "Expected Trivy artifact: trivy-filesystem-report-${{ github.event.pull_request.base.sha }}"
echo "Base branch: ${{ github.event.pull_request.base.ref }}"
- name: Download Baseline Trivy Report (PR only)
if: github.event_name == 'pull_request'
continue-on-error: true
uses: dawidd6/action-download-artifact@v3
with:
name: trivy-filesystem-report-${{ github.event.pull_request.base.sha }}
path: ./baseline-reports
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: security.yml
branch: ${{ github.event.pull_request.base.ref }}
workflow_conclusion: ""
check_artifacts: true
if_no_artifact_found: warn
repo: ${{ github.repository }}
search_artifacts: true
- name: Compare Trivy Vulnerabilities with Baseline (PR only)
if: github.event_name == 'pull_request'
id: trivy_compare
run: |
echo "Comparing Trivy vulnerabilities with baseline..."
# Initialize counts
current_count=0
baseline_count=0
added_count=0
fixed_count=0
baseline_method="none"
# Count current vulnerabilities
if [[ -f "tmp/trivy-report.json" ]]; then
current_count=$(jq -e '
(.Results // [])
| map(.Vulnerabilities? // [])
| add
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| length
' tmp/trivy-report.json || echo 0)
fi
# Try to use artifact baseline first
if [[ -f "baseline-reports/trivy-report.json" ]]; then
echo "✅ Using artifact baseline from main branch"
baseline_method="artifact"
baseline_count=$(jq -e '
(.Results // [])
| map(.Vulnerabilities? // [])
| add
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| length
' baseline-reports/trivy-report.json || echo 0)
# Create unique vulnerability identifiers for comparison
jq -r '
(.Results // [])
| .[]
| .Target as $file
| (.Vulnerabilities? // [])
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| .[]
| "\($file):\(.VulnerabilityID):\(.PkgName)"
' tmp/trivy-report.json | sort > tmp/current-trivy-vulns.txt
jq -r '
(.Results // [])
| .[]
| .Target as $file
| (.Vulnerabilities? // [])
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| .[]
| "\($file):\(.VulnerabilityID):\(.PkgName)"
' baseline-reports/trivy-report.json | sort > tmp/baseline-trivy-vulns.txt
# Calculate added and fixed vulnerabilities
added_count=$(comm -23 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt | wc -l)
fixed_count=$(comm -13 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt | wc -l)
else
echo "⚠️ No baseline artifact found, scanning base branch live..."
baseline_method="live_scan"
# Save current state
cp tmp/trivy-report.json tmp/trivy-report-pr.json
# Checkout and scan base branch
git fetch origin ${{ github.event.pull_request.base.ref }}
git checkout ${{ github.event.pull_request.base.sha }}
# Run baseline scan
trivy fs --format json --severity HIGH,CRITICAL --output tmp/trivy-report-baseline.json .
[[ -f tmp/trivy-report-baseline.json ]] || echo '{"Results":[]}' > tmp/trivy-report-baseline.json
baseline_count=$(jq -e '
(.Results // [])
| map(.Vulnerabilities? // [])
| add
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| length
' tmp/trivy-report-baseline.json || echo 0)
# Create comparison files
jq -r '
(.Results // [])
| .[]
| .Target as $file
| (.Vulnerabilities? // [])
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| .[]
| "\($file):\(.VulnerabilityID):\(.PkgName)"
' tmp/trivy-report-pr.json | sort > tmp/current-trivy-vulns.txt
jq -r '
(.Results // [])
| .[]
| .Target as $file
| (.Vulnerabilities? // [])
| map(select(.Severity=="HIGH" or .Severity=="CRITICAL"))
| .[]
| "\($file):\(.VulnerabilityID):\(.PkgName)"
' tmp/trivy-report-baseline.json | sort > tmp/baseline-trivy-vulns.txt
# Calculate differences
added_count=$(comm -23 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt | wc -l)
fixed_count=$(comm -13 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt | wc -l)
# Restore PR state
git checkout ${{ github.sha }}
cp tmp/trivy-report-pr.json tmp/trivy-report.json
fi
echo "Baseline method: $baseline_method"
echo "Current Trivy HIGH/CRITICAL vulnerabilities: $current_count"
echo "Baseline Trivy HIGH/CRITICAL vulnerabilities: $baseline_count"
echo "Added Trivy vulnerabilities: $added_count"
echo "Fixed Trivy vulnerabilities: $fixed_count"
# Generate detailed vulnerability lists
added_details=""
fixed_details=""
if [[ -f "tmp/current-trivy-vulns.txt" && -f "tmp/baseline-trivy-vulns.txt" ]]; then
# Get added vulnerabilities with details
if [[ $added_count -gt 0 ]]; then
added_vulns=$(comm -23 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt)
added_details=""
while IFS= read -r vuln_id; do
if [[ -n "$vuln_id" ]]; then
target=$(echo "$vuln_id" | cut -d':' -f1)
vuln_cve=$(echo "$vuln_id" | cut -d':' -f2)
pkg_name=$(echo "$vuln_id" | cut -d':' -f3)
details=$(jq -r --arg target "$target" --arg vuln "$vuln_cve" --arg pkg "$pkg_name" '
(.Results // []) | .[] | select(.Target == $target) |
(.Vulnerabilities? // []) | .[] |
select(.VulnerabilityID == $vuln and .PkgName == $pkg and (.Severity == "HIGH" or .Severity == "CRITICAL")) |
"**Target:** `\(.Target // $target)`\\n**Package:** \(.PkgName) \(.InstalledVersion)\\n**Vulnerability:** \(.VulnerabilityID)\\n**Severity:** \(.Severity)\\n**Title:** \(.Title)\\n"
' tmp/trivy-report.json)
if [[ -n "$details" ]]; then
added_details="${added_details}${details}\\n"
fi
fi
done <<< "$added_vulns"
fi
# Get fixed vulnerabilities with details
if [[ $fixed_count -gt 0 ]]; then
fixed_vulns=$(comm -13 tmp/current-trivy-vulns.txt tmp/baseline-trivy-vulns.txt)
fixed_details=""
while IFS= read -r vuln_id; do
if [[ -n "$vuln_id" ]]; then
target=$(echo "$vuln_id" | cut -d':' -f1)
vuln_cve=$(echo "$vuln_id" | cut -d':' -f2)
pkg_name=$(echo "$vuln_id" | cut -d':' -f3)
baseline_report="baseline-reports/trivy-report.json"
if [[ "$baseline_method" == "live_scan" ]]; then
baseline_report="tmp/trivy-report-baseline.json"
fi
details=$(jq -r --arg target "$target" --arg vuln "$vuln_cve" --arg pkg "$pkg_name" '
(.Results // []) | .[] | select(.Target == $target) |
(.Vulnerabilities? // []) | .[] |
select(.VulnerabilityID == $vuln and .PkgName == $pkg and (.Severity == "HIGH" or .Severity == "CRITICAL")) |
"**Target:** `\(.Target // $target)`\\n**Package:** \(.PkgName) \(.InstalledVersion)\\n**Vulnerability:** \(.VulnerabilityID)\\n**Severity:** \(.Severity)\\n**Title:** \(.Title)\\n"
' "$baseline_report")
if [[ -n "$details" ]]; then
fixed_details="${fixed_details}${details}\\n"
fi
fi
done <<< "$fixed_vulns"
fi
fi
# Set outputs
echo "current_count=$current_count" >> "$GITHUB_OUTPUT"
echo "baseline_count=$baseline_count" >> "$GITHUB_OUTPUT"
echo "added_count=$added_count" >> "$GITHUB_OUTPUT"
echo "fixed_count=$fixed_count" >> "$GITHUB_OUTPUT"
echo "baseline_method=$baseline_method" >> "$GITHUB_OUTPUT"
{
echo "added_details<<EOF"
echo -e "$added_details"
echo "EOF"
} >> "$GITHUB_OUTPUT"
{
echo "fixed_details<<EOF"
echo -e "$fixed_details"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Display Trivy Vulnerability Report
if: ${{ steps.scan.outputs.trivy_high_found == 'true' }}
run: |
echo "=========================================="
echo "Trivy HIGH/CRITICAL Vulnerability Report"
echo "=========================================="
printf "%-50s %-20s %-25s %-10s %s\n" "TARGET" "VULNERABILITY" "PACKAGE" "SEVERITY" "TITLE"
printf "%-50s %-20s %-25s %-10s %s\n" "------" "-------------" "-------" "--------" "-----"
jq -r '
(.Results // [])
| .[]
| .Target as $target
| (.Vulnerabilities? // [])
| map(select(.Severity == "HIGH" or .Severity == "CRITICAL"))
| .[]
| [$target, .VulnerabilityID, (.PkgName + " " + .InstalledVersion), .Severity, .Title]
| @tsv
' tmp/trivy-report.json | while IFS=$'\t' read -r target vuln pkg sev title; do
printf "%-50s %-20s %-25s %-10s %s\n" "$target" "$vuln" "$pkg" "$sev" "$title"
done
echo "=========================================="
- name: Store Trivy Filesystem Report as Artifact (Main/Release)
if: ${{ (github.ref == 'refs/heads/main' && github.event_name == 'push') || github.event_name == 'release' }}
uses: actions/upload-artifact@v4
with:
name: trivy-filesystem-report-${{ github.sha }}
path: tmp/trivy-report.json
retention-days: 90
- name: Save Trivy PR Summary for Comment Workflow
if: github.event_name == 'pull_request'
env:
TRIVY_ADDED_DETAILS: ${{ steps.trivy_compare.outputs.added_details }}
TRIVY_FIXED_DETAILS: ${{ steps.trivy_compare.outputs.fixed_details }}
run: |
mkdir -p tmp/trivy-summary
echo "${{ github.event.pull_request.number }}" > tmp/trivy-summary/pr-number.txt
echo "${{ github.event.pull_request.base.sha }}" > tmp/trivy-summary/base-sha.txt
echo "${{ steps.trivy_compare.outputs.current_count }}" > tmp/trivy-summary/current.txt
echo "${{ steps.trivy_compare.outputs.baseline_count }}" > tmp/trivy-summary/baseline.txt
echo "${{ steps.trivy_compare.outputs.added_count }}" > tmp/trivy-summary/added.txt
echo "${{ steps.trivy_compare.outputs.fixed_count }}" > tmp/trivy-summary/fixed.txt
echo "${{ steps.trivy_compare.outputs.baseline_method }}" > tmp/trivy-summary/method.txt
printf '%s' "$TRIVY_ADDED_DETAILS" > tmp/trivy-summary/added-details.txt
printf '%s' "$TRIVY_FIXED_DETAILS" > tmp/trivy-summary/fixed-details.txt
- name: Upload Trivy PR Summary Artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: security-trivy-summary
path: tmp/trivy-summary/
# - name: Create Pull Request (if vulnerabilities found)
# if: ${{ github.event_name == 'push' && steps.scan.outputs.trivy_high_found == 'true' }}
# continue-on-error: true
# uses: peter-evans/create-pull-request@v5
# with:
# commit-message: 'chore: vulnerabilities detected by Trivy (HIGH/CRITICAL)'
# title: 'Trivy Vulnerability Report for branch ${{ github.ref_name }}'
# body-path: tmp/pr-body.md
# branch: auto/trivy-scan/${{ env.SAFE_REF_NAME }}
# base: ${{ github.ref_name }}
# delete-branch: true
# add-paths: tmp/pr-body.md
# Temporarily disabled: fail on vulnerabilities — fixing existing findings before re-enabling
# - name: Fail Job If Vulnerabilities Found (Push)
# if: ${{ github.event_name != 'pull_request' && steps.scan.outputs.trivy_high_found == 'true' }}
# run: exit 1
#
# - name: Fail Job If New Vulnerabilities Introduced (PR)
# if: ${{ github.event_name == 'pull_request' && steps.trivy_compare.outputs.added_count > 0 }}
# run: |
# echo "New HIGH/CRITICAL vulnerabilities introduced: ${{ steps.trivy_compare.outputs.added_count }}"
# exit 1
# vulnerability_summary job moved to security-comment.yml workflow
# which uses workflow_run trigger to post PR comments with full write permissions,
# including for fork PRs where pull_request trigger tokens are read-only.