|
1 |
| -name: Security Scan |
| 1 | +name: π‘οΈ Security Scan |
2 | 2 |
|
3 | 3 | on:
|
4 | 4 | push:
|
5 |
| - branches: [ main, develop ] |
| 5 | + branches: [ "master", "main", "develop" ] |
6 | 6 | pull_request:
|
7 |
| - branches: [ main ] |
| 7 | + branches: [ "master", "main" ] |
8 | 8 | schedule:
|
9 |
| - # Run weekly security scans on Sundays at 2 AM UTC |
10 |
| - - cron: '0 2 * * 0' |
| 9 | + # Run security scan daily at 2 AM UTC |
| 10 | + - cron: '0 2 * * *' |
| 11 | + workflow_dispatch: # Allow manual trigger |
11 | 12 |
|
12 | 13 | jobs:
|
13 |
| - security: |
| 14 | + security-scan: |
| 15 | + name: π Security Vulnerability Scan |
14 | 16 | runs-on: ubuntu-latest
|
15 |
| - name: Security Analysis |
16 |
| - |
17 | 17 | permissions:
|
18 | 18 | actions: read
|
19 | 19 | contents: read
|
20 | 20 | security-events: write
|
21 | 21 |
|
| 22 | + strategy: |
| 23 | + matrix: |
| 24 | + python-version: ["3.10", "3.11", "3.12"] |
| 25 | + |
22 | 26 | steps:
|
23 |
| - - name: Checkout code |
| 27 | + - name: π₯ Checkout repository |
24 | 28 | uses: actions/checkout@v4
|
25 |
| - |
26 |
| - - name: Set up Python |
| 29 | + with: |
| 30 | + fetch-depth: 0 |
| 31 | + |
| 32 | + - name: π Set up Python ${{ matrix.python-version }} |
27 | 33 | uses: actions/setup-python@v4
|
28 | 34 | with:
|
29 |
| - python-version: '3.9' |
30 |
| - |
31 |
| - - name: Install dependencies |
| 35 | + python-version: ${{ matrix.python-version }} |
| 36 | + cache: 'pip' |
| 37 | + cache-dependency-path: 'requirements.txt' |
| 38 | + timeout-minutes: 10 |
| 39 | + |
| 40 | + - name: β
Verify Python Version (Must be 3.10+) |
| 41 | + run: | |
| 42 | + python_version=$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") |
| 43 | + echo "Python version detected: $python_version" |
| 44 | + if [[ "$python_version" < "3.10" ]]; then |
| 45 | + echo "β ERROR: This workflow requires Python 3.10+ but found $python_version" |
| 46 | + echo "This indicates an old workflow is running. Please cancel old workflow runs." |
| 47 | + exit 1 |
| 48 | + fi |
| 49 | + echo "β
Python version $python_version is compatible with MCP library" |
| 50 | +
|
| 51 | + - name: π¦ Install dependencies |
| 52 | + timeout-minutes: 15 |
32 | 53 | run: |
|
33 | 54 | python -m pip install --upgrade pip
|
34 |
| - pip install -r requirements.txt |
35 |
| - pip install bandit safety semgrep |
| 55 | + # Install dependencies, skipping Windows-specific packages on Linux |
| 56 | + if [[ "$RUNNER_OS" == "Linux" ]]; then |
| 57 | + # Create temp requirements file without Windows-specific packages for Linux |
| 58 | + grep -v "platform_system==\"Windows\"" requirements.txt > temp-requirements.txt |
| 59 | + echo "Installing filtered requirements for Linux:" |
| 60 | + cat temp-requirements.txt |
| 61 | + pip install -r temp-requirements.txt --timeout 300 |
| 62 | + else |
| 63 | + pip install -r requirements.txt --timeout 300 |
| 64 | + fi |
| 65 | + pip install safety bandit semgrep --timeout 300 |
36 | 66 |
|
37 |
| - - name: Run Bandit Security Linter |
38 |
| - run: | |
39 |
| - bandit -r . -f json -o bandit-report.json || true |
40 |
| - bandit -r . -f txt |
41 |
| - continue-on-error: true |
42 |
| - |
43 |
| - - name: Run Safety Check |
| 67 | + - name: π Run Safety - Check for known vulnerabilities |
44 | 68 | run: |
|
| 69 | + echo "## π‘οΈ Safety - Known Vulnerabilities Check" >> $GITHUB_STEP_SUMMARY |
45 | 70 | safety check --json --output safety-report.json || true
|
46 |
| - safety check |
47 |
| - continue-on-error: true |
48 |
| - |
49 |
| - - name: Run Semgrep |
| 71 | + if [ -f safety-report.json ]; then |
| 72 | + echo "### Safety Report Results:" >> $GITHUB_STEP_SUMMARY |
| 73 | + python -c "import json; data=json.load(open('safety-report.json')); print('- Total vulnerabilities found:', len(data.get('vulnerabilities', [])))" >> $GITHUB_STEP_SUMMARY |
| 74 | + if [ $(python -c "import json; data=json.load(open('safety-report.json')); print(len(data.get('vulnerabilities', [])))") -gt 0 ]; then |
| 75 | + echo "β Vulnerabilities detected! See full report in artifacts." >> $GITHUB_STEP_SUMMARY |
| 76 | + exit 1 |
| 77 | + else |
| 78 | + echo "β
No known vulnerabilities found!" >> $GITHUB_STEP_SUMMARY |
| 79 | + fi |
| 80 | + fi |
| 81 | +
|
| 82 | + - name: π Run Bandit - Security linter for Python |
50 | 83 | run: |
|
51 |
| - semgrep --config=auto --json --output=semgrep-report.json . || true |
52 |
| - semgrep --config=auto . |
53 |
| - continue-on-error: true |
54 |
| - |
55 |
| - - name: Upload Bandit Results to GitHub Security |
56 |
| - uses: github/codeql-action/upload-sarif@v2 |
57 |
| - if: always() |
58 |
| - with: |
59 |
| - sarif_file: bandit-report.json |
60 |
| - continue-on-error: true |
| 84 | + echo "## π Bandit - Python Security Linter" >> $GITHUB_STEP_SUMMARY |
| 85 | + bandit -r . -f json -o bandit-report.json || true |
| 86 | + if [ -f bandit-report.json ]; then |
| 87 | + echo "### Bandit Report Results:" >> $GITHUB_STEP_SUMMARY |
| 88 | + python -c "import json; data=json.load(open('bandit-report.json')); print('- Total issues found:', len(data.get('results', [])))" >> $GITHUB_STEP_SUMMARY |
| 89 | + python -c "import json; data=json.load(open('bandit-report.json')); high=[r for r in data.get('results',[]) if r.get('issue_severity')=='HIGH']; medium=[r for r in data.get('results',[]) if r.get('issue_severity')=='MEDIUM']; print(f'- High severity: {len(high)}'); print(f'- Medium severity: {len(medium)}')" >> $GITHUB_STEP_SUMMARY |
| 90 | + fi |
61 | 91 |
|
62 |
| - - name: Archive security reports |
63 |
| - uses: actions/upload-artifact@v3 |
| 92 | + - name: β‘ Run Semgrep - Static analysis |
| 93 | + run: | |
| 94 | + echo "## β‘ Semgrep - Static Code Analysis" >> $GITHUB_STEP_SUMMARY |
| 95 | + semgrep --config=auto --json --output=semgrep-report.json . || true |
| 96 | + if [ -f semgrep-report.json ]; then |
| 97 | + echo "### Semgrep Report Results:" >> $GITHUB_STEP_SUMMARY |
| 98 | + python -c "import json; data=json.load(open('semgrep-report.json')); results=data.get('results',[]); print('- Total findings:', len(results)); critical=[r for r in results if r.get('extra',{}).get('severity')=='ERROR']; warning=[r for r in results if r.get('extra',{}).get('severity')=='WARNING']; print(f'- Critical: {len(critical)}'); print(f'- Warnings: {len(warning)}')" >> $GITHUB_STEP_SUMMARY |
| 99 | + fi |
| 100 | +
|
| 101 | + - name: π Generate Security Report |
| 102 | + run: | |
| 103 | + echo "## π Security Scan Summary" >> $GITHUB_STEP_SUMMARY |
| 104 | + echo "### Scan Details:" >> $GITHUB_STEP_SUMMARY |
| 105 | + echo "- Python Version: ${{ matrix.python-version }}" >> $GITHUB_STEP_SUMMARY |
| 106 | + echo "- Scan Date: $(date)" >> $GITHUB_STEP_SUMMARY |
| 107 | + echo "- Repository: ${{ github.repository }}" >> $GITHUB_STEP_SUMMARY |
| 108 | + echo "- Branch: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY |
| 109 | +
|
| 110 | + - name: π€ Upload Security Reports |
| 111 | + uses: actions/upload-artifact@v4 |
64 | 112 | if: always()
|
65 | 113 | with:
|
66 |
| - name: security-reports |
| 114 | + name: security-reports-py${{ matrix.python-version }} |
67 | 115 | path: |
|
68 |
| - bandit-report.json |
69 | 116 | safety-report.json
|
| 117 | + bandit-report.json |
70 | 118 | semgrep-report.json
|
| 119 | + retention-days: 30 |
71 | 120 |
|
72 |
| - dependency-check: |
| 121 | + dependency-review: |
| 122 | + name: π Dependency Review |
73 | 123 | runs-on: ubuntu-latest
|
74 |
| - name: Dependency Vulnerability Check |
75 |
| - |
| 124 | + if: github.event_name == 'pull_request' |
76 | 125 | steps:
|
77 |
| - - name: Checkout code |
| 126 | + - name: π₯ Checkout repository |
78 | 127 | uses: actions/checkout@v4
|
79 | 128 |
|
80 |
| - - name: Set up Python |
81 |
| - uses: actions/setup-python@v4 |
| 129 | + - name: π Dependency Review |
| 130 | + uses: actions/dependency-review-action@v3 |
82 | 131 | with:
|
83 |
| - python-version: '3.9' |
84 |
| - |
85 |
| - - name: Install pip-audit |
86 |
| - run: | |
87 |
| - python -m pip install --upgrade pip |
88 |
| - pip install pip-audit |
89 |
| - |
90 |
| - - name: Run pip-audit |
91 |
| - run: | |
92 |
| - pip-audit --desc --format=json --output=pip-audit-report.json || true |
93 |
| - pip-audit --desc |
94 |
| - continue-on-error: true |
95 |
| - |
96 |
| - - name: Upload pip-audit results |
97 |
| - uses: actions/upload-artifact@v3 |
98 |
| - if: always() |
| 132 | + fail-on-severity: moderate |
| 133 | + |
| 134 | + codeql-analysis: |
| 135 | + name: π΅οΈ CodeQL Analysis |
| 136 | + runs-on: ubuntu-latest |
| 137 | + permissions: |
| 138 | + actions: read |
| 139 | + contents: read |
| 140 | + security-events: write |
| 141 | + |
| 142 | + strategy: |
| 143 | + fail-fast: false |
| 144 | + matrix: |
| 145 | + language: [ 'python' ] |
| 146 | + |
| 147 | + steps: |
| 148 | + - name: π₯ Checkout repository |
| 149 | + uses: actions/checkout@v4 |
| 150 | + |
| 151 | + - name: π§ Initialize CodeQL |
| 152 | + uses: github/codeql-action/init@v2 |
99 | 153 | with:
|
100 |
| - name: pip-audit-report |
101 |
| - path: pip-audit-report.json |
| 154 | + languages: ${{ matrix.language }} |
| 155 | + queries: security-extended,security-and-quality |
102 | 156 |
|
103 |
| - secrets-scan: |
| 157 | + - name: ποΈ Autobuild |
| 158 | + uses: github/codeql-action/autobuild@v2 |
| 159 | + |
| 160 | + - name: π Perform CodeQL Analysis |
| 161 | + uses: github/codeql-action/analyze@v2 |
| 162 | + with: |
| 163 | + category: "/language:${{matrix.language}}" |
| 164 | + |
| 165 | + secret-scan: |
| 166 | + name: π Secret Scanning |
104 | 167 | runs-on: ubuntu-latest
|
105 |
| - name: Secrets Detection |
106 |
| - |
107 | 168 | steps:
|
108 |
| - - name: Checkout code |
| 169 | + - name: π₯ Checkout repository |
109 | 170 | uses: actions/checkout@v4
|
110 | 171 | with:
|
111 | 172 | fetch-depth: 0
|
112 |
| - |
113 |
| - - name: Run TruffleHog |
| 173 | + |
| 174 | + - name: π Run TruffleHog |
114 | 175 | uses: trufflesecurity/trufflehog@main
|
115 | 176 | with:
|
116 | 177 | path: ./
|
117 | 178 | base: main
|
118 | 179 | head: HEAD
|
119 | 180 | extra_args: --debug --only-verified
|
| 181 | + |
| 182 | + security-audit: |
| 183 | + name: π‘οΈ Security Audit |
| 184 | + runs-on: ubuntu-latest |
| 185 | + needs: [security-scan, codeql-analysis] |
| 186 | + if: always() |
| 187 | + steps: |
| 188 | + - name: π₯ Checkout repository |
| 189 | + uses: actions/checkout@v4 |
| 190 | + |
| 191 | + - name: π Security Audit Summary |
| 192 | + run: | |
| 193 | + echo "# π‘οΈ Security Audit Complete" >> $GITHUB_STEP_SUMMARY |
| 194 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 195 | + echo "## π Scans Performed:" >> $GITHUB_STEP_SUMMARY |
| 196 | + echo "- β
Python Security Linting (Bandit)" >> $GITHUB_STEP_SUMMARY |
| 197 | + echo "- β
Known Vulnerability Check (Safety)" >> $GITHUB_STEP_SUMMARY |
| 198 | + echo "- β
Static Code Analysis (Semgrep)" >> $GITHUB_STEP_SUMMARY |
| 199 | + echo "- β
Advanced Code Analysis (CodeQL)" >> $GITHUB_STEP_SUMMARY |
| 200 | + echo "- β
Secret Detection (TruffleHog)" >> $GITHUB_STEP_SUMMARY |
| 201 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 202 | + echo "## π Artifacts Generated:" >> $GITHUB_STEP_SUMMARY |
| 203 | + echo "- Security reports available in workflow artifacts" >> $GITHUB_STEP_SUMMARY |
| 204 | + echo "- CodeQL results available in Security tab" >> $GITHUB_STEP_SUMMARY |
| 205 | + echo "" >> $GITHUB_STEP_SUMMARY |
| 206 | + echo "## π¨ Next Steps:" >> $GITHUB_STEP_SUMMARY |
| 207 | + echo "1. Review all security findings" >> $GITHUB_STEP_SUMMARY |
| 208 | + echo "2. Address high-priority vulnerabilities" >> $GITHUB_STEP_SUMMARY |
| 209 | + echo "3. Update dependencies as needed" >> $GITHUB_STEP_SUMMARY |
| 210 | + echo "4. Document remediation actions" >> $GITHUB_STEP_SUMMARY |
0 commit comments