Skip to content

ci: crane-based Rust checks (clippy/doc/test) via nix flake check#1801

Merged
kixelated merged 5 commits into
mainfrom
claude/crane-ci-checks
Jun 19, 2026
Merged

ci: crane-based Rust checks (clippy/doc/test) via nix flake check#1801
kixelated merged 5 commits into
mainfrom
claude/crane-ci-checks

Conversation

@kixelated

@kixelated kixelated commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Why

The self-hosted A1 runner filled its 200G boot volume and CI started failing with No space left on device. Root cause: the heavy Rust CI (just rs cicargo clippy/doc/test --all-features) compiled into a persistent CARGO_TARGET_DIR ($HOME/cargo-target/moq-$RUNNER_NAME) that grew unbounded (every branch's artifacts, never pruned — 161G), was unsafe to share across parallel jobs, and lived outside the workspace so the per-job cleanup never touched it. Crane already built the release binaries, but the CI checks never went through it.

What

Move the heavy checks into crane, exposed via flake checks, and make nix flake check the thing that runs them:

  • clippy--all-targets --all-features -- -D warnings
  • doc--no-deps --all-features, RUSTDOCFLAGS=-D warnings
  • test--all-targets --all-features

Dependencies compile once (cargoArtifacts = buildDepsOnly), land in the Cachix binary cache, are shared across machines, and are LRU-evicted by the Nix store's free-space GC. Only first-party code recompiles, inside Nix's sandbox — no persistent target dir to bound.

Then (stage 2 in this PR):

  • just rs ci no longer repeats cargo clippy/doc/test (crane owns them); it keeps non-compiling hygiene (fmt/shear/sort), cargo-deny (needs network, can't run in the sandbox), and the default / no-default-feature cargo checks the all-features crane run doesn't cover.
  • check.yml drops the persistent CARGO_TARGET_DIR; residual cargo checks use the in-workspace ./target, which the runner wipes per job.
  • A self-hosted CI step asserts nothing wrote under $HOME/cargo-target, so a CARGO_TARGET_DIR override can't silently reintroduce an unbounded target dir.

Local just rs check (the fast cargo inner loop) is unchanged.

Verification

CI on the self-hosted aarch64-linux runner is authoritative (Linux-only features: alsa, libva, jemalloc). Confirmed green through iterations: the --all-features dep graph — including boring-sys/quiche — builds in the sandbox (needed git for BoringSSL patches), test fixtures (include_*! data) are kept in the check source, and the test suite passes inside the sandbox.

Notes

  • Companion to the runner disk fix (disk-guard timer + CARGO_INCREMENTAL=0, in the oci infra repo).
  • Dropping the persistent CARGO_TARGET_DIR also removes the hardcoded-./target wasm-recipe footgun that bit branch claude/merge-main-into-dev-992spq on the self-hosted runner.
  • Follow-up ideas: a single shared cargoArtifacts across packages+checks to cut redundant dep compiles; Nix-vendoring the other languages (Go buildGoModule, uv via uv2nix, bun via bun2nix) to extend the "sandbox-except-/nix" model beyond Rust.

kixelated and others added 3 commits June 19, 2026 10:07
The heavy Rust CI (clippy / doc / test, --all-features) ran as plain cargo
into a persistent CARGO_TARGET_DIR on the self-hosted runner. That dir grew
unbounded (every branch's artifacts, never pruned -- it filled a 200G boot
volume) and is unsafe to share across parallel jobs.

Express those checks as crane derivations instead, exposed via flake
`checks`. `just ci` already runs `nix flake check`, so these now build in
CI. Dependencies compile once (cargoArtifacts), land in the binary cache,
are shared across machines, and are LRU-evicted by the store's free-space
GC; only first-party code recompiles, inside Nix's sandbox -- no target dir
to bound.

Stage 1 (additive). Stage 2 removes the now-redundant cargo clippy/doc/test
from `just rs ci` and drops the persistent CARGO_TARGET_DIR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
crane concatenates checkCommonArgs.cargoExtraArgs (--workspace --all-features)
with each check's command-specific extra args, so repeating the scope there
produced 'cargo clippy --workspace ... --workspace ...' -> 'the argument
--workspace cannot be used multiple times'. Keep the shared scope only in
cargoExtraArgs; per-check args now carry just the command-specific flags
(--all-targets, -D warnings, --no-deps).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cleanCargoSource strips non-Rust files, but --all-targets compiles test
targets that include_str!/include_bytes! data fixtures (moq-mux test_data
*.ts, moq-json tests/vectors.json). clippy/doc/test failed with 'couldn't
read ...'. Take the whole tree minus heavy non-source dirs (node_modules,
target, .direnv, .venv, .git) so any fixture is present; dep caching is
unaffected (buildDepsOnly keys on Cargo.lock).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated marked this pull request as ready for review June 19, 2026 18:22
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@kixelated, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 8 minutes and 37 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 30392bd7-123c-4443-912f-ba480534dc63

📥 Commits

Reviewing files that changed from the base of the PR and between d17c90f and 50eb2e0.

📒 Files selected for processing (1)
  • .github/workflows/check.yml

Walkthrough

The PR integrates Nix-based CI checks for the Rust workspace with updated GitHub Actions configuration and a new local CI recipe. In nix/overlay.nix, a checkSrc source filter excludes non-source directories such as target and node_modules. A checkCommonArgs attribute set configures full workspace builds with --workspace --all-features, required native inputs, and Linux-only system libraries. A checkDeps derivation compiles third-party dependencies once via craneLib.buildDepsOnly. A moqChecks attribute set defines three derivations—cargoClippy, cargoDoc, and cargoTest—each reusing checkDeps. The overlay's returned attribute set inherits and exposes moqChecks. In flake.nix, the per-system outputs set checks = overlayPkgs.moqChecks. In rs/justfile, the ci recipe is rewritten to run formatting checks, cargo shear, cargo check with multiple configurations, and cargo deny. In .github/workflows/check.yml, GitHub-hosted caching is refined and self-hosted runners now record a baseline marker on $HOME/cargo-target, then assert no leaked writes occur after nix develop --command just ci completes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: moving Rust checks into crane-based derivations exposed via nix flake check. It is specific, clear, and directly reflects the primary objective of the PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset. It explains the root cause, solution, implementation details, and verification steps, all aligned with the actual file changes made.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/crane-ci-checks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

kixelated and others added 2 commits June 19, 2026 11:39
…stage 2)

