Security Scanning #86
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Security Scanning | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main ] | |
| schedule: | |
| # Run security scans daily at 2 AM UTC | |
| - cron: '0 2 * * *' | |
| workflow_dispatch: | |
| env: | |
| PYTHON_VERSION: "3.10" | |
| jobs: | |
| dependency-scan: | |
| name: Dependency Vulnerability Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: "1.6.1" | |
| virtualenvs-create: true | |
| virtualenvs-in-project: true | |
| - name: Install dependencies | |
| run: | | |
| poetry install --with dev | |
| - name: Run Safety check | |
| run: | | |
| poetry run safety check --json --output safety-report.json || true | |
| poetry run safety check --short-report | |
| - name: Run pip-audit | |
| run: | | |
| pip install pip-audit | |
| pip-audit --format=json --output=pip-audit-report.json || true | |
| pip-audit --format=cyclone-json --output=pip-audit-cyclone.json || true | |
| - name: Upload dependency scan results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: dependency-scan-results | |
| path: | | |
| safety-report.json | |
| pip-audit-report.json | |
| pip-audit-cyclone.json | |
| code-security-scan: | |
| name: Code Security Analysis | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: "1.6.1" | |
| - name: Install dependencies | |
| run: | | |
| poetry install --with dev | |
| - name: Run Bandit security linter | |
| run: | | |
| poetry run bandit -r . -x tests/ -f json -o bandit-report.json | |
| poetry run bandit -r . -x tests/ -f txt -o bandit-report.txt | |
| - name: Run semgrep security analysis | |
| uses: returntocorp/semgrep-action@v1 | |
| with: | |
| config: >- | |
| p/security-audit | |
| p/secrets | |
| p/python | |
| p/owasp-top-ten | |
| generateSarif: "1" | |
| - name: Upload code security results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: code-security-results | |
| path: | | |
| bandit-report.json | |
| bandit-report.txt | |
| - name: Upload SARIF file | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: semgrep.sarif | |
| secret-scan: | |
| name: Secret Detection | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run TruffleHog secret scan | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| base: main | |
| head: HEAD | |
| extra_args: --debug --only-verified | |
| - name: Run GitLeaks secret scan | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} | |
| docker-security-scan: | |
| name: Docker Security Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Build Docker image | |
| run: | | |
| docker build -t rag-templates:security-test . | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: 'rag-templates:security-test' | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| - name: Run Trivy filesystem scan | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: '.' | |
| format: 'sarif' | |
| output: 'trivy-fs-results.sarif' | |
| - name: Upload Trivy scan results | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: | | |
| trivy-results.sarif | |
| trivy-fs-results.sarif | |
| - name: Run Docker Bench Security | |
| run: | | |
| docker run --rm --net host --pid host --userns host --cap-add audit_control \ | |
| -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \ | |
| -v /etc:/etc:ro \ | |
| -v /usr/bin/containerd:/usr/bin/containerd:ro \ | |
| -v /usr/bin/runc:/usr/bin/runc:ro \ | |
| -v /usr/lib/systemd:/usr/lib/systemd:ro \ | |
| -v /var/lib:/var/lib:ro \ | |
| -v /var/run/docker.sock:/var/run/docker.sock:ro \ | |
| --label docker_bench_security \ | |
| docker/docker-bench-security > docker-bench-results.txt || true | |
| - name: Upload Docker security results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: docker-security-results | |
| path: | | |
| docker-bench-results.txt | |
| infrastructure-scan: | |
| name: Infrastructure Security Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run Checkov IaC security scan | |
| uses: bridgecrewio/checkov-action@master | |
| with: | |
| directory: . | |
| framework: dockerfile,kubernetes,terraform | |
| output_format: sarif | |
| output_file_path: checkov-results.sarif | |
| - name: Upload Checkov scan results | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: checkov-results.sarif | |
| - name: Run Terrascan | |
| uses: tenable/terrascan-action@main | |
| with: | |
| iac_type: 'docker' | |
| iac_version: 'v1' | |
| policy_type: 'aws' | |
| only_warn: true | |
| sarif_upload: true | |
| compliance-check: | |
| name: Compliance & License Check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| version: "1.6.1" | |
| - name: Install dependencies | |
| run: | | |
| poetry install --with dev | |
| - name: Check license compatibility | |
| run: | | |
| pip install licensecheck | |
| licensecheck --no-deps --zero --format json > license-report.json | |
| licensecheck --no-deps --zero | |
| - name: Run FOSSA license scan | |
| if: env.FOSSA_API_KEY != '' | |
| uses: fossas/fossa-action@main | |
| with: | |
| api-key: ${{ secrets.FOSSA_API_KEY }} | |
| run-tests: true | |
| - name: Upload compliance results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: compliance-results | |
| path: | | |
| license-report.json | |
| codeql-analysis: | |
| name: CodeQL Security Analysis | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| actions: read | |
| contents: read | |
| security-events: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| language: [ 'python', 'javascript' ] | |
| steps: | |
| - name: Checkout code | |
| 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}}" | |
| security-scorecard: | |
| name: OSSF Security Scorecard | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| permissions: | |
| security-events: write | |
| id-token: write | |
| actions: read | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| - name: Run analysis | |
| uses: ossf/scorecard-action@v2.3.1 | |
| with: | |
| results_file: results.sarif | |
| results_format: sarif | |
| publish_results: true | |
| - name: Upload SARIF results | |
| uses: github/codeql-action/upload-sarif@v2 | |
| with: | |
| sarif_file: results.sarif | |
| security-report: | |
| name: Generate Security Report | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: [dependency-scan, code-security-scan, secret-scan, docker-security-scan, compliance-check] | |
| if: always() | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download all security artifacts | |
| uses: actions/download-artifact@v3 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Generate security report | |
| run: | | |
| python scripts/ci/generate-security-report.py \ | |
| --output security-report.md \ | |
| --format markdown | |
| - name: Upload security report | |
| uses: actions/upload-artifact@v3 | |
| with: | |
| name: security-report | |
| path: security-report.md | |
| - name: Comment security report on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v6 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const report = fs.readFileSync('security-report.md', 'utf8'); | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: `## 🔒 Security Scan Results\n\n${report}` | |
| }); | |
| security-policy-check: | |
| name: Security Policy Validation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check for security policy | |
| run: | | |
| if [ ! -f SECURITY.md ]; then | |
| echo "❌ SECURITY.md file not found" | |
| exit 1 | |
| fi | |
| echo "✅ SECURITY.md file exists" | |
| - name: Validate security policy content | |
| run: | | |
| python scripts/ci/validate-security-policy.py SECURITY.md | |
| - name: Check for vulnerability disclosure | |
| run: | | |
| if ! grep -q "vulnerability" SECURITY.md; then | |
| echo "❌ Security policy should include vulnerability disclosure process" | |
| exit 1 | |
| fi | |
| echo "✅ Vulnerability disclosure process found" | |
| penetration-test: | |
| name: Basic Penetration Testing | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Start application | |
| run: | | |
| docker-compose -f docker-compose.test.yml up -d | |
| sleep 30 | |
| - name: Install OWASP ZAP | |
| run: | | |
| docker pull owasp/zap2docker-stable | |
| - name: Run OWASP ZAP baseline scan | |
| run: | | |
| docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable \ | |
| zap-baseline.py -t http://localhost:8000 -J zap-report.json || true | |
| - name: Run OWASP ZAP full scan | |
| run: | | |
| docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable \ | |
| zap-full-scan.py -t http://localhost:8000 -J zap-full-report.json || true | |
| - name: Upload penetration test results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: penetration-test-results | |
| path: | | |
| zap-report.json | |
| zap-full-report.json | |
| - name: Stop application | |
| if: always() | |
| run: | | |
| docker-compose -f docker-compose.test.yml down |