Skip to content
Merged
12 changes: 10 additions & 2 deletions .github/actions/core-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ description: >
proofs behind non-default features (e.g. networking-proxy, networking-wg)
are NOT run here — invoke those explicitly in the calling workflow.

inputs:
shared-key:
description: rust-cache shared-key, forwarded to setup-rust.
required: false
default: tests

runs:
using: composite
steps:
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
shared-key: ${{ inputs.shared-key }}
- name: Install nextest
uses: taiki-e/install-action@v2
with:
Expand All @@ -21,7 +29,7 @@ runs:
shell: bash
# --no-tests=fail: an empty selection is a broken filter or a dropped
# target, not a pass.
run: cargo nextest run --workspace --profile ci --no-tests=fail
run: cargo nextest run --workspace --locked --profile ci --no-tests=fail
- name: Run doctests
shell: bash
run: cargo test --workspace --doc
run: cargo test --workspace --doc --locked
31 changes: 29 additions & 2 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
name: Setup Rust
description: >
Common Rust CI preamble for GitHub-hosted Ubuntu runners: free disk space,
install protoc, and restore the cargo registry/build cache. Assumes the
repository is already checked out.
install protoc, slim CI debug info, and restore the cargo registry/build
cache. Assumes the repository is already checked out.

inputs:
shared-key:
description: >
rust-cache shared-key. One key per job CLASS that compiles the same
artifacts (same packages, features, profile); jobs that compile
differently must not share a key, or they thrash each other's cache.
required: false
default: workspace
save-if:
description: >
Whether this job may WRITE the cache. Defaults to main only: PR
branches restore but never save, so PR churn cannot LRU-evict the
main-branch caches every PR wants to restore from.
required: false
default: ${{ github.ref == 'refs/heads/main' }}

runs:
using: composite
Expand All @@ -17,5 +33,16 @@ runs:
- name: Install protoc
shell: bash
run: sudo sh -c 'apt-get update && apt-get install -y protobuf-compiler'
- name: Slim debug info for CI builds
# line-tables-only keeps usable backtraces while shrinking target/ (and
# every cache built from it) and speeding linking. An env var rather
# than a named Cargo profile: a profile would move output to
# target/<name>/ and break every hardcoded target/debug path (codesign
# steps, testbeds, PATH exports, justfile).
shell: bash
run: echo "CARGO_PROFILE_DEV_DEBUG=line-tables-only" >> "$GITHUB_ENV"
- name: Cache cargo registry and build artifacts
uses: Swatinem/rust-cache@v2
with:
shared-key: ${{ inputs.shared-key }}
save-if: ${{ inputs.save-if }}
29 changes: 25 additions & 4 deletions .github/workflows/ci-linux-kvm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ jobs:
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.kvm == 'true'
runs-on: ubuntu-latest
timeout-minutes: 45
env:
# Slim debug info (usable backtraces, smaller caches, faster links);
# this job doesn't run the setup-rust composite that sets this on the
# other Linux lanes.
CARGO_PROFILE_DEV_DEBUG: line-tables-only
steps:
- name: Free Disk Space
# The workspace build + libkrun prefix routinely exceed the ~14 GB
Expand Down Expand Up @@ -116,7 +121,9 @@ jobs:
tool: cross,nextest

- name: Cache cargo + build artifacts
uses: actions/cache@v6
# Restore-only; the save half (main only) runs at the end of the job.
id: cargo-cache
uses: actions/cache/restore@v6
with:
path: |
~/.cargo/bin/
Expand All @@ -141,15 +148,15 @@ jobs:
run: ./scripts/build-initramfs.sh "$RUNNER_TEMP/initramfs.cpio" x86_64-unknown-linux-musl

- name: Build minvmd
run: cargo build -p minvmd --bin minvmd
run: cargo build -p minvmd --bin minvmd --locked

