Skip to content

Security Scan

Security Scan #153

Workflow file for this run

# Comprehensive Security Scanning Suite
#
# Purpose: Unified security scanning combining CodeQL, dependency scanning,
# and secret detection.
#
# Triggers:
# - Push to main/develop/staging branches
# - PRs to main/develop/staging branches
# - Daily scheduled scan at 2 AM UTC
#
# Scan Types:
# 1. Code security analysis (CodeQL)
# 2. Dependency vulnerabilities (Trivy)
# 3. Secret detection (TruffleHog)
# 4. Container security (when applicable)
#
# Results:
# - Uploaded to GitHub Security tab
# - Available in SARIF format
# - Fails build on critical issues
name: Security Scan
on:
push:
branches: [main, develop, staging]
paths-ignore:
- '**/*.md'
- 'docs/**'
- '.github/*.md'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- 'LICENSE'
- 'CHANGELOG.md'
- 'README.md'
- '**/*.txt'
pull_request:
branches: [main, develop, staging]
paths-ignore:
- '**/*.md'
- 'docs/**'
- '.github/*.md'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- 'LICENSE'
- 'CHANGELOG.md'
- 'README.md'
- '**/*.txt'
schedule:
# Daily scan ensures we catch newly disclosed vulnerabilities
- cron: '0 2 * * *'
# Cancel in-progress security scans when new commits are pushed
concurrency:
group: security-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read # Read repository content
security-events: write # Upload security findings
jobs:
codeql-analysis:
name: CodeQL Security Analysis
runs-on: ubuntu-latest
permissions:
security-events: write
packages: read
actions: read
contents: read
strategy:
fail-fast: false
matrix:
language: [ 'javascript-typescript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
dependency-scan:
name: Dependency Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Scan for known vulnerabilities in dependencies
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.24.0
with:
scan-type: 'fs' # Filesystem scan
scan-ref: '.' # Scan entire repository
format: 'sarif' # GitHub-compatible format
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH,MEDIUM' # Report these severity levels
ignore-unfixed: true # Skip vulnerabilities without fixes
# Make results visible in GitHub Security tab
- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
secret-scan:
name: Secret Scanning
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history needed for accurate secret detection
# Scan for exposed secrets and credentials
- name: TruffleHog Secret Scan
uses: trufflesecurity/trufflehog@v3.63.7
with:
path: ./ # Scan entire repository
base: ${{ github.event.repository.default_branch }} # Compare against default branch
head: HEAD # Current commit
extra_args: --only-verified # Only report verified secrets
docker-scan:
name: Container Security Scan
runs-on: ubuntu-latest
# Only run when Docker-related changes are made
if: contains(github.event.head_commit.message, 'docker') || contains(github.event.pull_request.title, 'docker')
steps:
- name: Checkout code
uses: actions/checkout@v4
# Build Docker image if Dockerfile exists
- name: Build Docker image
run: |
if [ -f Dockerfile ]; then
docker build -t zopio:scan .
else
echo "No Dockerfile found, skipping container scan"
exit 0
fi
# Scan built container for vulnerabilities
- name: Run Trivy container scan
if: success()
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: 'zopio:scan' # Local image to scan
format: 'sarif'
output: 'container-results.sarif'
severity: 'CRITICAL,HIGH' # Only critical and high severity
# Upload container scan results
- name: Upload container scan results
if: success()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'container-results.sarif'
# Summary job that creates the required "Security Scan" status check
security-scan-summary:
name: Security Scan
runs-on: ubuntu-latest
needs: [dependency-scan, secret-scan, docker-scan]
if: always()
steps:
- name: Check Security Scan Status
run: |
# Check if any required job failed (docker-scan is optional)
if [[ "${{ needs.dependency-scan.result }}" == "failure" || \
"${{ needs.secret-scan.result }}" == "failure" ]]; then
echo "Security Scan failed"
exit 1
else
echo "Security Scan passed"
fi