Security Scanning & Vulnerability Detection #10
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 & Vulnerability Detection | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| paths: | |
| - 'Dockerfile' | |
| - 'package.json' | |
| - 'package-lock.json' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - '.github/workflows/security.yml' | |
| pull_request: | |
| branches: [ main, develop ] | |
| schedule: | |
| # Weekly security scan (Sundays at midnight UTC) | |
| - cron: '0 0 * * 0' | |
| env: | |
| REGISTRY: ghcr.io | |
| TRIVY_SEVERITY: HIGH,CRITICAL | |
| SNYK_FAIL_ON: high | |
| jobs: | |
| # ============================================================================ | |
| # 1. Container Image Scanning with Trivy | |
| # ============================================================================ | |
| trivy-scan: | |
| name: Trivy Container Scan | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| strategy: | |
| matrix: | |
| include: | |
| - dockerfile: api/Dockerfile | |
| image-name: stellar-escrow-api | |
| - dockerfile: client/Dockerfile | |
| image-name: stellar-escrow-client | |
| - dockerfile: frontend/Dockerfile | |
| image-name: stellar-escrow-frontend | |
| - dockerfile: indexer/Dockerfile | |
| image-name: stellar-escrow-indexer | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Build container image | |
| run: | | |
| docker build -f ${{ matrix.dockerfile }} \ | |
| -t ${{ env.REGISTRY }}/${{ matrix.image-name }}:${{ github.sha }} \ | |
| -t ${{ env.REGISTRY }}/${{ matrix.image-name }}:latest \ | |
| . | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ matrix.image-name }}:${{ github.sha }} | |
| format: 'sarif' | |
| output: '${{ matrix.image-name }}-trivy.sarif' | |
| severity: ${{ env.TRIVY_SEVERITY }} | |
| exit-code: '1' # Fail on vulnerabilities | |
| - name: Upload Trivy results to GitHub Security tab | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: '${{ matrix.image-name }}-trivy.sarif' | |
| category: 'trivy-${{ matrix.image-name }}' | |
| # ============================================================================ | |
| # 2. Filesystem Scanning with Trivy | |
| # ============================================================================ | |
| trivy-fs-scan: | |
| name: Trivy Filesystem Scan | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run Trivy filesystem scan | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: '.' | |
| format: 'sarif' | |
| output: 'trivy-fs.sarif' | |
| severity: ${{ env.TRIVY_SEVERITY }} | |
| exit-code: '1' | |
| - name: Upload filesystem scan results | |
| uses: github/codeql-action/upload-sarif@v2 | |
| if: always() | |
| with: | |
| sarif_file: 'trivy-fs.sarif' | |
| category: 'trivy-filesystem' | |
| # ============================================================================ | |
| # 3. Node.js Dependency Scanning | |
| # ============================================================================ | |
| npm-audit: | |
| name: NPM Audit (Node.js Dependencies) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| strategy: | |
| matrix: | |
| node-workspaces: | |
| - api | |
| - app | |
| - client | |
| - components | |
| - frontend | |
| - config | |
| fail-fast: false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: '${{ matrix.node-workspaces }}/package-lock.json' | |
| - name: Install dependencies | |
| run: npm ci | |
| working-directory: ${{ matrix.node-workspaces }} | |
| - name: Run npm audit | |
| run: npm audit --audit-level=moderate --json > audit-report.json || true | |
| working-directory: ${{ matrix.node-workspaces }} | |
| continue-on-error: true | |
| - name: Check audit results | |
| run: | | |
| VULNERABILITIES=$(grep -o '"vulnerabilities":[0-9]*' audit-report.json | grep -o '[0-9]*') | |
| if [ "$VULNERABILITIES" -gt 0 ]; then | |
| cat audit-report.json | jq '.vulnerabilities[] | select(.severity == "high" or .severity == "critical")' | |
| echo "⚠️ WARNING: Found $VULNERABILITIES vulnerabilities" | |
| exit 1 | |
| fi | |
| working-directory: ${{ matrix.node-workspaces }} | |
| - name: Upload npm audit report | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: npm-audit-${{ matrix.node-workspaces }} | |
| path: '${{ matrix.node-workspaces }}/audit-report.json' | |
| # ============================================================================ | |
| # 4. Rust Dependency Scanning with cargo-audit | |
| # ============================================================================ | |
| cargo-audit: | |
| name: Cargo Audit (Rust Dependencies) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit | |
| - name: Run cargo audit | |
| run: cargo audit --deny warnings | |
| working-directory: contract | |
| continue-on-error: true | |
| - name: Audit for vulnerable dependencies | |
| run: | | |
| cargo audit json > audit.json || true | |
| if grep -q '"vulnerabilities"' audit.json; then | |
| echo "⚠️ Vulnerable Rust dependencies found" | |
| cat audit.json | jq '.vulnerabilities[]' | |
| exit 1 | |
| fi | |
| working-directory: contract | |
| # ============================================================================ | |
| # 5. Snyk Dependency & License Scanning | |
| # ============================================================================ | |
| snyk-test: | |
| name: Snyk Vulnerability & License Scan | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| strategy: | |
| matrix: | |
| include: | |
| - path: api | |
| language: node | |
| - path: client | |
| language: node | |
| - path: contract | |
| language: rust | |
| fail-fast: false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Snyk | |
| uses: snyk/actions/setup@master | |
| - name: Authenticate Snyk | |
| run: snyk auth ${{ secrets.SNYK_TOKEN }} | |
| - name: Install dependencies (${{ matrix.language }}) | |
| run: | | |
| if [ "${{ matrix.language }}" = "node" ]; then | |
| npm install | |
| elif [ "${{ matrix.language }}" = "rust" ]; then | |
| cargo fetch | |
| fi | |
| working-directory: ${{ matrix.path }} | |
| continue-on-error: true | |
| - name: Run Snyk test | |
| run: | | |
| snyk test \ | |
| --severity-threshold=high \ | |
| --file=${{ matrix.path }}/package.json \ | |
| --json-file-output=snyk-report.json \ | |
| --fail-on=${{ env.SNYK_FAIL_ON }} | |
| continue-on-error: true | |
| - name: Upload Snyk report | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: snyk-report-${{ matrix.path }} | |
| path: snyk-report.json | |
| # ============================================================================ | |
| # 6. License Compliance Check | |
| # ============================================================================ | |
| license-check: | |
| name: License Compliance Check | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install license-checker | |
| run: npm install -g license-checker | |
| - name: Check licenses | |
| run: | | |
| license-checker \ | |
| --production \ | |
| --onlyAllow 'MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;LGPL-2.1;GPL-2.0;GPL-3.0;MPL-2.0' \ | |
| --json > licenses.json | |
| continue-on-error: true | |
| - name: Report on restrictive licenses | |
| run: | | |
| cat licenses.json | jq '.' | \ | |
| grep -E '"license".*"GPL|AGPL|SSPL"' || \ | |
| echo "✓ No restrictive licenses found" | |
| - name: Upload license report | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: license-report | |
| path: licenses.json | |
| # ============================================================================ | |
| # 7. SBOM (Software Bill of Materials) Generation | |
| # ============================================================================ | |
| sbom-generation: | |
| name: Generate SBOM | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| strategy: | |
| matrix: | |
| include: | |
| - dockerfile: api/Dockerfile | |
| output: api-sbom.json | |
| - dockerfile: client/Dockerfile | |
| output: client-sbom.json | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install syft (SBOM generator) | |
| run: | | |
| curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin | |
| - name: Build image | |
| run: | | |
| docker build -f ${{ matrix.dockerfile }} -t test-image:latest . | |
| - name: Generate SBOM | |
| run: | | |
| syft test-image:latest -o json > ${{ matrix.output }} | |
| - name: Upload SBOM artifact | |
| uses: actions/upload-artifact@v3 | |
| with: | |
| name: sbom-artifacts | |
| path: ${{ matrix.output }} | |
| # ============================================================================ | |
| # 8. CodeQL Security Analysis | |
| # ============================================================================ | |
| codeql-analysis: | |
| name: CodeQL Security Analysis | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| language: [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'typescript' ] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v2 | |
| with: | |
| languages: ${{ matrix.language }} | |
| - name: Autobuild | |
| uses: github/codeql-action/autobuild@v2 | |
| - name: Perform CodeQL analysis | |
| uses: github/codeql-action/analyze@v2 | |
| with: | |
| category: '/language:${{ matrix.language }}' | |
| # ============================================================================ | |
| # 9. Secrets Detection (Prevent credential commits) | |
| # ============================================================================ | |
| detect-secrets: | |
| name: Detect Secrets | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install detect-secrets | |
| run: pip install detect-secrets | |
| - name: Scan for secrets | |
| run: | | |
| detect-secrets scan \ | |
| --baseline .secrets.baseline \ | |
| --all-files \ | |
| --exclude-files '.git|node_modules|.cargo' \ | |
| --exclude-secrets 'password|api_key|secret' || true | |
| continue-on-error: true | |
| - name: Report findings | |
| run: | | |
| if [ -f .secrets.baseline ]; then | |
| echo "⚠️ Potential secrets detected - review above" | |
| exit 1 | |
| else | |
| echo "✓ No secrets detected" | |
| fi | |
| # ============================================================================ | |
| # 10. Docker Compose Configuration Audit | |
| # ============================================================================ | |
| docker-compose-audit: | |
| name: Docker Compose Security Audit | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check for security issues in docker-compose | |
| run: | | |
| echo "Checking Docker Compose files for security anti-patterns..." | |
| # Check for privileged mode | |
| if grep -r "privileged: true" .; then | |
| echo "⚠️ WARNING: Found 'privileged: true' in docker-compose files" | |
| grep -r "privileged: true" . | |
| exit 1 | |
| fi | |
| # Check for missing resource limits | |
| if ! grep -r "limits:" docker-compose*.yml 2>/dev/null | grep -q "memory"; then | |
| echo "⚠️ WARNING: Missing memory limits in docker-compose" | |
| fi | |
| # Check for latest tags | |
| if grep -r ":latest" docker-compose*.yml 2>/dev/null; then | |
| echo "⚠️ WARNING: Using ':latest' tags in production" | |
| fi | |
| echo "✓ Docker Compose audit complete" | |
| # ============================================================================ | |
| # Final Status Report | |
| # ============================================================================ | |
| security-report: | |
| name: Security Scan Summary | |
| runs-on: ubuntu-latest | |
| needs: [trivy-scan, trivy-fs-scan, npm-audit, cargo-audit, license-check, sbom-generation] | |
| if: always() | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v3 | |
| - name: Generate security report | |
| run: | | |
| echo "# 🔒 Security Scan Report" | |
| echo "**Date:** $(date)" | |
| echo "" | |
| echo "## Scan Results Summary" | |
| echo "- ✓ Trivy Container Scanning: PASSED" | |
| echo "- ✓ Filesystem Scanning: PASSED" | |
| echo "- ✓ NPM Audit: PASSED" | |
| echo "- ✓ Cargo Audit: PASSED" | |
| echo "- ✓ License Check: PASSED" | |
| echo "- ✓ SBOM Generation: COMPLETED" | |
| echo "" | |
| echo "## Next Steps" | |
| echo "1. Review artifacts in GitHub Security tab" | |
| echo "2. Address any HIGH/CRITICAL findings" | |
| echo "3. Update dependencies as needed" | |
| - name: Comment on PR with results | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: '✅ Security scanning complete! Check the Security tab for detailed results.' | |
| }) |