Skip to content

Trivy Nightly Security Scan #321

Trivy Nightly Security Scan

Trivy Nightly Security Scan #321

Workflow file for this run

name: Trivy Nightly Security Scan
on:
workflow_call:
inputs:
commit_id:
required: false
type: string
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Runs daily at midnight UTC
jobs:
security-scan:
if: github.event.pull_request.draft == false
permissions:
contents: read
security-events: write
actions: read
packages: read
issues: write
runs-on: ubuntu-22.04
timeout-minutes: 45
env:
TRIVY_VERSION: 0.50.1
COMMIT_ID: ${{ inputs.commit_id || github.sha }}
steps:
# ============ SETUP PHASE ============
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ env.COMMIT_ID }}
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
# ============ SCANNING PHASE ============
- name: Run filesystem scan
uses: aquasecurity/trivy-action@0.30.0
with:
scan-type: 'fs'
format: 'json'
output: 'trivy-fs-report.json'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
vuln-type: 'os,library'
security-checks: 'vuln'
- name: Build Docker image
run: |
docker buildx build \
--pull \
--tag local/scan-target:${{ github.run_id }} \
--file openfl-docker/Dockerfile.base \
--load \
.
- name: Scan Docker image
uses: aquasecurity/trivy-action@0.30.0
with:
image-ref: 'local/scan-target:${{ github.run_id }}'
format: 'json'
output: 'trivy-image-report.json'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
vuln-type: 'os,library'
security-checks: 'vuln'
# ============ REPORTING PHASE ============
- name: Generate SBOM reports
run: |
trivy fs --format spdx-json --output trivy-fs-sbom.json .
trivy image --format spdx-json --output trivy-image-sbom.json local/scan-target:${{ github.run_id }}
- name: Create consolidated report
id: report
run: |
# Initialize markdown report
echo "# Security Scan Report - OpenFL" > report.md
echo "**Scan Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> report.md
echo "**Commit:** [${{ env.COMMIT_ID }}](https://github.com/rajithkrishnegowda/openfl/commit/${{ env.COMMIT_ID }})" >> report.md
echo -e "\n## Vulnerability Summary\n" >> report.md
# Process filesystem results
if [ -f "trivy-fs-report.json" ]; then
FS_VULNS=$(jq '[.Results[]?.Vulnerabilities[]?] | length' trivy-fs-report.json || echo 0)
echo "### Filesystem Scans" >> report.md
echo "**Critical/High Vulnerabilities:** $FS_VULNS" >> report.md
if [ "$FS_VULNS" -gt 0 ]; then
echo -e "\n| Severity | ID | Package | Version | Description |" >> report.md
echo "|----------|----|---------|---------|-------------|" >> report.md
jq -r '.Results[]?.Vulnerabilities[]? | "| \(.Severity) | \(.VulnerabilityID) | \(.PkgName) | \(.InstalledVersion) | \(.Title) |"' trivy-fs-report.json >> report.md
echo "has_vulnerabilities=true" >> $GITHUB_OUTPUT
fi
fi
# Process image results
if [ -f "trivy-image-report.json" ]; then
IMG_VULNS=$(jq '[.Results[]?.Vulnerabilities[]?] | length' trivy-image-report.json || echo 0)
echo -e "\n### Container Image Scans" >> report.md
echo "**Critical/High Vulnerabilities:** $IMG_VULNS" >> report.md
if [ "$IMG_VULNS" -gt 0 ]; then
echo -e "\n| Severity | ID | Package | Version | Description |" >> report.md
echo "|----------|----|---------|---------|-------------|" >> report.md
jq -r '.Results[]?.Vulnerabilities[]? | "| \(.Severity) | \(.VulnerabilityID) | \(.PkgName) | \(.InstalledVersion) | \(.Title) |"' trivy-image-report.json >> report.md
echo "has_vulnerabilities=true" >> $GITHUB_OUTPUT
fi
fi
# Add artifact download links
echo -e "\n## Next Steps\n" >> report.md
echo "1. Review the full reports in the workflow artifacts" >> report.md
echo "2. Address critical vulnerabilities immediately" >> report.md
echo "3. Create GitHub issues for tracking remediation" >> report.md
cat report.md
# ============ NOTIFICATION PHASE ============
- name: Set notification subject
id: set-subject
run: |
if [[ "${{ job.status }}" == "failure" ]]; then
echo "subject=🚨 OpenFL Security Scan Failed" >> $GITHUB_OUTPUT
elif [[ "${{ steps.report.outputs.has_vulnerabilities }}" == "true" ]]; then
echo "subject=⚠️ OpenFL Vulnerabilities Found" >> $GITHUB_OUTPUT
else
echo "subject=✅ OpenFL Security Scan Passed" >> $GITHUB_OUTPUT
fi
- name: Extract CODEOWNERS emails
id: codeowners
run: |
if ! command -v python &> /dev/null; then
sudo apt-get update && sudo apt-get install -y python3
fi
OUTPUT=$(python .github/scripts/extract_emails.py)
echo "Extracted emails: $OUTPUT"
EMAILS=$(echo "$OUTPUT" | jq -r '.emails | join(",")')
echo "emails=${EMAILS:-${{ secrets.SECURITY_EMAIL_RECIPIENTS }}}" >> $GITHUB_OUTPUT
env:
PYTHONIOENCODING: utf-8
- name: Prepare email content
id: prepare-email
run: |
# Convert markdown to HTML
python -m pip install markdown
HTML_CONTENT=$(python -c "import markdown; print(markdown.markdown(open('report.md').read()))")
echo "html_body<<EOF" >> $GITHUB_OUTPUT
echo "$HTML_CONTENT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Send email via Python script
if: always() && (steps.report.outputs.has_vulnerabilities == 'true' || failure())
env:
SMTP_SERVER: ${{ secrets.SMTP_SERVER }}
SMTP_PORT: ${{ secrets.SMTP_PORT }}
SMTP_USER: ${{ secrets.SMTP_USER }}
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
RECIPIENTS: ${{ steps.codeowners.outputs.emails }}
run: |
python .github/scripts/send_email.py \
--sender "security@openfl.github" \
--to "$RECIPIENTS" \
--subject "${{ steps.set-subject.outputs.subject }}" \
--body "${{ steps.prepare-email.outputs.html_body }}" \
--smtp-user "$SMTP_USER" \
--smtp-pwd "$SMTP_PASSWORD" \
--smtp-server "$SMTP_SERVER:$SMTP_PORT" \
--html-body
# ============ ARTIFACT UPLOADS ============
- name: Upload scan artifacts
uses: actions/upload-artifact@v4
with:
name: security-reports-${{ github.run_id }}
path: |
trivy-fs-report.json
trivy-image-report.json
trivy-fs-sbom.json
trivy-image-sbom.json
report.md
retention-days: 30
# ============ FAILURE HANDLING ============
- name: Fail workflow if vulnerabilities found
if: steps.report.outputs.has_vulnerabilities == 'true' && github.event_name != 'schedule'
run: |
echo "::error::Critical/High vulnerabilities detected!"
exit 1