name: Security Scanning on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] schedule: # Run security scan daily at 2 AM UTC - cron: '0 2 * * *' jobs: # Python Security Scanning with Bandit bandit-security-scan: runs-on: ubuntu-latest name: Bandit Security Scan strategy: matrix: # Define directories to scan directory: - "apps/coordinator-api/src" - "cli/aitbc_cli" - "packages/py/aitbc-core/src" - "packages/py/aitbc-crypto/src" - "packages/py/aitbc-sdk/src" - "tests" steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install bandit[toml] safety # Install project dependencies for context if [ -f "${{ matrix.directory }}/requirements.txt" ]; then pip install -r "${{ matrix.directory }}/requirements.txt" 2>/dev/null || true fi if [ -f "pyproject.toml" ]; then pip install -e . 2>/dev/null || true fi - name: Run Bandit security scan run: | echo "Scanning directory: ${{ matrix.directory }}" bandit -r ${{ matrix.directory }} \ -f json \ -o bandit-report-${{ matrix.directory }}.json \ --severity-level medium \ --confidence-level medium || true # Also generate human-readable report bandit -r ${{ matrix.directory }} \ -f txt \ -o bandit-report-${{ matrix.directory }}.txt \ --severity-level medium \ --confidence-level medium || true - name: Run Safety check for known vulnerabilities run: | echo "Running Safety check for known vulnerabilities..." safety check --json --output safety-report.json || true safety check || true - name: Upload Bandit reports uses: actions/upload-artifact@v3 if: always() with: name: bandit-reports-${{ matrix.directory }} path: | bandit-report-${{ matrix.directory }}.json bandit-report-${{ matrix.directory }}.txt retention-days: 30 - name: Upload Safety report uses: actions/upload-artifact@v3 if: always() with: name: safety-report path: safety-report.json retention-days: 30 - name: Comment PR with security findings if: github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const fs = require('fs'); const path = require('path'); try { const reportPath = `bandit-report-${{ matrix.directory }}.txt`; if (fs.existsSync(reportPath)) { const report = fs.readFileSync(reportPath, 'utf8'); // Create summary const lines = report.split('\n'); const issues = lines.filter(line => line.includes('Issue:')).length; const comment = `## 🔒 Security Scan Results for \`${{ matrix.directory }}\` **Bandit Security Scan** - Issues found: ${issues} - Severity: Medium and above - Confidence: Medium and above
📋 Detailed Report \`\`\` ${report} \`\`\`
--- *This security scan was automatically generated by Bandit.*`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment }); } } catch (error) { console.log('Could not read security report:', error.message); } # CodeQL Security Analysis codeql-security-scan: runs-on: ubuntu-latest name: CodeQL Security Analysis permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'python', 'javascript' ] steps: - name: Checkout repository 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}}" # Dependency Security Scanning dependency-security-scan: runs-on: ubuntu-latest name: Dependency Security Scan steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Run dependency security scan run: | python -m pip install --upgrade pip pip install safety # Check for known vulnerabilities in dependencies echo "Scanning Python dependencies..." safety check --json --output python-safety-report.json || true safety check || true # Check npm dependencies if they exist if [ -f "apps/explorer-web/package.json" ]; then echo "Scanning npm dependencies..." cd apps/explorer-web npm audit --json > ../npm-audit-report.json 2>&1 || true npm audit || true cd ../.. fi if [ -f "website/package.json" ]; then echo "Scanning website npm dependencies..." cd website npm audit --json > ../website-npm-audit-report.json 2>&1 || true npm audit || true cd ../.. fi - name: Upload dependency security reports uses: actions/upload-artifact@v3 if: always() with: name: dependency-security-reports path: | python-safety-report.json npm-audit-report.json website-npm-audit-report.json retention-days: 30 # Container Security Scanning (if Docker is used) container-security-scan: runs-on: ubuntu-latest name: Container Security Scan if: contains(github.event.head_commit.modified, 'Dockerfile') || contains(github.event.head_commit.modified, 'docker-compose') steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: 'ghcr.io/${{ github.repository }}:latest' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: 'trivy-results.sarif' # Security Scorecard security-scorecard: runs-on: ubuntu-latest name: OSSF Scorecard permissions: security-events: write actions: read id-token: write 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 # Note: Running without repo_token for local analysis only - name: Upload SARIF to GitHub Security tab uses: github/codeql-action/upload-sarif@v2 with: sarif_file: results.sarif # Security Summary Report security-summary: runs-on: ubuntu-latest name: Security Summary Report needs: [bandit-security-scan, codeql-security-scan, dependency-security-scan] if: always() steps: - name: Download all artifacts uses: actions/download-artifact@v3 - name: Generate security summary run: | echo "# 🔒 Security Scan Summary" > security-summary.md echo "" >> security-summary.md echo "## Scan Results" >> security-summary.md echo "" >> security-summary.md # Bandit results echo "### Bandit Security Scan" >> security-summary.md echo "- Scanned multiple Python directories" >> security-summary.md echo "- Severity level: Medium and above" >> security-summary.md echo "- Confidence level: Medium and above" >> security-summary.md echo "" >> security-summary.md # CodeQL results echo "### CodeQL Security Analysis" >> security-summary.md echo "- Languages: Python, JavaScript" >> security-summary.md echo "- Queries: security-extended, security-and-quality" >> security-summary.md echo "" >> security-summary.md # Dependency results echo "### Dependency Security Scan" >> security-summary.md echo "- Python dependencies checked with Safety" >> security-summary.md echo "- npm dependencies checked with npm audit" >> security-summary.md echo "" >> security-summary.md # Additional info echo "### Additional Information" >> security-summary.md echo "- Scans run on: $(date)" >> security-summary.md echo "- Commit: ${{ github.sha }}" >> security-summary.md echo "- Branch: ${{ github.ref_name }}" >> security-summary.md echo "" >> security-summary.md echo "## Recommendations" >> security-summary.md echo "1. Review any high-severity findings immediately" >> security-summary.md echo "2. Update dependencies with known vulnerabilities" >> security-summary.md echo "3. Address security best practices recommendations" >> security-summary.md echo "4. Regular security audits and penetration testing" >> security-summary.md - name: Upload security summary uses: actions/upload-artifact@v3 with: name: security-summary path: security-summary.md retention-days: 90 - name: Comment PR with security summary if: github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const fs = require('fs'); try { 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 }); } catch (error) { console.log('Could not read security summary:', error.message); }