mirror of
https://github.com/vhaudiquet/ecrou.git
synced 2026-11-12 22:22:44 +00:00
CI runs fmt/clippy/test plus a real alpine boot on a macos-26 runner with libkrun from the krun tap; the release workflow ships a signed darwin-arm64 tarball beside the snaps. The formula installs from the tap, carries the runtime kegs (libkrun, e2fsprogs, libarchive), and codesigns the binary with the hypervisor entitlement — Hypervisor .framework grants VM creation only to entitled binaries on current macOS, the same requirement krunkit's formula signs for.
209 lines
7.1 KiB
YAML
209 lines
7.1 KiB
YAML
name: ci
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
jobs:
|
|
test:
|
|
name: fmt, clippy, test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
components: clippy, rustfmt
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
|
|
# Same order as the pre-commit list in AGENTS.md.
|
|
- name: cargo fmt
|
|
run: cargo fmt --all -- --check
|
|
|
|
- name: cargo clippy
|
|
run: cargo clippy --all-targets -- -D warnings
|
|
|
|
- name: cargo test
|
|
run: cargo test
|
|
|
|
macos:
|
|
name: macos — fmt, clippy, test, boot
|
|
runs-on: macos-26
|
|
timeout-minutes: 45
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
components: clippy, rustfmt
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
|
|
# The engine is dlopen'd from the brew kegs at runtime; e2fsprogs
|
|
# supplies mke2fs and libarchive its tar path.
|
|
- name: Install the engine and the image tooling
|
|
run: brew install libkrun/homebrew-krun/libkrun e2fsprogs libarchive
|
|
|
|
- name: cargo fmt
|
|
run: cargo fmt --all -- --check
|
|
|
|
- name: cargo clippy
|
|
run: cargo clippy --all-targets -- -D warnings
|
|
|
|
- name: cargo test
|
|
run: cargo test
|
|
|
|
- name: Build the CLI
|
|
run: cargo build --release -p ecrou-cli
|
|
|
|
# HVF grants VM creation only to binaries carrying the hypervisor
|
|
# entitlement on current macOS; packaging signs the same way.
|
|
- name: Sign the binary with the hypervisor entitlement
|
|
run: codesign --force --sign - --entitlements packaging/macos/ecrou.entitlements target/release/ecrou
|
|
|
|
- name: Probe
|
|
run: ./target/release/ecrou probe
|
|
|
|
- name: Boot alpine
|
|
run: |
|
|
set -euo pipefail
|
|
guest="$(./target/release/ecrou run --quiet alpine -- uname -r | tail -n 1)"
|
|
echo "guest kernel: $guest"
|
|
test -n "$guest"
|
|
|
|
t6:
|
|
name: T6 strace audit
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
|
|
- name: Install strace and the image tooling
|
|
run: |
|
|
sudo apt-get update -qq
|
|
# mke2fs populates from a tarball through a runtime dlopen of
|
|
# libarchive; the runner has e2fsprogs but not the lib.
|
|
sudo apt-get install -y -qq strace libarchive13t64 \
|
|
|| sudo apt-get install -y -qq strace libarchive13
|
|
|
|
# The runner exposes nested KVM; the runner user needs rw on the
|
|
# device node for the probe to pass.
|
|
- name: Open /dev/kvm
|
|
run: |
|
|
test -c /dev/kvm || { echo "::error::no /dev/kvm on this runner"; exit 1; }
|
|
test -w /dev/kvm || sudo chmod 666 /dev/kvm
|
|
|
|
# The engine is dlopen'd at runtime: build libkrun from the same
|
|
# tag the snap bundles, and take libkrunfw from the pool the way
|
|
# the snap's libkrunfw part does.
|
|
- name: Build the engine
|
|
run: |
|
|
curl -fsSL -o /tmp/libkrunfw5.deb \
|
|
https://archive.ubuntu.com/ubuntu/pool/universe/libk/libkrunfw/libkrunfw5_5.5.0+ds-1_amd64.deb
|
|
echo "924cd545080aaf5da66740d12a51b7a5cbd9a5c0b502d21cbef9bc82bf1c8b6b /tmp/libkrunfw5.deb" | sha256sum -c
|
|
dpkg -x /tmp/libkrunfw5.deb /tmp/libkrunfw
|
|
git clone --depth 1 --branch v1.19.7 https://github.com/containers/libkrun /tmp/libkrun
|
|
cargo build --release --manifest-path /tmp/libkrun/Cargo.toml -p libkrun --features net,blk
|
|
mkdir /tmp/engine
|
|
cp /tmp/libkrun/target/release/libkrun.so /tmp/engine/libkrun.so.1
|
|
cp /tmp/libkrunfw/usr/lib/x86_64-linux-gnu/libkrunfw.so.5.5.0 /tmp/engine/
|
|
ln -s libkrunfw.so.5.5.0 /tmp/engine/libkrunfw.so.5
|
|
|
|
- name: Build the CLI
|
|
run: cargo build --release -p ecrou-cli
|
|
|
|
- name: T6 — no denied syscalls in the host process tree
|
|
env:
|
|
ECROU_BIN: ${{ github.workspace }}/target/release/ecrou
|
|
LD_LIBRARY_PATH: /tmp/engine
|
|
run: cargo test -p ecrou-cli -- --ignored
|
|
|
|
snap:
|
|
name: snap build
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# The same pack the release workflow publishes. Building it on
|
|
# every change keeps the snap from rotting between tags: the
|
|
# cargo part, the libkrun build, and the libkrunfw digest pins
|
|
# all break here first.
|
|
- uses: snapcore/action-build@v1
|
|
id: build
|
|
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: snap-amd64
|
|
path: ${{ steps.build.outputs.snap }}
|
|
|
|
e2e:
|
|
name: snap e2e — apt install
|
|
needs: snap
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: snap-amd64
|
|
path: snap
|
|
|
|
- name: Install the snap
|
|
run: |
|
|
test -c /dev/kvm || { echo "::error::no /dev/kvm on this runner"; exit 1; }
|
|
test -w /dev/kvm || sudo chmod 666 /dev/kvm
|
|
sudo snap install --dangerous ./snap/*.snap
|
|
sudo snap connect ecrou:kvm
|
|
|
|
# Diagnostics for whatever fails below: KVM state, the engine
|
|
# load from the snap's staged libraries, the cache directory.
|
|
- name: Probe
|
|
run: ecrou probe || true
|
|
|
|
# T8's first half, on the packaged binary: a guest kernel that
|
|
# differs from the host's, inside strict confinement. Fast, so a
|
|
# broken environment fails here instead of deep in the apt run.
|
|
- name: Smoke — boot alpine under confinement
|
|
run: |
|
|
set -euo pipefail
|
|
guest="$(timeout 10m ecrou run --quiet alpine -- uname -r | tail -n 1)"
|
|
host="$(uname -r)"
|
|
echo "guest kernel: $guest / host kernel: $host"
|
|
test -n "$guest" && test "$guest" != "$host"
|
|
|
|
# T8's second half: a real package install end to end — apt
|
|
# through the TSI proxy, mkfs and debugfs through the snap's
|
|
# staged e2fsprogs, the payload's exit code back through the
|
|
# control file. The ln driver's known throughput limit makes
|
|
# this the long pole; how long it takes is the standing
|
|
# re-measurement the Networking section calls for on every
|
|
# engine update.
|
|
- name: apt update && install fastfetch
|
|
run: |
|
|
set -euo pipefail
|
|
# --pipe --logo none: the payload's stdout is a serial
|
|
# console, which fastfetch reads as a tty and decorates with
|
|
# cursor escapes (a first local run grepped nothing); plain
|
|
# output keeps the receipt readable.
|
|
timeout 35m ecrou run --quiet -e DEBIAN_FRONTEND=noninteractive ubuntu -- \
|
|
"apt update && apt install -y fastfetch && fastfetch --pipe --logo none" \
|
|
| tee /tmp/e2e.log
|
|
# Insurance, not the primary check: strip any escape
|
|
# sequences before anchoring on the fastfetch key.
|
|
sed -e 's/\x1b\[[0-9;?]*[A-Za-z]//g' /tmp/e2e.log | grep -E "^OS:"
|