This document contains information for developers working on the Reaper project.
- Development Setup
- Building
- Testing
- Code Quality
- Git Hooks
- Docker (Optional)
- VS Code Setup
- CI/CD
- Coverage
- Contributing
- Rust toolchain (we pin
stableviarust-toolchain.toml) - Docker (optional, for Linux-specific testing on macOS)
- Ansible (for deploying to clusters)
git clone https://github.com/miguelgila/reaper
cd reaper
cargo buildThe repository includes rust-toolchain.toml which automatically pins the Rust toolchain version and enables rustfmt and clippy components.
cargo buildBinaries are output to target/debug/.
cargo build --releaseBinaries are output to target/release/.
For deployment to Kubernetes clusters, we build static musl binaries:
# Install musl target (one-time setup)
rustup target add x86_64-unknown-linux-musl
# Build static binary
docker run --rm \
-v "$(pwd)":/work \
-w /work \
messense/rust-musl-cross:x86_64-musl \
cargo build --release --target x86_64-unknown-linux-muslThis produces binaries at target/x86_64-unknown-linux-musl/release/ that work in containerized environments (like Kind nodes).
For aarch64:
rustup target add aarch64-unknown-linux-musl
docker run --rm \
-v "$(pwd)":/work \
-w /work \
messense/rust-musl-cross:aarch64-musl \
cargo build --release --target aarch64-unknown-linux-muslSee TESTING.md for comprehensive testing documentation.
# Unit tests (fast, recommended for local development)
cargo test
# Full integration tests (Kubernetes + unit tests)
./scripts/run-integration-tests.sh
# Integration tests (K8s only, skip cargo tests)
./scripts/run-integration-tests.sh --skip-cargo
# Coverage report (requires Docker)
./scripts/docker-coverage.shtests/integration_basic_binary.rs- Basic runtime functionality (create/start/state/delete)tests/integration_user_management.rs- User/group ID handling, umasktests/integration_shim.rs- Shim-specific teststests/integration_io.rs- FIFO stdout/stderr redirectiontests/integration_exec.rs- Exec into running containerstests/integration_overlay.rs- Overlay filesystem tests
Run a specific test suite:
cargo test --test integration_basic_binaryFormat all code before committing:
cargo fmt --allCheck formatting without making changes:
cargo fmt --all -- --checkRun clippy to catch common mistakes and improve code quality:
# Quick check
cargo clippy --all-targets --all-features
# Match CI exactly (treats warnings as errors)
cargo clippy -- -D warningsCI runs clippy with -D warnings, so any warning is a hard failure. The pre-push hook runs this automatically if you've installed hooks via ./scripts/install-hooks.sh.
The overlay module (src/bin/reaper-runtime/overlay.rs) is gated by #[cfg(target_os = "linux")] and doesn't compile on macOS. To catch compilation errors in Linux-only code:
# One-time setup
rustup target add x86_64-unknown-linux-gnu
# Check compilation for Linux target
cargo clippy --target x86_64-unknown-linux-gnu --all-targets --all-featuresWe provide git hooks in .githooks/ to catch issues before they reach CI.
./scripts/install-hooks.shThis sets core.hooksPath to .githooks/ and marks the hooks executable. Since the hooks are checked into the repo, every contributor gets the same setup.
| Hook | Runs | Purpose |
|---|---|---|
pre-commit |
cargo fmt --all |
Auto-formats code and stages changes before each commit |
pre-push |
cargo clippy -- -D warnings |
Catches lint issues before pushing (matches CI) |
The pre-push hook mirrors the exact clippy invocation used in CI, so pushes that pass locally will pass the CI clippy check too.
- pre-commit: To fail on unformatted code instead of auto-fixing, change
cargo fmt --alltocargo fmt --all -- --checkand remove the re-staging logic. - pre-push: To skip clippy for a one-off push, use
git push --no-verify.
Docker is not required for local development on macOS. Prefer cargo test locally for speed.
Use Docker when you need:
- Code coverage via
cargo-tarpaulin(Linux-first tool) - CI failure reproduction specific to Linux
- Static musl binary builds for Kubernetes
./scripts/docker-coverage.shThis runs cargo-tarpaulin in a Linux container with appropriate capabilities.
- rust-analyzer — Main Rust language support
- CodeLLDB (vadimcn.vscode-lldb) — Debug adapter for Rust
- Test Explorer UI — Unified test UI
Configure rust-analyzer to run clippy on save and enable CodeLens for inline run/debug buttons.
GitHub Actions workflows run on pushes and pull requests to main:
A single unified pipeline that runs:
cargo fmt -- --check(formatting)cargo clippy --workspace --all-targets -- -D warnings(linting)cargo audit(dependency vulnerability scan)cargo test --verbose(unit tests)cargo tarpaulin→ Codecov upload (coverage)- Cross-compile static musl binaries (all binaries)
- Kind integration tests (
run-integration-tests.sh --skip-cargo) - Example validation (
test-examples.sh --skip-cluster)
If running on Linux, you can use tarpaulin directly:
cargo install cargo-tarpaulin
cargo tarpaulin --out Xml --timeout 600Run the included Docker script:
./scripts/docker-coverage.shConfiguration lives in tarpaulin.toml. Functions requiring root + Linux namespaces (tested by kind-integration) are excluded via #[cfg(not(tarpaulin_include))] so coverage reflects what unit tests can actually reach.
-
Format code:
cargo fmt --all
-
Run linting:
cargo clippy --all-targets --all-features
-
Run tests:
cargo test -
Optional: Run integration tests:
./scripts/run-integration-tests.sh
-
Install git hooks (auto-formats on commit, runs clippy before push):
./scripts/install-hooks.sh
For fast feedback during development:
# Quick iteration cycle
cargo test # Unit tests (seconds)
cargo clippy # Linting
# Before pushing
cargo fmt --all # Format code
cargo test # All unit tests
./scripts/run-integration-tests.sh # Full validationIf you're iterating on overlay or shim logic:
# First run (build cluster, binaries, tests)
./scripts/run-integration-tests.sh --no-cleanup
# Make code changes...
# Rebuild and test (skip cargo, reuse cluster)
cargo build --release --bin containerd-shim-reaper-v2 --bin reaper-runtime
./scripts/run-integration-tests.sh --skip-cargo --no-cleanup
# Repeat until satisfied...
# Final cleanup run
./scripts/run-integration-tests.sh --skip-cargoreaper/
├── src/
│ ├── bin/
│ │ ├── containerd-shim-reaper-v2/ # Shim binary
│ │ │ └── main.rs # Shim implementation
│ │ └── reaper-runtime/ # Runtime binary
│ │ ├── main.rs # OCI runtime CLI
│ │ ├── state.rs # State persistence
│ │ └── overlay.rs # Overlay filesystem (Linux)
├── tests/ # Integration tests
├── scripts/ # Installation and testing scripts
├── deploy/
│ ├── ansible/ # Ansible playbooks for deployment
│ └── kubernetes/ # Kubernetes manifests
├── docs/ # Documentation
└── .githooks/ # Git hooks (pre-commit, pre-push)
- Create directory under
src/bin/<binary-name>/ - Add
main.rsin that directory - Add entry to
Cargo.toml:[[bin]] name = "binary-name" path = "src/bin/binary-name/main.rs"
- Create
tests/integration_<name>.rs - Use
#[test]or#[tokio::test]for async tests - Run with
cargo test --test integration_<name>
# Check for outdated dependencies
cargo outdated
# Update to latest compatible versions
cargo update
# Update Cargo.lock and check tests still pass
cargo testUse VS Code's debug launch configurations or run with logging:
RUST_LOG=debug cargo test <test-name> -- --nocaptureRun clippy with Linux target:
cargo clippy --target x86_64-unknown-linux-gnu --all-targetsSome tests require root for namespace operations. Run:
sudo cargo testOr use integration tests which run in Kind (isolated environment):
./scripts/run-integration-tests.shEnsure Docker is running:
docker psIf Docker daemon is not accessible, start Docker Desktop or the Docker daemon.
Increase timeout or check cluster resources:
kubectl get nodes
kubectl describe pod <pod-name>