-
-
Notifications
You must be signed in to change notification settings - Fork 11
261 lines (234 loc) · 8.09 KB
/
Copy pathci.yml
File metadata and controls
261 lines (234 loc) · 8.09 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# CI checks to run when a PR is opened, or manually via workflow_dispatch
# Test and lint are handled by their own dedicated workflows
name: 🚦 CI
on:
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
PYTHON_VERSION: '3.11'
jobs:
changes:
name: 🔎 Detect Changes
runs-on: ubuntu-latest
outputs:
lockfile: ${{ steps.filter.outputs.lockfile }}
workflows: ${{ steps.filter.outputs.workflows }}
src: ${{ steps.filter.outputs.src }}
docker: ${{ steps.filter.outputs.docker }}
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Filter Paths
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
id: filter
with:
filters: |
lockfile:
- 'package-lock.json'
- 'scripts/requirements.txt'
workflows:
- '.github/workflows/**'
src:
- 'apps/**'
- 'scripts/**'
- 'package.json'
- 'frameworks.json'
- 'config.json'
docker:
- 'Dockerfile'
- '.dockerignore'
- 'docker-compose.yml'
dependency-audit:
name: 🔒 Dependency Audit
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.lockfile == 'true' && github.event_name == 'pull_request'
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Review Dependencies
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
with:
fail-on-severity: moderate
workflow-audit:
name: 🛠️ Workflow Audit
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.workflows == 'true' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Run Actionlint
uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2
with:
fail-on-error: true
- name: Run Zizmor
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
with:
inputs: .github/workflows/
advanced-security: false
annotations: true
smoke:
name: 💨 Smoke Test
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
cache-dependency-path: scripts/requirements.txt
- name: Install dependencies
run: pip install -r scripts/requirements.txt
- name: Validate config schemas
run: python scripts/verify/validate_schemas.py
config-sync:
name: 🧬 Config Sync
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
cache-dependency-path: scripts/requirements.txt
- name: Install dependencies
run: pip install -r scripts/requirements.txt
- name: Regenerate config-derived files
run: |
python scripts/setup/generate_scripts.py
python scripts/setup/generate_mocks.py
- name: Check for drift
run: |
if ! git diff --quiet -- package.json assets/mocks/; then
echo "❌ Generated files are out of sync with frameworks.json"
echo " Run generate_scripts.py and generate_mocks.py, then commit"
git diff -- package.json assets/mocks/
exit 1
fi
echo "✅ Config-derived files in sync"
docker-smoke:
name: 🐳 Docker Smoke Test
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.docker == 'true' || github.event_name == 'workflow_dispatch'
timeout-minutes: 20
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
- name: Build production image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
with:
context: .
target: production
load: true
tags: framework-benchmarks:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run container & check health
run: |
docker run -d --rm --name fb-smoke framework-benchmarks:ci
for _ in $(seq 1 30); do
if docker exec fb-smoke curl -fsS http://localhost:3000/health >/dev/null 2>&1; then
echo "✅ Container healthy"
docker stop fb-smoke
exit 0
fi
sleep 2
done
echo "❌ Container failed health check"
docker logs fb-smoke || true
docker stop fb-smoke || true
exit 1
secret-scan:
name: 🔑 Secret Scanning
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
persist-credentials: false
- name: Scan PR Diff for Secrets
uses: trufflesecurity/trufflehog@30d5bb91af1a771378349dbbb0c82129392acf70 # v3.95.6
with:
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --only-verified
# Renders markdown summary of all checks at the end
summary:
name: 📋 Summary
runs-on: ubuntu-latest
if: always()
continue-on-error: true
needs:
- dependency-audit
- workflow-audit
- smoke
- config-sync
- docker-smoke
- secret-scan
steps:
- name: Render Summary
env:
NEEDS: ${{ toJSON(needs) }}
run: |
label() {
case "$1" in
dependency-audit) echo "🔒 Dependency Audit" ;;
workflow-audit) echo "🛠️ Workflow Audit" ;;
smoke) echo "💨 Smoke Test" ;;
config-sync) echo "🧬 Config Sync" ;;
docker-smoke) echo "🐳 Docker Smoke Test" ;;
secret-scan) echo "🔑 Secret Scanning" ;;
*) echo "$1" ;;
esac
}
status() {
case "$1" in
success) echo "✅ Passed" ;;
skipped) echo "⏭️ Skipped" ;;
cancelled) echo "🚫 Cancelled" ;;
failure) echo "❌ Failed" ;;
*) echo "❔ $1" ;;
esac
}
{
echo "## CI Summary"
echo ""
echo "| Check | Status |"
echo "|-------|--------|"
} >> "$GITHUB_STEP_SUMMARY"
for job in $(echo "$NEEDS" | jq -r 'keys[]'); do
result=$(echo "$NEEDS" | jq -r --arg j "$job" '.[$j].result')
echo "| $(label "$job") | $(status "$result") |" >> "$GITHUB_STEP_SUMMARY"
done