Developing locally
roci uses just as its task runner. Every recipe mirrors a CI gate, so passing locally means passing the required CI checks.
Prerequisites
- Rust via
rustup— the pinned toolchain inrust-toolchain.tomlinstalls automatically on the firstcargoinvocation. just— the task runner.cargo-nextest— test runner used by CI.cargo-deny— supply-chain gate.cargo-llvm-cov— coverage gate (rustup component add llvm-tools-previewtoo).- Go 1.17+ — only for the OCI conformance suite.
actionlintandzizmor— only for linting/auditing the GitHub Actions workflows.helm— only for chart linting (just helm-lint).
Install the cargo tools in one line:
cargo install just cargo-nextest cargo-deny cargo-llvm-covFirst-time setup
Fetch the pinned OCI spec submodules:
git submodule update --init --depth 1 # or: just initInstall the git pre-commit hook (when Rust sources are staged it runs fmt, clippy, the 95% coverage floor, and the full OCI conformance suite; it also runs workflow lint/security when workflows are staged, and refreshes COVERAGE.md + the badge on every commit):
just hooks # or, with the pre-commit framework: pre-commit installTasks
| Command | What it does |
|---|---|
just | List all recipes |
just init | Fetch pinned spec submodules |
just fmt / just fmt-fix | Check / apply formatting |
just clippy | Lint both build flavors, warnings = errors |
just test | Run tests (nextest) + doctests |
just build | Build minimal and full flavors |
just deps-guard | Assert no extension crate leaks into the minimal build |
just lint-workflows | Lint the GitHub Actions workflows (actionlint) |
just zizmor | Security-audit the workflows (zizmor) |
just audit | cargo deny supply-chain check |
just coverage | Enforce the 95% line-coverage floor (cargo-llvm-cov) |
just coverage-report | Show uncovered lines (developer aid) |
just ci | Run the full local gate before pushing (includes helm-lint) |
just conformance | Run the OCI dist-spec conformance suite against a local roci |
just container | Build the hardened scratch image and smoke-test it |
just container-multiarch | Build the multi-arch image (linux/amd64, linux/arm64) |
just bench | Benchmark roci vs distribution vs zot in pinned containers (quick smoke / full 5-rep) — see docs/guide/benchmarks.md |
just bench-perf | Profile roci (flamegraphs, syscalls, per-route latency, gaps vs a prior just bench run) |
just helm-lint | Lint the Helm chart and assert its render-time security guards (needs helm) |
CI parity
just ci runs the same checks GitHub Actions requires — if it passes locally, the required CI checks pass. Run just ci before pushing or opening a PR.
Coverage gate
A 95% line-coverage floor is enforced. CI compiles the workspace once (instrumented) and runs tests under cargo llvm-cov nextest, then scripts/coverage.sh asserts the lcov line coverage stays at or above 95% and prints the uncovered lines for triage. New code should ship with tests for the behavior it adds; the handful of lines that remain uncovered are unreachable-in-CI defensive syscall-error arms in the beneath-root storage path. Inspect gaps with just coverage-report.
The gate runs on the Linux CI runner, which is authoritative: cargo llvm-cov's line attribution differs on macOS/APFS (it collapses some error/skip arms), so a local just coverage number is indicative only — reproduce the Linux figure with just coverage-linux before pushing coverage-sensitive work.
Security & static analysis
Beyond the required gate, CI runs three security/static-analysis workflows: actionlint (workflow linting, part of the CI workflow), zizmor (GitHub Actions security audit), and codeql (CodeQL SAST for Rust). When editing any workflow, keep it actionlint- and zizmor-clean: pin third-party actions by commit SHA, set persist-credentials: false on checkout, and avoid over-broad token permissions.