-
Notifications
You must be signed in to change notification settings - Fork 8
288 lines (245 loc) · 11.7 KB
/
ci.yaml
File metadata and controls
288 lines (245 loc) · 11.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
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
name: CI
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
# ---------------------------------------------------------------------------
# Linux: compile + test KVM hypervisor backend (cfg(target_os = "linux"))
# ---------------------------------------------------------------------------
test-linux:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools
- uses: Swatinem/rust-cache@v2
# Try to enable KVM for integration tests. GitHub-hosted runners don't
# always expose nested virt -- when /dev/kvm is absent the udev trigger
# fails with "Failed to open the device 'kvm': Invalid argument". We
# let that pass and fall through to a compile-only/no-KVM run; the
# release pipeline owns real-KVM coverage. See sprints/done/ci-green.
- name: Enable KVM (best-effort)
continue-on-error: true
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Install tools
run: |
cargo install cargo-nextest --locked
cargo install cargo-llvm-cov --locked
# Library + service crate tests with coverage (capsem-core includes KVM backend on Linux).
# capsem-app (Tauri shell) and capsem-tray (macOS muda menu-bar) are macOS-only; every
# other host crate is portable and runs here so it gets Linux-specific regression coverage.
- name: Unit tests (KVM backend) with coverage
run: |
cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-linux.json --fail-under-lines 70 -p capsem-core -p capsem-admin -p capsem-agent -p capsem-debug-upstream -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-process
cargo llvm-cov report --no-cfg-coverage --summary-only -p capsem-core -p capsem-admin -p capsem-agent -p capsem-debug-upstream -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-process 2>&1 | tee coverage-summary-linux.txt
- name: Upload Linux coverage
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
files: codecov-linux.json
flags: linux-unit
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# Note KVM exercise status. Hosted ARM runners may lack /dev/kvm; the
# compile-only path still catches Linux build/lint regressions, and
# real-KVM coverage runs in the release pipeline. Surfacing as a
# warning (not an error) keeps CI honest about what was actually
# exercised without false-failing on a runner-fleet limitation.
- name: Note KVM exercise status
run: |
if [ -e /dev/kvm ]; then
echo "KVM is available at /dev/kvm -- KVM-backed tests exercised."
else
echo "::warning::/dev/kvm not available on this runner -- compile + non-KVM tests only. Real-KVM coverage runs in release pipeline."
fi
- name: Test summary
if: always()
run: |
KVM_STATUS="available"
[ -e /dev/kvm ] || KVM_STATUS="not available"
COV=$(grep 'TOTAL' coverage-summary-linux.txt 2>/dev/null | awk '{print $(NF)}' || echo "?")
cat >> "$GITHUB_STEP_SUMMARY" << EOF
## Linux Test Results
| Metric | Result |
|--------|--------|
| Runner | ubuntu-24.04-arm (aarch64) |
| /dev/kvm | $KVM_STATUS |
| Line coverage | $COV |
| KVM backend | compiled (real-KVM tests run only when /dev/kvm is present) |
EOF
# T5: preserve test artifacts on failure (Linux job).
- name: Upload test artifacts on failure (Linux)
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-artifacts-linux-${{ github.run_attempt }}
path: |
test-artifacts/
frontend/test-artifacts/
retention-days: 7
if-no-files-found: ignore
# ---------------------------------------------------------------------------
# macOS: full test suite (Apple VZ backend, frontend, Python, coverage)
# ---------------------------------------------------------------------------
test:
runs-on: macos-14
steps:
- uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-unknown-linux-musl,x86_64-unknown-linux-musl
components: llvm-tools
- uses: Swatinem/rust-cache@v2
- uses: pnpm/action-setup@v5
with:
version: 10
- uses: actions/setup-node@v5
with:
node-version: 24
cache: pnpm
cache-dependency-path: frontend/pnpm-lock.yaml
- run: cd frontend && pnpm install --frozen-lockfile
- uses: astral-sh/setup-uv@v5
- run: uv sync
- name: Dependency audit
run: |
cargo install cargo-audit --locked
cargo audit
cd frontend && pnpm audit
- name: Install tools
run: |
cargo install cargo-llvm-cov --locked
cargo install cargo-nextest --locked
# Unit tests: all crates with coverage + JUnit XML for test analytics.
# capsem-app (Tauri bin) is macOS-only; capsem-mcp-aggregator and
# capsem-mcp-builtin are thin binaries that pull capsem-core logic.
- name: Unit tests with coverage
run: |
cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-unit.json --fail-under-lines 70 -p capsem-core -p capsem-admin -p capsem-agent -p capsem-debug-upstream -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process
cargo llvm-cov report --no-cfg-coverage --summary-only -p capsem-core -p capsem-admin -p capsem-agent -p capsem-debug-upstream -p capsem-logger -p capsem-proto -p capsem-guard -p capsem-gateway -p capsem-service -p capsem -p capsem-tui -p capsem-mcp -p capsem-mcp-aggregator -p capsem-mcp-builtin -p capsem-tray -p capsem-app -p capsem-process 2>&1 | tee coverage-summary.txt
# Integration tests (tests/ directory, cross-crate)
- name: Integration tests with coverage
run: |
cargo llvm-cov nextest --no-cfg-coverage --profile ci --codecov --output-path codecov-integration.json -p capsem-core --test '*' || true
# Frontend tests with coverage + JUnit output
- name: Frontend type-check, test, and build
run: |
cd frontend
pnpm run check
npx vitest run --coverage --reporter=default --reporter=junit --outputFile=../frontend-junit.xml
pnpm run build
# Python schema tests with coverage
- name: Python lint and type check
run: |
uv run ruff check .
uv run ty check src/capsem
uv run capsem-builder validate-skills config/skills
- name: Python schema tests with coverage
run: uv run python -m pytest tests/ --cov=src/capsem --cov-report=xml:codecov-python.xml --cov-fail-under=90 --junitxml=python-junit.xml
# Python integration tests that need no VM
- name: Python integration tests (non-VM suites)
run: |
uv run python -m pytest tests/capsem-bootstrap/ tests/capsem-codesign/ tests/capsem-rootfs-artifacts/ -v --tb=short
# Verify all integration test suites import cleanly (catches broken imports/syntax)
- name: Verify all integration test imports
run: |
uv run python -m pytest tests/capsem-*/ --collect-only -q
# Schema drift check
- name: Schema drift check
run: |
uv run python scripts/generate_schema.py
git diff --exit-code config/settings-schema.json
# Upload coverage with flags
- name: Upload Rust unit test coverage
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
files: codecov-unit.json
flags: unit
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
- name: Upload Rust integration test coverage
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
files: codecov-integration.json
flags: integration
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
- name: Upload frontend coverage
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
files: coverage/frontend/coverage-final.json
flags: unit
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
- name: Upload Python coverage
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v5
with:
files: codecov-python.xml
flags: unit
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# Upload test results for test analytics
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
files: target/nextest/ci/junit.xml,frontend-junit.xml,python-junit.xml
token: ${{ secrets.CODECOV_TOKEN }}
# T5: preserve every test artifact (service.log / process.log /
# session.db etc.) on failure so PR reviewers can debug without
# rerunning. preserve_tmp_dir_on_failure() in tests/helpers/service.py
# populates `test-artifacts/` only on red runs; if-no-files-found
# is "ignore" so green runs don't bloat the workflow.
- name: Upload test artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-artifacts-${{ runner.os }}-${{ github.run_attempt }}
path: |
test-artifacts/
frontend/test-artifacts/
retention-days: 7
if-no-files-found: ignore
# Check-only (no link) -- actual cross-compile runs on Linux in release workflow
- name: Cross-compile check (guest binaries)
run: |
cargo check --release --target aarch64-unknown-linux-musl -p capsem-agent
cargo check --release --target x86_64-unknown-linux-musl -p capsem-agent
- name: Test summary
if: always()
run: |
COV=$(grep 'TOTAL' coverage-summary.txt 2>/dev/null | awk '{print $(NF)}' || echo "?")
cat >> "$GITHUB_STEP_SUMMARY" << EOF
## Test Results
| Metric | Result |
|--------|--------|
| Line coverage | $COV |
| Test results | See Codecov test analytics |
| Cross-compile | aarch64-unknown-linux-musl |
| Audit | cargo audit + pnpm audit |
> Coverage covers library crates + gateway (capsem-core, agent, logger, proto, gateway).
> Full workspace coverage runs in the release pipeline.
EOF
# ---------------------------------------------------------------------------
# Install e2e: Docker-based install layout + systemd tests (Linux)
# ---------------------------------------------------------------------------
test-install:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v5
- uses: extractions/setup-just@v3
- name: Build host builder Docker image
run: just build-host-image
- name: Run install e2e tests
run: just test-install