security.yml•9.01 kB
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
# Run security scan daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
permissions:
contents: read
security-events: write
actions: read
jobs:
security-scan:
name: Security Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=moderate
continue-on-error: true
- name: Run custom security scan
run: npm run security:scan
continue-on-error: true
- name: Upload security scan results
uses: actions/upload-artifact@v4
if: always()
with:
name: security-scan-report
path: security-scan-report.json
retention-days: 30
dependency-scan:
name: Dependency Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: Upload Snyk results to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: snyk.sarif
code-security:
name: Code Security Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/secrets
p/owasp-top-ten
generateSarif: "1"
- name: Upload Semgrep results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: semgrep.sarif
docker-security:
name: Docker Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
run: |
docker build -t open-search-mcp:test .
continue-on-error: true
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'open-search-mcp:test'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Scan Docker Compose images
run: |
# Extract images from docker-compose
images=$(grep -E "image:" deployment/searx-cluster.yml | awk '{print $2}' | sort -u)
for image in $images; do
echo "Scanning $image..."
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --exit-code 1 --severity HIGH,CRITICAL $image || true
done
secrets-scan:
name: Secrets Detection
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run GitLeaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
- name: Run TruffleHog
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
head: HEAD
extra_args: --debug --only-verified
configuration-security:
name: Configuration Security Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check for sensitive files
run: |
# Check for files that shouldn't be in the repository
sensitive_files=()
if [ -f ".env" ]; then
sensitive_files+=(".env")
fi
if [ -f "config/user.json" ]; then
sensitive_files+=("config/user.json")
fi
# Check for potential API keys in files
if grep -r "AIza\|sk-\|ghp_" --include="*.js" --include="*.ts" --include="*.json" --include="*.yml" .; then
echo "Potential API keys found in repository"
exit 1
fi
if [ ${#sensitive_files[@]} -gt 0 ]; then
echo "Sensitive files found: ${sensitive_files[*]}"
exit 1
fi
echo "Configuration security check passed"
- name: Validate Docker security configuration
run: |
# Check Docker Compose security settings
if ! grep -q "no-new-privileges:true" deployment/searx-cluster.yml; then
echo "Docker containers should use no-new-privileges:true"
exit 1
fi
if ! grep -q "user:" deployment/searx-cluster.yml; then
echo "Docker containers should run as non-root user"
exit 1
fi
if ! grep -q "read_only: true" deployment/searx-cluster.yml; then
echo "Docker containers should use read-only filesystem"
exit 1
fi
echo "Docker security configuration validated"
security-report:
name: Generate Security Report
runs-on: ubuntu-latest
needs: [security-scan, dependency-scan, code-security, docker-security, secrets-scan, configuration-security]
if: always()
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download security scan results
uses: actions/download-artifact@v4
with:
name: security-scan-report
path: ./reports/
- name: Generate security summary
run: |
echo "# Security Scan Summary" > security-summary.md
echo "" >> security-summary.md
echo "**Scan Date:** $(date)" >> security-summary.md
echo "**Repository:** ${{ github.repository }}" >> security-summary.md
echo "**Branch:** ${{ github.ref_name }}" >> security-summary.md
echo "**Commit:** ${{ github.sha }}" >> security-summary.md
echo "" >> security-summary.md
# Add job statuses
echo "## Job Results" >> security-summary.md
echo "- Security Scan: ${{ needs.security-scan.result }}" >> security-summary.md
echo "- Dependency Scan: ${{ needs.dependency-scan.result }}" >> security-summary.md
echo "- Code Security: ${{ needs.code-security.result }}" >> security-summary.md
echo "- Docker Security: ${{ needs.docker-security.result }}" >> security-summary.md
echo "- Secrets Scan: ${{ needs.secrets-scan.result }}" >> security-summary.md
echo "- Configuration Security: ${{ needs.configuration-security.result }}" >> security-summary.md
# Add detailed results if available
if [ -f "./reports/security-scan-report.json" ]; then
echo "" >> security-summary.md
echo "## Detailed Results" >> security-summary.md
echo "See attached security-scan-report.json for detailed findings." >> security-summary.md
fi
- name: Upload security summary
uses: actions/upload-artifact@v4
with:
name: security-summary
path: security-summary.md
retention-days: 90
- name: Comment PR with security results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('security-summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
- name: Fail workflow if critical issues found
run: |
# Check if any critical security issues were found
if [ "${{ needs.secrets-scan.result }}" == "failure" ]; then
echo "Critical: Secrets detected in repository"
exit 1
fi
if [ "${{ needs.configuration-security.result }}" == "failure" ]; then
echo "Critical: Configuration security issues found"
exit 1
fi
echo "Security scan completed successfully"