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.
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.
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.