Skip to content

CI

Four jobs on every push to main and every pull request, defined in .github/workflows/ci.yml. Zig is pinned to 0.16.0.

Terminal window
zig fmt --check build.zig src tests examples

Formatting is not a review topic.

Runs on ubuntu-latest, macos-latest, and windows-latest, with fail-fast: false so one platform failing still reports the others.

Terminal window
zig build test --summary all
zig build example-01 # and 02, 03, 04
zig build

zig build test also builds every example, so a stale one fails here. The examples are then run, because building proves they compile and running proves they work.

Path handling and the atomic write differ per platform, so the CLI is exercised end to end rather than trusted to unit tests:

Terminal window
zpack pack examples/example-assets ci.zpak
zpack list ci.zpak
zpack verify ci.zpak
zpack unpack ci.zpak ci-out
zpack manifest ci.zpak > /dev/null
zpack ids ci.zpak > /dev/null
diff -r examples/example-assets ci-out

That diff -r is the round-trip guarantee, checked on three operating systems every time.

The most interesting job. A damaged archive must fail cleanly - a non-zero exit with a named error, never a crash. Three kinds of damage are manufactured and fed to verify:

Damage How Must produce
A flipped byte mid-data dd one byte to 0xff, or 0x00 if it was already 0xff HashMismatch
Truncation head -c $((size - 64)) CorruptArchive
Not an archive at all printf 'NOTZPAK' BadMagic

Each is checked three ways: the exit status must be non-zero, the output must not contain panic, and the corruption itself must not have been a no-op - cmp confirms the flipped file actually differs before the test means anything.

That last check is the sort of thing that keeps a test honest. A byte flip that silently did nothing would produce a passing test that proves nothing.

Cross-compiles every release target on every PR:

x86_64-linux-musl aarch64-linux-musl
x86_64-macos aarch64-macos
x86_64-windows aarch64-windows
Terminal window
zig build -Dtarget=$TARGET -Doptimize=ReleaseSafe -Dstrip

Building all six on every change means a portability break surfaces on the change that caused it, rather than at tag time when someone is trying to ship.

Builds this site:

Terminal window
cd docs
bun install --frozen-lockfile
bun run build

The build runs starlight-links-validator, so a link to a page that was renamed or never written fails the check rather than shipping as a 404.

Benchmarks. There is no performance regression suite.

Fuzzing. The corruption job manufactures three specific kinds of damage, not random mutation. A fuzzing harness over Archive.open would be a genuinely useful contribution.

Large archives. Everything runs against the small examples/example-assets tree. Behaviour past 4 GB, or past maxInt(u32) entries, is bounded by code review rather than by test.

Tagging runs a separate workflow with its own gate - see releasing.