- name: Build the minimal CLI
# SEPARATE invocation from the minvmd build: a combined `cargo build
# -p minvmd -p minimal` unifies minvmd's default `libkrun` feature
# into the CLI's default-features=false opt-out, linking libkrun into
# `minimal` (the regression the macOS lane hit and now guards). The
# CLI drives the unified session e2e in the test job.
run: cargo build -p minimal --bin minimal
run: cargo build -p minimal --bin minimal --locked

- name: Archive e2e harnesses + stage the testbed
# `cargo nextest archive` replaces the hand-rolled testbins.json
Expand All @@ -162,7 +169,7 @@ jobs:
run: |
set -euo pipefail
mkdir -p testbed
cargo nextest archive -p minvmd --archive-file testbed/nextest-archive.tar.zst
cargo nextest archive -p minvmd --locked --archive-file testbed/nextest-archive.tar.zst
cp target/debug/minvmd testbed/minvmd
cp target/debug/minimal testbed/minimal
cp "$RUNNER_TEMP/initramfs.cpio" testbed/initramfs.cpio
Expand All @@ -177,6 +184,20 @@ jobs:
if-no-files-found: error
retention-days: 3

- name: Save cargo + build artifacts cache (main only)
# PR branches restore but never write: multi-GB caches written by
# every branch LRU-evict the main entries all PRs restore from.
if: github.ref == 'refs/heads/main' && steps.cargo-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ steps.cargo-cache.outputs.cache-primary-key }}

test-kvm:
# TEST phase: no Rust toolchain, no cargo build — download the testbed,
# pull the guest images, and run the archived harnesses with the
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ci-linux-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ jobs:
with:
persist-credentials: false
- uses: ./.github/actions/setup-rust
with:
# `-p` builds unify features differently than the workspace test
# suite — own cache class.
shared-key: native-e2e
- name: Enable unprivileged user namespaces
# The session sandbox (hakoniwa) needs userns; Ubuntu 24.04 restricts
# them via AppArmor by default.
Expand All @@ -122,7 +126,7 @@ jobs:
key: native-e2e-minimal-cache-${{ hashFiles('.minimal/minimal.toml') }}
restore-keys: native-e2e-minimal-cache-
- name: Build minimal + minimald
run: cargo build -p minimald --bin minimald -p minimal --bin minimal
run: cargo build -p minimald --bin minimald -p minimal --bin minimal --locked
- name: Session e2e (native minimald)
run: |
export PATH="$PWD/target/debug:$PATH"
Expand Down
46 changes: 38 additions & 8 deletions .github/workflows/ci-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ jobs:
- name: Cache cargo + build artifacts (incl. the aarch64 cross target)
# Raw actions/cache (not Swatinem) — it preserves the full
# target/aarch64-unknown-linux-musl tree, so the initramfs cross-compile
# is incremental after the first run.
uses: actions/cache@v6
# is incremental after the first run. Restore-only here; the save
# half (main only) runs at the end of the job.
id: stage2-cache
uses: actions/cache/restore@v6
with:
path: |
~/.cargo/bin/
Expand Down Expand Up @@ -133,6 +135,19 @@ jobs:
name: minimald-initramfs-aarch64
path: ${{ runner.temp }}/initramfs.cpio
if-no-files-found: error
- name: Save cargo + build artifacts cache (main only)
# PR branches restore but never write: multi-GB caches written by
# every branch LRU-evict the main entries all PRs restore from.
if: github.ref == 'refs/heads/main' && steps.stage2-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ steps.stage2-cache.outputs.cache-primary-key }}