The heavy Rust CI now runs as crane checks via `nix flake check` (stage 1), so
`just rs ci` no longer repeats cargo clippy/doc/test, and check.yml no longer
sets a persistent CARGO_TARGET_DIR. Residual `cargo check`s (default /
no-default feature combos crane's all-features run doesn't cover) compile into
the in-workspace ./target, which the runner wipes per job -- nothing grows on
$HOME anymore. Local `just rs check` is unchanged.

Add a self-hosted CI assertion that nothing wrote under $HOME/cargo-target, so a
CARGO_TARGET_DIR override can't silently reintroduce an unbounded target dir.
This also removes the hardcoded-./target wasm-recipe footgun on the runner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
$HOME/cargo-target is shared across repos (moq-pro) and both runners, so the
broad find flagged a concurrent moq-pro job's writes. Check only this repo's
old per-runner path (moq-$RUNNER_NAME) -- the dir our removed CARGO_TARGET_DIR
pointed at -- so a real leak is caught without false positives from neighbors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated merged commit 9cf11cc into main Jun 19, 2026
1 check passed
@kixelated kixelated deleted the claude/crane-ci-checks branch June 19, 2026 20:24
@kixelated kixelated mentioned this pull request Jun 19, 2026
4 tasks
kixelated added a commit that referenced this pull request Jun 20, 2026
Effectively reverts the crane apparatus from #1801 while keeping the
problem #1801 actually fixed: the heavy checks no longer compile into a
persistent CARGO_TARGET_DIR (which had grown unbounded to 161G and filled
the disk). Instead of crane's whole-deps blob, the runner caches cargo
compilation per-crate with sccache, so a Cargo.lock change recompiles
only the changed crate + its reverse-deps. ./target stays ephemeral
(wiped per job) -- no persistent target dir to bound.

The crane checks rebuilt the entire third-party graph on any Cargo.lock
change (e.g. adding serde_with = ~tens of minutes when the box is busy),
because buildDepsOnly is keyed on the whole lockfile.

- nix/overlay.nix: remove the crane check apparatus (moqChecks, checkDeps,
  checkCommonArgs, checkSrc).
- flake.nix: `checks = { }`. `nix flake check` still validates flake eval
  + dev shell, just without compiling the workspace.
- rs/justfile: run all-features clippy/doc/test + the feature-edge cargo
  checks here, as plain cargo.
- justfile: refresh the `nix flake check` gate comment.

sccache is wired into the runner environment (see the oci repo), not the
repo: jobs just run cargo, and the cache is invisible infra that benefits
every repo's Rust jobs. Release artifacts are unchanged -- still built via
crane buildPackage, hermetically (the sandbox scrubs the runner env).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated mentioned this pull request Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant