diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..74a3604 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,216 @@ +name: Security Scanning + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + schedule: + # Run security scans daily at 2 AM UTC + - cron: '0 2 * * *' + workflow_dispatch: + +permissions: + contents: read + security-events: write + actions: read + +jobs: + dependency-check: + name: Dependency Vulnerability Scan + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install safety pip-audit + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Run Safety check + run: | + safety check --json --output safety-report.json || true + safety check || true + + - name: Run pip-audit + run: | + pip-audit --desc --format json --output pip-audit-report.json || true + pip-audit || true + + - name: Upload dependency scan results + uses: actions/upload-artifact@v4 + if: always() + with: + name: dependency-scan-results + path: | + safety-report.json + pip-audit-report.json + + codeql-analysis: + name: CodeQL Security Analysis + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: security-extended,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}}" + + secret-scanning: + name: Secret Detection + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: TruffleHog Secret Scan + uses: trufflesecurity/trufflehog@main + with: + path: ./ + base: ${{ github.event.repository.default_branch }} + head: HEAD + + container-scanning: + name: Container Security Scan + runs-on: ubuntu-latest + needs: [dependency-check] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build Docker image + run: | + docker build -t geo-analytics-api:test . + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'geo-analytics-api:test' + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'CRITICAL,HIGH,MEDIUM' + + - name: Upload Trivy results to GitHub Security + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: 'trivy-results.sarif' + + - name: Run Trivy in table format + uses: aquasecurity/trivy-action@master + with: + image-ref: 'geo-analytics-api:test' + format: 'table' + severity: 'CRITICAL,HIGH,MEDIUM' + + sast-analysis: + name: Static Application Security Testing + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Bandit + run: | + python -m pip install --upgrade pip + pip install bandit[toml] + + - name: Run Bandit security linter + run: | + bandit -r . -f json -o bandit-report.json || true + bandit -r . -f screen + + - name: Upload Bandit results + uses: actions/upload-artifact@v4 + if: always() + with: + name: bandit-results + path: bandit-report.json + + license-check: + name: License Compliance Check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pip-licenses + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Check licenses + run: | + pip-licenses --format=json --output-file=licenses.json + pip-licenses --format=markdown --output-file=licenses.md + pip-licenses + + - name: Upload license reports + uses: actions/upload-artifact@v4 + with: + name: license-reports + path: | + licenses.json + licenses.md + + security-summary: + name: Security Scan Summary + runs-on: ubuntu-latest + needs: [dependency-check, codeql-analysis, secret-scanning, container-scanning, sast-analysis, license-check] + if: always() + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + + - name: Create security summary + run: | + echo "# Security Scan Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Scan Status" >> $GITHUB_STEP_SUMMARY + echo "- Dependency Check: ${{ needs.dependency-check.result }}" >> $GITHUB_STEP_SUMMARY + echo "- CodeQL Analysis: ${{ needs.codeql-analysis.result }}" >> $GITHUB_STEP_SUMMARY + echo "- Secret Scanning: ${{ needs.secret-scanning.result }}" >> $GITHUB_STEP_SUMMARY + echo "- Container Scanning: ${{ needs.container-scanning.result }}" >> $GITHUB_STEP_SUMMARY + echo "- SAST Analysis: ${{ needs.sast-analysis.result }}" >> $GITHUB_STEP_SUMMARY + echo "- License Check: ${{ needs.license-check.result }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Review the artifacts and Security tab for detailed results." >> $GITHUB_STEP_SUMMARY