CI / DevOps

Proof as a CI Check: What zk-ci.yml Actually Verifies on Every PR

"Proof as a CI check" is easy to say and easy to fake with a unit test that mocks the prover. Here's the actual workflow file, and why each step is there.

2026-09-01 · .github/workflows/zk-ci.yml

The gate only runs when it matters — its path filter is examples/**.zkasm, crates/**, contracts/**, or the workflow file itself, on every pull request and on every push to main. Two jobs run:

Job 1: build, test, then actually prove

cargo build --release --workspace
cargo test --release --workspace

So far that's a normal Rust CI job. The part that makes it "proof as a CI check" rather than "tests as a CI check" comes next: the workflow starts a real zkvm-host-server in the background, polls /healthz for up to 15 seconds, and only then runs this loop:

for f in examples/*.zkasm; do
  ./target/release/zkvm deploy "$f" --out "${f}.proof"
  ./target/release/zkvm verify "$f" "${f}.proof"
done

Every .zkasm file under examples/ — currently branching.zkasm, counter.zkasm, and fibonacci_like.zkasm — gets deployed to the live server and its returned proof verified, over a real HTTP round trip. If any one of them fails to prove or fails to verify, the job fails and the PR is blocked. Adding a new example program that doesn't verify is caught here, not by a human reviewer eyeballing a diff.

Job 2: forge test

cd contracts && forge test -vv

Runs independently, with contracts/lib/forge-std checked out as a git submodule. Currently 8 tests — see the Foundry testing post for what they actually check.

The healthcheck loop matters more than it looks: without it, the deploy step would race a server that hasn't finished binding its port yet, and an intermittent CI failure unrelated to the actual code would erode trust in the gate. curl -sf http://127.0.0.1:4477/healthz, retried every 0.5s for up to 30 attempts, before anything gets deployed.

What this gate does not catch: performance regressions (a program that used to prove in 2 seconds and now takes 20 still passes, as long as it eventually verifies), and anything about the on-chain path — scripts/onchain_demo.sh isn't wired into CI yet, so a break there would only surface by running it manually.

Related: what the Foundry test suite checks, and what's real vs. pitched across the rest of the project.