e2e:
# Hypervisor E2E on real hardware, using the cache-pulled kernel + rootfs
Expand All @@ -158,6 +173,10 @@ jobs:
needs: [artifacts]
runs-on: [self-hosted, macOS, ARM64]
timeout-minutes: 30
env:
# Slim debug info; see the unit job. First run after this change
# rebuilds the mini's persistent target dir once (new fingerprints).
CARGO_PROFILE_DEV_DEBUG: line-tables-only
steps:
- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -191,16 +210,16 @@ jobs:
# package bins for integration tests) and bakes its absolute
# CARGO_BIN_EXE path — same-machine build+run, so it resolves.
run: |
cargo test -p minvmd --test krun_smoke --test minimald_session_e2e --no-run
cargo build -p minvmd --bin minvmd
cargo test -p minvmd --test krun_smoke --test minimald_session_e2e --no-run --locked
cargo build -p minvmd --bin minvmd --locked
# SEPARATE invocation for the CLI (mirrors release.yml): built
# together, cargo unifies minvmd's default `libkrun` feature
# into minimal's default-features=false opt-out, and the CLI
# links libkrun. The brew era masked this (absolute install
# name loaded from anywhere); our @rpath dylib turns it into
# dyld "Library not loaded" at autospawn, since minimal bakes
# no rpaths.
cargo build -p minimal --bin minimal
cargo build -p minimal --bin minimal --locked
- name: Verify minimal links only system libraries
# The CLI spawns minvmd as a subprocess and calls no libkrun; a
# krun load command means the feature unification above regressed.
Expand Down Expand Up @@ -318,6 +337,11 @@ jobs:
# mac-buildable. Kept lean (private repo: macOS minutes bill at 10x).
runs-on: macos-latest
timeout-minutes: 45
env:
# Slim debug info (usable backtraces, smaller caches, faster
# links); the mac jobs don't run the setup-rust composite that
# sets this on the Linux lanes.
CARGO_PROFILE_DEV_DEBUG: line-tables-only
steps:
- uses: actions/checkout@v7
with:
Expand All @@ -328,12 +352,18 @@ jobs:
components: clippy
- name: Cache cargo registry and build artifacts
uses: Swatinem/rust-cache@v2
with:
shared-key: mac-unit
# PR branches restore but never save, so PR churn cannot
# LRU-evict the main-branch caches (same policy as the
# setup-rust composite).
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Provision libkrun (pinned own build)
uses: ./.github/actions/setup-libkrun-macos
- name: Clippy (minvmd)
run: cargo clippy -p minvmd --all-targets -- -D warnings
run: cargo clippy -p minvmd --all-targets --locked -- -D warnings
- name: Test (minvmd)
run: cargo test -p minvmd
run: cargo test -p minvmd --locked
- name: Test (sessions)
# Platform-sensitive surface: std::fs::canonicalize behavior on
# prefix-symlinked roots (/tmp → /private/tmp on macOS) and the
Expand All @@ -345,4 +375,4 @@ jobs:
# (`cargo build -p minimal` is fine: no dev-deps.) The CLI's macOS
# coverage stays the autospawn e2e until minimald's sandbox deps
# are cfg(linux)-gated.
run: cargo test -p sessions
run: cargo test -p sessions --locked
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ jobs:
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/setup-rust
with:
# check artifacts, not build artifacts — own cache class
shared-key: clippy
- name: Run Clippy
run: cargo clippy --workspace --all-targets -- -D warnings
run: cargo clippy --workspace --all-targets --locked -- -D warnings

test:
runs-on: ubuntu-latest
Expand All @@ -57,14 +60,14 @@ jobs:
# feature, so the core-tests `--workspace` run does not compile or run
# its proofs (R4.5 mtls_missing_cert_returns_401_with_no_topology, UC2b
# mtls_valid_cert_routes_to_backend). Exercise them explicitly.
run: cargo nextest run -p minimald --features networking-proxy
run: cargo nextest run -p minimald --features networking-proxy --locked
- name: Run WireGuard mesh tests
# The WireGuard mesh peer is behind the non-default `networking-wg`
# feature, so the core-tests `--workspace` run does not compile or run
# its proofs. Exercise them explicitly (R-WG:
# two_meshes_handshake_and_relay_a_packet, rpc get_mesh_status). The
# `#[ignore]` two-namespace mesh_uc7 proof runs in the netns lane.
run: cargo test -p minimald --features networking-wg
run: cargo test -p minimald --features networking-wg --locked

dogfood:
runs-on: ubuntu-latest
Expand Down
Loading