Skip to content

docs(skills): ship the a3s-box agent skill + cross-tool installer (#157) #571

docs(skills): ship the a3s-box agent skill + cross-tool installer (#157)

docs(skills): ship the a3s-box agent skill + cross-tool installer (#157) #571

Workflow file for this run

name: CI
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
workflow_dispatch: {}
env:
CARGO_TERM_COLOR: always
A3S_DEPS_STUB: "1"
jobs:
# ── Lint & Format ──────────────────────────────────────────────
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cd src && cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Create stub libkrun
run: |
echo "void krun_stub(void) {}" > /tmp/krun_stub.c
gcc -shared -o /tmp/libkrun.so /tmp/krun_stub.c
sudo cp /tmp/libkrun.so /usr/lib/
sudo ldconfig
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
- run: cd src && cargo clippy --workspace --all-targets -- -D warnings
# ── Tests (stub mode, no VM) ───────────────────────────────────
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Create stub libkrun
run: |
echo "void krun_stub(void) {}" > /tmp/krun_stub.c
gcc -shared -o /tmp/libkrun.so /tmp/krun_stub.c
sudo cp /tmp/libkrun.so /usr/lib/
sudo ldconfig
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
- run: cd src && cargo test --workspace --lib
# ── Build check (compile only, no artifacts) ────────────────────
build-check:
name: Build Check (${{ matrix.target }})
needs: [fmt, clippy, test]
strategy:
matrix:
include:
- target: linux-x86_64
os: ubuntu-latest
- target: linux-arm64
os: ubuntu-24.04-arm
- target: macos-arm64
os: macos-14
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential pkg-config libssl-dev \
musl-tools libclang-dev protobuf-compiler
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install lld llvm protobuf
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
key: ${{ matrix.target }}
- name: Check compilation
run: |
cd src
cargo check --release -p a3s-box-cli -p a3s-box-shim
if [ "${{ runner.os }}" = "Linux" ]; then
cargo check --release -p a3s-box-cri
fi
# ── Windows native WHPX build check ────────────────────────────
build-windows:
name: Build Windows WHPX
needs: [fmt, clippy, test]
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
key: windows-whpx
- name: Build Windows native binaries
run: |
Remove-Item Env:A3S_DEPS_STUB -ErrorAction SilentlyContinue
cd src
cargo build --release -p a3s-box-cli -p a3s-box-shim --target x86_64-pc-windows-msvc
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: windows-whpx
path: |
src/target/x86_64-pc-windows-msvc/release/a3s-box.exe
src/target/x86_64-pc-windows-msvc/release/a3s-box-shim.exe
# ── Real microVM integration gate (self-hosted, /dev/kvm) ───────
# The fmt/clippy/test/build jobs above all run in STUB mode
# (A3S_DEPS_STUB) and never boot a real microVM, so a runtime
# regression (boot, exec, virtio-fs, CRI lifecycle, snapshot-fork)
# cannot be caught by hosted CI — GitHub-hosted runners have no
# /dev/kvm. This job links REAL libkrun and runs the `#[ignore]`
# integration + crictl-smoke suites against a real microVM.
#
# ARMING THE GATE (one-time, operator — see docs/ci-kvm-runner.md):
# 1. Register a self-hosted runner that has /dev/kvm, with labels:
# self-hosted, linux, kvm
# 2. Set repository variable KVM_CI = true
# (Settings -> Secrets and variables -> Actions -> Variables)
# Until both are done this job is SKIPPED (inert) and never blocks a PR.
integration-kvm:
name: Integration (real microVM, KVM)
needs: [fmt, clippy, test]
if: vars.KVM_CI == 'true'
runs-on: [self-hosted, linux, kvm]
timeout-minutes: 75
# The runner has no direct docker.io egress (CN network), so the smoke
# tests pull alpine/busybox through a mirror. The image keeps its canonical
# docker.io identity; only the fetch is redirected. Override per-runner with
# the KVM_CI_REGISTRY_MIRRORS repo variable.
env:
A3S_REGISTRY_MIRRORS: ${{ vars.KVM_CI_REGISTRY_MIRRORS || 'docker.io=docker.m.daocloud.io' }}
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
# The self-hosted runner already has a working rustup/cargo. Using
# dtolnay/rust-toolchain forces rustup to re-sync the whole `stable`
# channel (7 components) on every run — ~20 min on this box's network,
# which blew the job timeout. Use the runner's existing toolchain: add the
# musl target (a fast no-op if already installed) and put cargo on PATH
# for later steps (the runner service env does not source a login shell).
- name: Use the runner's existing Rust toolchain
run: |
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
"$HOME/.cargo/bin/rustup" target add x86_64-unknown-linux-musl
# NOTE: no Swatinem/rust-cache here — fetching that action from
# codeload.github.com times out on this runner's network, which fails
# "Set up job". The self-hosted runner keeps a warm cargo registry, and
# the 75-min budget covers a cold libkrun build.
- name: Verify /dev/kvm is present
run: |
if [ ! -e /dev/kvm ]; then
echo "::error::/dev/kvm missing — this runner cannot boot microVMs"; exit 1
fi
echo "/dev/kvm present"
# Build REAL binaries: unset the stub so libkrun-sys compiles the
# vendored libkrun (build.rs gates on env::var("A3S_DEPS_STUB").is_ok(),
# so the var must be UNSET, not just emptied).
- name: Build real binaries + musl guest-init (no stub)
run: |
unset A3S_DEPS_STUB
cd src
cargo build --release -p a3s-box-guest-init --target x86_64-unknown-linux-musl
cargo build --release -p a3s-box-cli -p a3s-box-cri -p a3s-box-shim
- name: Core smoke — real boot + exec over virtio-fs
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-cli --test core_smoke -- --ignored --nocapture --test-threads=1
- name: CRI crictl smoke — full pod/container lifecycle
env:
A3S_BOX_CRI_SMOKE: "1"
A3S_BOX_CRI_SMOKE_AGENT_IMAGE: ${{ vars.KVM_CI_AGENT_IMAGE || 'docker.m.daocloud.io/library/alpine:latest' }}
# A3S_REGISTRY_MIRRORS inherited from the job env (covers docker.io).
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-cri --test crictl_smoke -- --ignored --nocapture --test-threads=1
# Gate leak-freeness under churn against REAL VMs: create/run/remove cycles
# must return orphan shims / overlay mounts / box dirs to baseline. Exits
# non-zero on a leak, so a resource-leak regression fails the gate.
- name: Leak assertion — no orphan shims/mounts/box-dirs after churn
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
CHURN: "20"
run: |
unset A3S_DEPS_STUB
chmod +x bench/bench.sh
bench/bench.sh leak
# Gate the cross-process advisory lock on boxes.json against REAL VMs:
# concurrent `run -d` processes must NOT lose each other's state writes.
# The unit tests only race in-process threads, so a broken/missing flock
# across separate a3s-box processes is invisible to them — this boots a
# fleet at once and asserts no lost update + intact JSON. Exits non-zero
# on a lost update, failing the gate.
- name: Race assertion — no lost update on boxes.json under concurrent run -d
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
RACE: "8"
run: |
unset A3S_DEPS_STUB
chmod +x bench/bench.sh
bench/bench.sh race