OXYGENHUB
# a4b3f8cb9aae oxygenflow / images / rust / README.md
2.3 KiB · Markdown · last changed Build image for Rust and Node jobs (images/rust: toolchain, rustfmt, clippy, Node 24, vendored crates, offline cargo); flow-init finds the program in the job's PATH (glibc's execvpe used PID 1's own); network "loopback" in M0 1 month ago renderedsource blame history raw

The OxygenFlow build image

A root file system for Rust and Node jobs:

  • Rust 1.97.1 with rustfmt and clippy.
  • Node 24.21.0, checked against its published SHA-256.
  • git, make and pkg-config.
  • Every crate that oxygen, oxygenhub and oxygenflow use, vendored in /opt/vendor.

OxygenFlow jobs have no network (network "isolated"). So cargo is pointed at the vendored crates by /.cargo/config.toml, which cargo reads for any directory under /, including /src. CARGO_HOME stays at its default, $HOME/.cargo, which is under /tmp and writable. The toolchain's binaries are linked into /usr/local/bin, because the guest's PATH is fixed and nothing at run time needs rustup.

Building and importing

images/rust/build.sh /path/to/oxygenflow-build.tar
scp /path/to/oxygenflow-build.tar claude@earth:/home/claude/flow/dl/
ssh claude@earth 'cd ~/flow && FLOW_HOME=~/flow bin/flow rootfs import dl/oxygenflow-build.tar'

build.sh vendors the crates of the three workspaces next to this repository with cargo vendor --locked, then builds the image. Docker is used only on the machine that builds it, as a way to assemble a file system: the image is exported as a plain tarball. On the runner, flow rootfs import makes an ext4 image pinned by BLAKE3, which Firecracker boots read-only.

Rebuild and re-import whenever a Cargo.lock of those projects changes, then pin the new hash in the pipelines that use the image. A crate missing from the image fails the job with cargo's "no matching package" error, not with a network error.

Using it

sandbox "rust" {
    runtime "microvm"
    rootfs "cas://blob/<hash printed by flow rootfs import>"
    memory-limit "8GiB"
    cpu-limit 4
    network "loopback"   // tests that serve on 127.0.0.1 need it; nothing leaves the guest
}

job "test" {
    sandbox "rust"
    mount {
        source "ephemeral://disk"
        target "/src/target"
        size "24GiB"
    }
    env {
        CARGO_INCREMENTAL "0"
    }
    exec "cargo" "test" "--workspace"
}

Measured on Earth (4 cores, the job given all of them and 8 GiB): oxygen's cargo fmt --check, clippy -D warnings and cargo test --workspace from a cold build take 135 s.

The build tree goes on an ephemeral://disk mount. The workspace itself has only 512 MiB to spare, and a tmpfs would take the build tree out of the job's memory.