Skip to content

Security Scan

Security Scan #103

Workflow file for this run

name: Security Scan
on:
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch: # Allow manual triggering
jobs:
vulnerability-scan:
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
# Use pip-audit for dependency scanning (no authentication required)
pip install pip-audit bandit[toml]
echo "πŸ“¦ Installed dependencies:"
pip list | grep -E "(pip-audit|bandit)"
echo "πŸ”§ pip-audit version:"
pip-audit --version
- name: Run pip-audit dependency vulnerability scan
run: |
echo "πŸ” Running pip-audit dependency vulnerability scan..."
# Use pip-audit for dependency vulnerability scanning
pip-audit --format=json --output=safety-report.json --requirement=requirements.txt || true
if [ -f safety-report.json ] && [ -s safety-report.json ]; then
echo "βœ… pip-audit JSON report generated"
echo "πŸ“Š Report size: $(wc -c < safety-report.json) bytes"
else
echo "❌ pip-audit JSON report not generated or empty"
# Create a basic report structure if scan fails
echo '{"vulnerabilities": [], "scan_target": "requirements.txt", "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' > safety-report.json
fi
echo "Running pip-audit summary report..."
pip-audit --requirement=requirements.txt || echo "pip-audit summary failed"
- name: Run Bandit code security scan
run: |
echo "πŸ” Running Bandit code security scan..."
bandit -r gefcore/ -f json -o bandit-report.json || true
if [ -f bandit-report.json ]; then
echo "βœ… Bandit JSON report generated"
else
echo "❌ Bandit JSON report not generated"
fi
echo "Running Bandit severity check..."
bandit -r gefcore/ --severity-level medium || true
- name: Run Trivy filesystem scan
uses: aquasecurity/trivy-action@0.24.0
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH,MEDIUM'
exit-code: '0' # Don't fail the workflow on vulnerabilities
- name: Check if Trivy SARIF file exists and is valid
run: |
if [ -f trivy-results.sarif ]; then
echo "βœ… Trivy SARIF file exists"
# Check if file is not empty and has valid JSON structure
if [ -s trivy-results.sarif ]; then
echo "βœ… Trivy SARIF file is not empty"
# Basic JSON validation
if python -m json.tool trivy-results.sarif >/dev/null 2>&1; then
echo "βœ… Trivy SARIF file has valid JSON structure"
else
echo "❌ Trivy SARIF file has invalid JSON structure"
cat trivy-results.sarif
fi
else
echo "❌ Trivy SARIF file is empty"
fi
else
echo "❌ Trivy SARIF file does not exist"
# Create an empty valid SARIF file as fallback
echo '{
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
"runs": []
}' > trivy-results.sarif
echo "Created empty SARIF file as fallback"
fi
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always() && hashFiles('trivy-results.sarif') != ''
with:
sarif_file: trivy-results.sarif
category: 'trivy-fs-scan'
continue-on-error: true
- name: Check SARIF upload status
if: always()
run: |
if [ -f trivy-results.sarif ]; then
echo "πŸ“Š SARIF file size: $(wc -c < trivy-results.sarif) bytes"
echo "πŸ“Š SARIF file lines: $(wc -l < trivy-results.sarif) lines"
# Show first few lines to check structure
echo "πŸ“Š SARIF file structure (first 10 lines):"
head -n 10 trivy-results.sarif
else
echo "❌ SARIF file not found for upload verification"
fi
- name: Upload security scan artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: security-scan-reports
path: |
safety-report.json
bandit-report.json
trivy-results.sarif
retention-days: 30
- name: Create security summary
if: always()
run: |
echo "## πŸ” Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "*Scan completed on $(date -u)*" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### πŸ›‘οΈ pip-audit (Dependency Vulnerabilities)" >> $GITHUB_STEP_SUMMARY
if [ -f safety-report.json ]; then
echo "βœ… pip-audit scan completed successfully" >> $GITHUB_STEP_SUMMARY
# Extract vulnerability count if possible
if command -v jq >/dev/null 2>&1; then
VULN_COUNT=$(jq -r '.vulnerabilities | length // "unknown"' safety-report.json 2>/dev/null || echo "unknown")
echo "πŸ“Š Vulnerabilities found: $VULN_COUNT" >> $GITHUB_STEP_SUMMARY
fi
else
echo "❌ pip-audit scan failed - check logs for details" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### πŸ” Bandit (Code Security)" >> $GITHUB_STEP_SUMMARY
if [ -f bandit-report.json ]; then
echo "βœ… Bandit scan completed successfully" >> $GITHUB_STEP_SUMMARY
# Extract issue count if possible
if command -v jq >/dev/null 2>&1; then
ISSUE_COUNT=$(jq -r '.results | length' bandit-report.json 2>/dev/null || echo "unknown")
echo "πŸ“Š Security issues found: $ISSUE_COUNT" >> $GITHUB_STEP_SUMMARY
fi
else
echo "❌ Bandit scan failed - check logs for details" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### πŸ—‚οΈ Trivy (Container/Filesystem Security)" >> $GITHUB_STEP_SUMMARY
if [ -f trivy-results.sarif ]; then
FILE_SIZE=$(wc -c < trivy-results.sarif)
echo "βœ… Trivy scan completed successfully" >> $GITHUB_STEP_SUMMARY
echo "πŸ“Š SARIF file size: ${FILE_SIZE} bytes" >> $GITHUB_STEP_SUMMARY
if [ "$FILE_SIZE" -gt 100 ]; then
echo "πŸ“€ Results uploaded to Security tab" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ SARIF file seems too small - may be empty" >> $GITHUB_STEP_SUMMARY
fi
else
echo "❌ Trivy scan failed - SARIF file not generated" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "πŸ“ All scan reports are available as workflow artifacts." >> $GITHUB_STEP_SUMMARY