Skip to content

Commit 159c06e

Browse files
riccajasonclaude
andcommitted
ci: add Tier A GitHub Actions regression gate
What: New .github/workflows/ci.yml running the core regression gate on GitHub-hosted Linux runners: tri-arch release build, host --lib tests, clippy missing_safety_doc, and the pure-Python check-* baseline lints. Why: "Gated in CI" was true only locally (make check-all + the git hooks). This makes it literally true on a server: a reviewer cloning the repo sees a green workflow running exactly what the prose claims. Mirrors CLAUDE.md § Tri-Architecture Regression Discipline (ADR-013). Detail: - build (3-target matrix): cargo build --release for x86_64/aarch64/ riscv64 -unknown-none -- the make check-all payload, parallelized, fail-fast off so each arch reports independently. - test: cargo test --lib, retargeted to x86_64-unknown-linux-gnu (the Makefile's x86_64-apple-darwin only overrides .cargo/config.toml's bare-metal default; --lib tests are pure logic). RUST_MIN_STACK matches the Makefile. - clippy: cargo clippy --target x86_64-unknown-none --release --lib, enforcing [lints.clippy] missing_safety_doc = "deny". No -D warnings, so the gate is exactly the manifest deny. - lints: the six don't-grow-the-baseline gates, one step each. Toolchain + the three targets come from rust-toolchain.toml; Swatinem/rust-cache keeps repeat runs fast. Out of scope (documented in the workflow header): - Tier B (Kani, make verify-all) -- separate workflow, heavier setup. - Tier C (QEMU boot smoke) -- needs qemu + image tooling + seed signing. - The commit-msg/pre-commit/pre-push provenance hooks stay local; they enforce Claude-authored-commit provenance and have no meaning in CI. Verification: - 5/6 baseline lints confirmed green locally; check-deferrals greened by the preceding baseline resync. - No Rust source changed, so no tri-arch build run locally; the build + linux-gnu host-test retarget are confirmed by the first CI run (not reproducible on the Apple-Silicon host). Staged files: .github/workflows/ci.yml Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 64be2b0 commit 159c06e

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# SPDX-License-Identifier: AGPL-3.0-or-later
2+
# Copyright (C) 2024-2026 Jason Ricca
3+
4+
# CambiOS CI — Tier A: the core regression gate.
5+
#
6+
# Mirrors the local pre-commit discipline (CLAUDE.md § Tri-Architecture
7+
# Regression Discipline, ADR-013) on GitHub-hosted Linux runners:
8+
#
9+
# * tri-arch release build — `make check-all` (x86_64 + aarch64 + riscv64)
10+
# * host unit tests — `make test`, retargeted to the Linux host
11+
# * missing_safety_doc = "deny" — `cargo clippy --lib` (Dev Convention 1)
12+
# * don't-grow-the-baseline lints — the pure-Python check-* gates
13+
#
14+
# The pinned nightly and the three bare-metal targets come from
15+
# rust-toolchain.toml; rustup installs them automatically on first use. The
16+
# *-unknown-none targets are tier-2 with prebuilt core/alloc, so every build
17+
# here is a pure Rust cross-compile — no C toolchain, no build-std.
18+
#
19+
# NOT in scope (deliberately):
20+
# * Tier B — Kani proofs (`make verify-all`). Heavier setup (CBMC + a
21+
# bundled toolchain, worth caching); lands as a separate workflow.
22+
# * Tier C — QEMU boot smoke (`make run-quiet`). Needs qemu-system-* plus
23+
# ISO/FAT-image tooling and seed signing; deferred.
24+
# * The commit-msg / pre-commit / pre-push provenance hooks. They enforce
25+
# Claude-authored-commit provenance (CLAUDE_PREFLIGHT_SESSION, edit logs)
26+
# and are inherently local — meaningless in CI. This workflow is additive;
27+
# that discipline stays where it is.
28+
29+
name: CI
30+
31+
on:
32+
push:
33+
branches: [main]
34+
pull_request:
35+
workflow_dispatch:
36+
37+
permissions:
38+
contents: read
39+
40+
# Supersede in-flight runs for the same ref instead of stacking them.
41+
concurrency:
42+
group: ci-${{ github.ref }}
43+
cancel-in-progress: true
44+
45+
jobs:
46+
# ---------------------------------------------------------------------------
47+
# Tri-arch release build — the `make check-all` payload, one job per target
48+
# so the three cross-compiles run in parallel. fail-fast: false so a break on
49+
# one arch still reports the status of the other two.
50+
# ---------------------------------------------------------------------------
51+
build:
52+
name: build (${{ matrix.target }})
53+
runs-on: ubuntu-latest
54+
strategy:
55+
fail-fast: false
56+
matrix:
57+
target:
58+
- x86_64-unknown-none
59+
- aarch64-unknown-none
60+
- riscv64gc-unknown-none-elf
61+
steps:
62+
- uses: actions/checkout@v4
63+
- name: Install pinned toolchain + target (rust-toolchain.toml)
64+
run: |
65+
rustup show
66+
rustup target add ${{ matrix.target }}
67+
- uses: Swatinem/rust-cache@v2
68+
with:
69+
key: ${{ matrix.target }}
70+
- name: cargo build --release
71+
run: cargo build --target ${{ matrix.target }} --release
72+
73+
# ---------------------------------------------------------------------------
74+
# Host unit tests — `make test`, retargeted from x86_64-apple-darwin to the
75+
# runner's native triple. The darwin target in the Makefile exists only to
76+
# override .cargo/config.toml's bare-metal default; the --lib tests are pure
77+
# logic. RUST_MIN_STACK matches the Makefile (buddy-allocator deep recursion).
78+
# ---------------------------------------------------------------------------
79+
test:
80+
name: unit tests (--lib)
81+
runs-on: ubuntu-latest
82+
steps:
83+
- uses: actions/checkout@v4
84+
- name: Install pinned toolchain (rust-toolchain.toml)
85+
run: rustup show
86+
- uses: Swatinem/rust-cache@v2
87+
with:
88+
key: host-test
89+
- name: cargo test --lib
90+
env:
91+
RUST_MIN_STACK: "8388608"
92+
run: cargo test --lib --target x86_64-unknown-linux-gnu
93+
94+
# ---------------------------------------------------------------------------
95+
# clippy — enforces missing_safety_doc = "deny" (Cargo.toml [lints.clippy],
96+
# Dev Convention 1) on the x86_64 kernel lib. Mirrors CLAUDE.md's Quick
97+
# Reference invocation; no `-D warnings` so the gate is exactly the manifest
98+
# deny, not a flood of unrelated style lints.
99+
# ---------------------------------------------------------------------------
100+
clippy:
101+
name: clippy (missing_safety_doc)
102+
runs-on: ubuntu-latest
103+
steps:
104+
- uses: actions/checkout@v4
105+
- name: Install pinned toolchain + clippy
106+
run: |
107+
rustup show
108+
rustup component add clippy
109+
rustup target add x86_64-unknown-none
110+
- uses: Swatinem/rust-cache@v2
111+
with:
112+
key: clippy
113+
- name: cargo clippy --lib
114+
run: cargo clippy --target x86_64-unknown-none --release --lib
115+
116+
# ---------------------------------------------------------------------------
117+
# Don't-grow-the-baseline content lints — pure Python (CLAUDE.md Dev
118+
# Conventions 1/8/9, ADR-021). No Rust toolchain needed; ubuntu-latest ships
119+
# python3 + make. One step per gate so a reviewer sees exactly which is green.
120+
#
121+
# Commit-boundary / provenance gates are excluded on purpose: they read the
122+
# staged diff or session state and are no-ops or meaningless in CI —
123+
# check-index-isolation, check-lockfile (advisory), check-status-freshness
124+
# (advisory), claude-preflight.
125+
#
126+
# Note: check-adrs regenerates docs/adr/INDEX.md as a side effect (exit 0 when
127+
# cross-refs are valid). CI does not commit, so a stale committed INDEX.md is
128+
# not caught here — it fails only on broken/duplicate ADR references.
129+
# ---------------------------------------------------------------------------
130+
lints:
131+
name: baseline lints
132+
runs-on: ubuntu-latest
133+
steps:
134+
- uses: actions/checkout@v4
135+
- name: check-adrs (ADR cross-references)
136+
run: make check-adrs
137+
- name: check-assumptions (Convention 8 numeric bounds)
138+
run: make check-assumptions
139+
- name: check-deferrals (Convention 9 Revisit-when triggers)
140+
run: make check-deferrals
141+
- name: check-boot-panics (ADR-021 boot-init panics)
142+
run: make check-boot-panics
143+
- name: check-banned-paths (deleted-stays-deleted)
144+
run: make check-banned-paths
145+
- name: check-unsafe-coverage (Convention 1 SAFETY comments)
146+
run: make check-unsafe-coverage

0 commit comments

Comments
 (0)