Skip to content

Security Scan

Security Scan #4

Workflow file for this run

name: Security Scan
on:
schedule:
# Run security scans daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
push:
branches: [ main ]
paths:
- '**/requirements.txt'
- '**/package.json'
- '**/package-lock.json'
- '**/Containerfile'
jobs:
dependency-scan:
name: Dependency Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Python dependencies
working-directory: ./backend
run: |
python -m pip install --upgrade pip
pip install safety bandit
- name: Run Python security scan with Safety
working-directory: ./backend
run: |
safety check --json --output safety-report.json || true
cat safety-report.json
- name: Run Python security scan with Bandit
working-directory: ./backend
run: |
bandit -r . -f json -o bandit-report.json || true
cat bandit-report.json
- name: Install Node.js dependencies
working-directory: ./frontend
run: npm ci
- name: Run npm audit
working-directory: ./frontend
run: |
npm audit --audit-level=moderate --json > npm-audit-report.json || true
cat npm-audit-report.json
- name: Upload security reports
uses: actions/upload-artifact@v3
with:
name: security-reports
path: |
backend/safety-report.json
backend/bandit-report.json
frontend/npm-audit-report.json
container-scan:
name: Container Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Podman
run: |
sudo apt-get update
sudo apt-get install -y podman
- name: Build backend image
working-directory: ./backend
run: |
podman build -t redhat-learning-paths-backend:scan -f Containerfile .
- name: Build frontend image
working-directory: ./frontend
run: |
podman build -t redhat-learning-paths-frontend:scan -f Containerfile .
- name: Run Trivy scan on backend image
uses: aquasecurity/trivy-action@master
with:
image-ref: 'redhat-learning-paths-backend:scan'
format: 'sarif'
output: 'backend-trivy-results.sarif'
- name: Run Trivy scan on frontend image
uses: aquasecurity/trivy-action@master
with:
image-ref: 'redhat-learning-paths-frontend:scan'
format: 'sarif'
output: 'frontend-trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'backend-trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'frontend-trivy-results.sarif'
codeql-analysis:
name: CodeQL Security Analysis
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python', 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: security-extended,security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"
secrets-scan:
name: Secrets Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
head: HEAD
extra_args: --debug --only-verified
sbom-generation:
name: Generate SBOM
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Podman
run: |
sudo apt-get update
sudo apt-get install -y podman
- name: Build images
run: |
cd backend && podman build -t redhat-learning-paths-backend:sbom -f Containerfile .
cd ../frontend && podman build -t redhat-learning-paths-frontend:sbom -f Containerfile .
- name: Generate SBOM for backend
uses: anchore/sbom-action@v0
with:
image: redhat-learning-paths-backend:sbom
format: spdx-json
output-file: backend-sbom.spdx.json
- name: Generate SBOM for frontend
uses: anchore/sbom-action@v0
with:
image: redhat-learning-paths-frontend:sbom
format: spdx-json
output-file: frontend-sbom.spdx.json
- name: Upload SBOM artifacts
uses: actions/upload-artifact@v3
with:
name: sbom-reports
path: |
backend-sbom.spdx.json
frontend-sbom.spdx.json
compliance-check:
name: Compliance Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check for required security files
run: |
echo "Checking for security-related files..."
# Check for security policy
if [ ! -f "SECURITY.md" ]; then
echo "❌ SECURITY.md file not found"
exit 1
else
echo "✅ SECURITY.md found"
fi
# Check for license
if [ ! -f "LICENSE" ] && [ ! -f "LICENSE.md" ] && [ ! -f "LICENSE.txt" ]; then
echo "❌ LICENSE file not found"
exit 1
else
echo "✅ LICENSE found"
fi
# Check for contributing guidelines
if [ ! -f "CONTRIBUTING.md" ]; then
echo "⚠️ CONTRIBUTING.md not found (recommended)"
else
echo "✅ CONTRIBUTING.md found"
fi
- name: Check container security best practices
run: |
echo "Checking Containerfile security practices..."
# Check for non-root user in Containerfiles
if ! grep -q "USER.*[^0]" backend/Containerfile; then
echo "❌ Backend Containerfile should run as non-root user"
exit 1
fi
if ! grep -q "USER.*[^0]" frontend/Containerfile; then
echo "❌ Frontend Containerfile should run as non-root user"
exit 1
fi
echo "✅ Containerfiles use non-root users"
security-summary:
name: Security Summary
runs-on: ubuntu-latest
needs: [dependency-scan, container-scan, codeql-analysis, secrets-scan, sbom-generation, compliance-check]
if: always()
steps:
- name: Generate security summary
run: |
echo "# Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.dependency-scan.result }}" == "success" ]; then
echo "| Dependency Scan | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| Dependency Scan | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.container-scan.result }}" == "success" ]; then
echo "| Container Scan | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| Container Scan | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.codeql-analysis.result }}" == "success" ]; then
echo "| CodeQL Analysis | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| CodeQL Analysis | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.secrets-scan.result }}" == "success" ]; then
echo "| Secrets Scan | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| Secrets Scan | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.sbom-generation.result }}" == "success" ]; then
echo "| SBOM Generation | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| SBOM Generation | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.compliance-check.result }}" == "success" ]; then
echo "| Compliance Check | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
else
echo "| Compliance Check | ❌ Failed |" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "For detailed results, check the individual job logs and security tab." >> $GITHUB_STEP_SUMMARY