OXYGENHUB
60d848f2…4c717b54
Code

The URL alone: https://oxygenhub.io/andymccall/oxygenflow

For tools that only speak Git. Push with oxy: the mirror refuses pushes.

Download ZIP

60d848f2474b21bb61c6761bce2ab4898e9cbd737a302ac6236d8a7a4c717b54 as it is now, without its history. Also as .tar.zst.

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.

Deploying the runner on Earth

make deploy-runner builds flow and the static flow-init, installs them under /home/claude/flow (keeping the previous files as .prev), re-pins flow-init in flow.toml and restarts the flow-runner service.

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:

  1. Build flow with cargo 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.
  2. 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.155 from Firecracker's CI bucket.
  3. Run flow rootfs import alpine-minirootfs-3.24.2-x86_64.tar.gz --sha256 ….
  4. Write flow.toml, pinning each file by its flow 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.