-
Notifications
You must be signed in to change notification settings - Fork 0
154 lines (133 loc) · 4.7 KB
/
ci.yml
File metadata and controls
154 lines (133 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
name: CI (uv)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
name: Test / Lint / Typecheck (uv)
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Sync dependencies with uv
run: uv sync --all-extras
- name: Lint (ruff)
run: uv run ruff check python_project_deployment
- name: Typecheck (mypy)
run: uv run mypy python_project_deployment
- name: Tests (pytest)
run: uv run pytest --cov --cov-report=xml --cov-report=html
- name: Security scan for dangerous APIs
run: |
set -euo pipefail
if grep -R --line-number -E "\beval\(|\bexec\(|pickle\.loads|yaml\.load|subprocess\.(Popen|call)" python_project_deployment/ tests/ || true; then
echo "⚠️ Potentially dangerous API usage detected. Please review before merging." >&2
exit 2
fi
continue-on-error: true
- name: Upload coverage.xml
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
- name: Upload coverage HTML
uses: actions/upload-artifact@v4
with:
name: coverage-html-${{ matrix.python-version }}
path: htmlcov
security:
name: Security Scan
runs-on: ubuntu-latest
env:
SECURITY_FAIL_LEVEL: MEDIUM
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python 3.11
run: uv python install 3.11
- name: Sync deps and install security tools
run: |
uv sync --all-extras
uv pip install bandit safety
- name: Run Bandit and export SARIF
run: |
uv run bandit -r python_project_deployment/ -f json -o bandit-report.json
uv run bandit -r python_project_deployment/ -f sarif -o bandit-report.sarif
continue-on-error: true
- name: Upload Bandit SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: bandit-report.sarif
continue-on-error: true
- name: Run Safety (fail on any vulnerability)
run: |
uv run safety check --json > safety-report.json || true
python - <<'PY'
import json,sys,os
try:
data=json.load(open('safety-report.json'))
if data.get('vulnerabilities'):
print('Safety reported vulnerabilities')
sys.exit(2)
print('No safety vulnerabilities')
except Exception as e:
print(f'Error parsing safety output: {e}')
sys.exit(0)
PY
continue-on-error: true
- name: Apply Bandit threshold
run: |
python - <<'PY'
import json,sys,os
level=os.environ.get('SECURITY_FAIL_LEVEL','MEDIUM').upper()
try:
data=json.load(open('bandit-report.json'))
sevs=[issue.get('issue_severity','') for issue in data.get('results',[])]
if level=='NONE':
print('SECURITY_FAIL_LEVEL=NONE: not failing on bandit issues')
sys.exit(0)
if level=='HIGH':
if 'HIGH' in sevs:
print('Failing on HIGH bandit issues')
sys.exit(2)
else:
print('No HIGH bandit issues')
sys.exit(0)
if level=='MEDIUM':
if any(s in ('HIGH','MEDIUM') for s in sevs):
print('Failing on MEDIUM or HIGH bandit issues')
sys.exit(2)
else:
print('No MEDIUM/HIGH bandit issues')
sys.exit(0)
print('Unknown SECURITY_FAIL_LEVEL:', level)
sys.exit(1)
except Exception as e:
print(f'Error parsing bandit report: {e}')
sys.exit(0)
PY
continue-on-error: true
- name: Upload security reports
if: always()
uses: actions/upload-artifact@v4
with:
name: security-reports
path: |
bandit-report.json
bandit-report.sarif
safety-report.json
if data.get('vulnerabilities'):