-
Notifications
You must be signed in to change notification settings - Fork 7
282 lines (227 loc) · 8.31 KB
/
Copy pathci.yml
File metadata and controls
282 lines (227 loc) · 8.31 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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
name: CI
on:
pull_request:
push:
branches:
- main
- master
- dev
jobs:
repository-hygiene:
name: Repository Hygiene
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Verify tracked generated files
run: |
matches=$(git ls-files | grep -E '(^|/)dist/|(^|/)\.env$|(^|/)\.env\.(local|development|production|test)$' || true)
if [ -n "$matches" ]; then
echo "Tracked generated or environment files detected:"
echo "$matches"
exit 1
fi
echo "Repository hygiene checks passed."
api-contract:
name: API Contract Drift
needs: repository-hygiene
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: apps/frontend/package-lock.json
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip
- name: Install frontend dependencies
run: npm ci --prefix apps/frontend
- name: Install backend dependencies
run: |
python -m pip install -r apps/backend/requirements-dev.txt
python -m pip install -e apps/backend --no-deps
- name: Check generated frontend API contract
run: npm --prefix apps/frontend run generate:api-contract -- --check
frontend:
name: Frontend
needs: repository-hygiene
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: apps/frontend/package-lock.json
- name: Install dependencies
run: npm ci --prefix apps/frontend
# Policy-aware, so a green build represents a reviewed dependency-risk
# posture rather than the absence of `npm audit`. Runtime exposure is
# gated harder than development-only exposure, and every exception needs
# a written reason and a review date that expires.
- name: Dependency audit policy tests
run: node --test scripts/dependency-audit.test.mjs
- name: Dependency audit
run: node scripts/dependency-audit.mjs
- name: Lint
run: npm --prefix apps/frontend run lint
- name: Test
run: npm --prefix apps/frontend run test
- name: Build
run: npm --prefix apps/frontend run build
backend:
name: Backend
needs: repository-hygiene
runs-on: ubuntu-latest
# Postgres validates the full migration round trip against the deployment
# dialect and lets the gated refresh-token concurrency test exercise its
# row-lock race. Redis lets the gated rate-limit tests exercise the real
# atomic script and TTL behaviour. Local runs retain SQLite and in-memory
# fallbacks where supported.
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: partha
POSTGRES_PASSWORD: partha
POSTGRES_DB: partha_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U partha -d partha_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip
- name: Upgrade pip
run: python -m pip install --upgrade pip
- name: Install dependencies
run: |
python -m pip install -r apps/backend/requirements-dev.txt
python -m pip install -e apps/backend --no-deps
- name: Static analysis
working-directory: apps/backend
run: |
ruff check app
ruff format --check app
mypy app
- name: Validate capability registry and README
run: python scripts/check-capabilities.py
- name: Test
working-directory: apps/backend
env:
PARTHA_TEST_PG_URL: postgresql+psycopg://partha:partha@localhost:5432/partha_test
PARTHA_TEST_REDIS_URL: redis://localhost:6379/0
run: python -m pytest
# The pytest step above validates every benchmark invariant (including the
# failure paths). This step is the human-facing regression report and CI
# artifact: it runs the real benchmark command, writes Markdown + JSON to a
# temporary (never committed) directory, adds a summary to the job page, and
# its exit status is captured so the reports upload even on failure. A later
# step re-raises that status so a below-threshold benchmark fails the job.
- name: Run Repository Intelligence golden benchmark
id: ri_benchmark
working-directory: apps/backend
run: |
mkdir -p "$RUNNER_TEMP/ri-benchmark"
set +e
python tests/benchmark/run.py --report-dir "$RUNNER_TEMP/ri-benchmark"
echo "status=$?" >> "$GITHUB_OUTPUT"
- name: Validate benchmark report contract
if: always() && steps.ri_benchmark.outcome != 'skipped'
run: |
python - <<'PY'
import json
import os
from pathlib import Path
report_path = Path(os.environ["RUNNER_TEMP"]) / "ri-benchmark" / "benchmark.json"
report = json.loads(report_path.read_text(encoding="utf-8"))
scoring = report.get("scoring", {})
if scoring.get("status") != "scored":
raise SystemExit("benchmark did not publish real precision/recall measurements")
if scoring.get("realExtractorProvenance") is None:
raise SystemExit("benchmark did not publish real-extractor citation validity")
rendered = json.dumps(report).lower()
if "deferred" in rendered or "unavailable" in rendered:
raise SystemExit("benchmark report contains a skipped live measurement")
PY
- name: Upload benchmark reports
if: always() && steps.ri_benchmark.outcome != 'skipped'
uses: actions/upload-artifact@v4
with:
name: ri-golden-benchmark
path: ${{ runner.temp }}/ri-benchmark
if-no-files-found: error
- name: Enforce benchmark gate
if: always() && steps.ri_benchmark.outcome != 'skipped'
run: |
if [ "${{ steps.ri_benchmark.outputs.status }}" != "0" ]; then
echo "Repository Intelligence golden benchmark failed (exit ${{ steps.ri_benchmark.outputs.status }})."
exit 1
fi
echo "Repository Intelligence golden benchmark passed."
prototype-acceptance:
name: Prototype Browser Acceptance
needs:
- frontend
- backend
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: apps/frontend/package-lock.json
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip
- name: Install frontend
run: npm ci --prefix apps/frontend
- name: Install backend
run: |
python -m pip install -r apps/backend/requirements-dev.txt
python -m pip install -e apps/backend --no-deps
- name: Install Chromium
run: npm --prefix apps/frontend exec -- playwright install --with-deps chromium
- name: Run disposable-fixture browser journeys
run: node scripts/run-prototype-acceptance.mjs
- name: Upload browser report
if: always()
uses: actions/upload-artifact@v4
with:
name: prototype-browser-acceptance
path: |
apps/frontend/e2e-report
apps/frontend/test-results
if-no-files-found: warn
retention-days: 14