-
Notifications
You must be signed in to change notification settings - Fork 2
464 lines (408 loc) · 16.6 KB
/
Copy pathtests.yml
File metadata and controls
464 lines (408 loc) · 16.6 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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
name: tests
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
workflow_dispatch:
permissions:
contents: read
jobs:
python-lint:
name: Python lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install ruff
run: python -m pip install ruff==0.13.0
- name: Run ruff check on new hardening tests
run: |
python -m ruff check \
python/vibap/drp.py \
python/vibap/drp_conformance.py \
python/vibap/drp_fixture.py \
python/vibap/policy_conformance.py \
python/vibap/receipt_telemetry.py \
python/tests/test_drp_conformance.py \
python/tests/test_policy_conformance.py \
python/tests/test_drp.py \
python/tests/test_proxy.py \
python/tests/test_receipt_telemetry.py \
python/tests/test_examples_governance_integration.py \
scripts/generate-drp-implementation-fixtures.py \
scripts/generate-policy-conformance-fixtures.py
go-lint:
name: Go lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# Must match the `go` directive in go/go.mod (currently 1.26.5).
go-version: '1.26.5'
cache: true
cache-dependency-path: go/go.sum
- name: Install golangci-lint with Go 1.26
working-directory: go
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.5.0
- name: Run golangci-lint on hardening packages
working-directory: go
run: '"$(go env GOPATH)/bin/golangci-lint" run ./pkg/credential ./pkg/policy'
python:
name: Python
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
- name: Install ardur with dev extras
working-directory: python
run: |
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
- name: Run public DRP implementation fixtures
working-directory: python
run: |
python -m vibap.drp_conformance \
--bundle ../docs/specs/conformance/drp-v0.1/bundle.json \
--output "${{ runner.temp }}/ardur-drp-fixture-report.json"
- name: Run public agentic-policy conformance fixtures
working-directory: python
run: |
python -m vibap.policy_conformance \
--bundle ../docs/specs/conformance/policy-v0.1/bundle.json \
--output "${{ runner.temp }}/ardur-policy-conformance-report.json"
- name: Run pytest with coverage
working-directory: python
timeout-minutes: 15
env:
PYTHONFAULTHANDLER: "1"
COVERAGE_FILE: ${{ runner.temp }}/ardur-coverage
run: python -m pytest tests/ -q --tb=short --durations=20 --cov=vibap --cov-report=term --cov-report=xml:${{ runner.temp }}/ardur-coverage-report.xml
- name: Require pytest to leave the checkout clean
run: |
worktree_status="$(git status --porcelain --untracked-files=all)"
if [ -n "$worktree_status" ]; then
printf '%s\n' "$worktree_status"
exit 1
fi
- name: Show coverage summary
working-directory: python
env:
COVERAGE_FILE: ${{ runner.temp }}/ardur-coverage
run: |
python -m coverage report --fail-under=0
echo "::notice:: Aspirational targets: vibap=80%%, cli=60%%, integrations=70%%"
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-coverage-${{ matrix.python-version }}
path: ${{ runner.temp }}/ardur-coverage-report.xml
if-no-files-found: warn
retention-days: 14
- name: Upload DRP implementation fixture report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: drp-implementation-fixtures-${{ matrix.python-version }}
path: ${{ runner.temp }}/ardur-drp-fixture-report.json
if-no-files-found: error
retention-days: 14
- name: Upload agentic-policy conformance report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: policy-conformance-${{ matrix.python-version }}
path: ${{ runner.temp }}/ardur-policy-conformance-report.json
if-no-files-found: error
retention-days: 14
go:
name: Go
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# Must match the `go` directive in go/go.mod (currently 1.26.5).
# If you bump go.mod, bump this string in the same PR.
go-version: '1.26.5'
cache: true
cache-dependency-path: go/go.sum
- name: Run go test
working-directory: go
run: go test -count=1 ./...
- name: Run maintained agent-recognition corpus gate
working-directory: go
shell: bash
run: go run ./cmd/ardur-agent-recognition-eval | tee "${{ runner.temp }}/agent-recognition-report.json"
- name: Run go vet
working-directory: go
run: go vet ./...
- name: Cross-compile Windows portability targets
working-directory: go
env:
GOOS: windows
GOARCH: amd64
CGO_ENABLED: "0"
run: |
go test -c -o "${{ runner.temp }}/kernelcapture-windows.test.exe" ./pkg/kernelcapture
go test -c -o "${{ runner.temp }}/kernelcaptured-windows.test.exe" ./cmd/ardur-kernelcaptured
go test -c -o "${{ runner.temp }}/recognition-benchmark-windows.test.exe" ./cmd/ardur-agent-recognition-benchmark
- name: Upload agent-recognition corpus report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: agent-recognition-report
path: ${{ runner.temp }}/agent-recognition-report.json
if-no-files-found: error
retention-days: 14
go-cve:
name: Go CVE scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# Must match the `go` directive in go/go.mod (currently 1.26.5).
go-version: '1.26.5'
cache: true
cache-dependency-path: go/go.sum
- name: Install govulncheck
# Pin to v1.1.4; @latest (v1.4.0) panics on generics via x/tools@v0.46.0.
run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
- name: Run govulncheck
working-directory: go
run: govulncheck ./...
rwt-phase1:
name: "RWT Phase 1 (fresh-user)"
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Run RWT Phase 1
run: python scripts/run-rwt-phase1-fresh-user.py --allow-dirty
examples-smoke:
name: "Examples smoke"
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install ardur
working-directory: python
run: python -m pip install -e '.[dev,langgraph]'
- name: Run governance integration tests (demo code paths)
working-directory: python
run: python -m pytest tests/test_examples_governance_integration.py tests/test_examples_smoke.py -v --tb=short
demo-smoke:
name: "Demo stack smoke"
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
env:
COMPOSE_PROJECT_NAME: ardur-ci-${{ github.run_id }}-${{ github.run_attempt }}
ARDUR_SPIRE_SERVER_PORT: "18081"
ARDUR_PROXY_PORT: "18443"
ARDUR_HUB_PORT: "18765"
ARDUR_API_TOKEN: ci-demo-token
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Start the full demo stack and wait for health
run: make demo DEMO_UP_ARGS="--detach --wait --wait-timeout 240"
- name: Verify health, PERMIT, DENY, and signed attestation
run: ./scripts/verify-mvp.sh
- name: Show demo status and logs on failure
if: failure()
run: |
docker compose ps --all
docker compose logs --no-color
- name: Remove demo containers and volumes
if: always()
run: make demo-down
latency-bench:
name: "Latency benchmarks (informational)"
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
continue-on-error: true
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install ardur
working-directory: python
run: python -m pip install -e '.[dev]'
- name: Run latency benchmarks
working-directory: python
env:
ARDUR_RUN_LATENCY_BENCH: "1"
run: python -m pytest tests/test_claude_code_hook_latency.py -v -s
# Deterministic latency gate (ADR-027, issue #380). Surfaces a
# ``pass`` / ``fail`` / ``inconclusive`` verdict over the reports the
# benchmark just wrote. ``if: always()`` so the signal is produced
# even when the benchmark step partially fails, and
# ``continue-on-error: true`` so a gate FAIL or INCONCLUSIVE never
# blocks the build (the ``latency-bench`` job is informational at
# this stage). The evaluator is read-only over the report directory;
# exit codes are 0=PASS, 1=FAIL, 2=INCONCLUSIVE. Reports live under
# ``$RUNNER_TEMP/ardur-latency-reports`` (``default_report_dir`` on
# GitHub Actions), the same directory uploaded as an artifact below.
- name: Evaluate latency gate
if: always()
working-directory: python
continue-on-error: true
run: |
python -m vibap.cli latency-gate evaluate \
--reports ${{ runner.temp }}/ardur-latency-reports/ \
--format json
- name: Upload latency benchmark reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: latency-benchmark-reports
path: ${{ runner.temp }}/ardur-latency-reports/
if-no-files-found: error
retention-days: 14
e2e-showcase:
name: "E2E Showcase (real Ollama)"
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
# Decision (issue #375): this job stays informational and is NOT added to
# the blocking ``tests`` aggregate below. It requires live cloud
# credentials (ARDUR_OLLAMA_API_KEY secret + ARDUR_OLLAMA_CLOUD_MODEL var)
# that are not available on every PR, so making it required would gate
# unrelated contributions on a credentialled showcase. Instead, the
# fail-closed logic below makes the job honest about its own skip state:
# when the showcase job DOES have credentials configured, it must either
# run the model-gated tests or fail loudly -- it may not silently skip
# them and report green. ``continue-on-error`` is retained so an
# informational red on a credentialled run does not block the release
# train, but the signal is now trustworthy rather than a false green.
continue-on-error: true
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Install ardur with dev + ollama extras
working-directory: python
run: python -m pip install -e '.[dev,ollama]'
# Preflight (issue #375): verify the ollama client imports and that the
# API key + cloud model are present BEFORE running pytest. The check
# prints only booleans / redacted presence indicators -- never the API
# key value. Exits non-zero on any missing prerequisite so the job fails
# loudly at this step rather than skipping silently inside pytest.
- name: Ollama showcase preflight
working-directory: python
env:
ARDUR_OLLAMA_API_KEY: ${{ secrets.ARDUR_OLLAMA_API_KEY }}
ARDUR_OLLAMA_CLOUD_MODEL: ${{ vars.ARDUR_OLLAMA_CLOUD_MODEL }}
run: |
python - <<'PY'
import os
import sys
api_key = os.environ.get("ARDUR_OLLAMA_API_KEY", "")
cloud_model = os.environ.get("ARDUR_OLLAMA_CLOUD_MODEL", "")
print(f"ARDUR_OLLAMA_API_KEY present: {bool(api_key)}")
print(f"ARDUR_OLLAMA_CLOUD_MODEL present: {bool(cloud_model)}")
try:
import ollama # noqa: F401
print("ollama client import: ok")
client_ok = True
except ImportError as exc:
print(f"ollama client import: FAILED ({type(exc).__name__})")
client_ok = False
missing = []
if not api_key:
missing.append("ARDUR_OLLAMA_API_KEY")
if not cloud_model:
missing.append("ARDUR_OLLAMA_CLOUD_MODEL")
if not client_ok:
missing.append("ollama client import")
if missing:
print(f"::error::Ollama showcase preflight missing: {', '.join(missing)}")
sys.exit(1)
PY
- name: Run E2E showcase
working-directory: python
env:
ARDUR_OLLAMA_API_KEY: ${{ secrets.ARDUR_OLLAMA_API_KEY }}
ARDUR_OLLAMA_CLOUD_MODEL: ${{ vars.ARDUR_OLLAMA_CLOUD_MODEL }}
# Fail closed: if preflight passed but pytest still skips an
# ollama_required test, convert that skip into a collection error.
ARDUR_OLLAMA_FAIL_CLOSED: "1"
run: python -m pytest tests/test_e2e_showcase.py -v -s --tb=short
tests:
name: tests
if: ${{ always() }}
needs:
- python-lint
- go-lint
- python
- go
- go-cve
- rwt-phase1
- examples-smoke
- demo-smoke
runs-on: ubuntu-latest
steps:
- name: Require every blocking test job
env:
PYTHON_LINT: ${{ needs['python-lint'].result }}
GO_LINT: ${{ needs['go-lint'].result }}
PYTHON: ${{ needs.python.result }}
GO: ${{ needs.go.result }}
GO_CVE: ${{ needs['go-cve'].result }}
RWT_PHASE1: ${{ needs['rwt-phase1'].result }}
EXAMPLES_SMOKE: ${{ needs['examples-smoke'].result }}
DEMO_SMOKE: ${{ needs['demo-smoke'].result }}
run: |
set -euo pipefail
require_success() {
local job="$1"
local result="$2"
if [ "$result" != "success" ]; then
echo "::error::Required job $job concluded $result"
exit 1
fi
}
require_success python-lint "$PYTHON_LINT"
require_success go-lint "$GO_LINT"
require_success python "$PYTHON"
require_success go "$GO"
require_success go-cve "$GO_CVE"
require_success rwt-phase1 "$RWT_PHASE1"
require_success examples-smoke "$EXAMPLES_SMOKE"
require_success demo-smoke "$DEMO_SMOKE"