README.md
OxygenFlow
Hermetic pipelines for Oxygen repositories:
- a typed pipeline in
.flow/pipeline.kdl - jobs run in isolation tiers, Firecracker microVMs by default
- the host writes the receipts
- results go to OxygenHub as checks and appear on its Flow tab
The specification is docs/spec.md. What works today is docs/m0.md.
A pipeline
schema-version 1
sandbox "alpine" {
runtime "microvm"
rootfs "cas://blob/…" // printed by `flow rootfs import`
memory-limit "256MiB"
network "isolated"
}
job "build" {
sandbox "alpine"
exec "make"
}
job "test" {
sandbox "alpine"
depends-on "build"
exec "sh" "-eu" "test.sh" // argv, run as written: no shell unless you name one
}
Each job boots its own microVM:
- it has no network device
- the rootfs is read-only
- the workspace is the state being built, read-write at
/src - the job runs as a user that is not root
This repository's own pipeline is .flow/pipeline.kdl.
Commands
flow check # validate .flow/pipeline.kdl, print jobs and the pipeline hash
flow run [JOB…] # run the pipeline on this directory, locally, in microVMs
flow rootfs import T.tgz --sha256 HEX # make a rootfs image; prints the `rootfs` line to pin
flow rootfs list
flow hash FILE # BLAKE3, for pinning in flow.toml
flow runner # claim and run jobs for the hub in flow.toml
A Flow home
$FLOW_HOME (default ~/.local/share/flow) holds:
flow.toml- the pinned Firecracker binary, guest kernel and
flow-init - rootfs images under
cas/ - scratch space
Every pinned file is checked against its BLAKE3 before use.
[microvm]
firecracker = { path = "bin/firecracker", blake3 = "…" }
kernel = { path = "kernel/vmlinux", blake3 = "…" }
init = { path = "bin/flow-init", blake3 = "…" }
[runner] # only for `flow runner`
hub = "https://hub.example:7343"
token = "…" # listed in the hub's [flow] runner_tokens
ca = "/path/to/hub-ca.pem" # when the hub's certificate is self-signed
name = "runner-1"
Setting one up needs Linux x86-64 with KVM and e2fsprogs 1.43 or later:
- Build
flowwithcargo build --release -p flow. Build the guest init as a static binary:RUSTFLAGS="-C target-feature=+crt-static" cargo build --release -p flow-init --target x86_64-unknown-linux-gnu. - Download Firecracker v1.17.0 from its GitHub release, and check the
published SHA-256. Download the guest kernel
firecracker-ci/v1.15/x86_64/vmlinux-6.1.155from Firecracker's CI bucket. - Run
flow rootfs import alpine-minirootfs-3.24.2-x86_64.tar.gz --sha256 …. - Write
flow.toml, pinning each file by itsflow hash.
On OxygenHub, hub.toml lists the runner token and the repositories whose
pushes run pipelines:
[flow]
runner_tokens = ["…"]
repos = ["owner/*"]
Tests
cargo test --workspace runs every test that needs no VM. The microVM
conformance test also runs when FLOW_TEST_HOME names a Flow home and
FLOW_TEST_ROOTFS is the hash of an Alpine rootfs in it. The test checks
literal argv, network isolation, the read-only rootfs, and that dependents
are skipped after a failure.