Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Phase 409 — build onix-busybox.stone

ItemValue
Commandmake phase 409
Underlying make target/scriptvm/phase4/build-busybox-stone.sh
Recipe templatevm/phase4/stone-recipes/onix-busybox/stone.yaml.in
Mutates disk/image?No
Boots QEMU?No
Main proofONIX can build BusyBox from source into a local .stone, verify it with moss, and add it to the local Phase 4 moss repo.

Why this phase exists

Phase 407 found a real architecture problem:

the current booting image still contains Nix-sourced system payloads

That was okay for getting a first boot, but it is not the final ONIX model.

The ONIX rule is:

machine-plane software = moss/.stone
user toolbox software  = Nix

BusyBox is machine-plane software.

It provides commands the operating system needs before a user has installed any personal toolbox:

/usr/bin/sh
/usr/bin/ls
/usr/bin/mount
/usr/bin/ifconfig
/usr/bin/nc
/usr/bin/ps

So BusyBox must become a .stone package.

Phase 409 builds that first replacement package.

What BusyBox is

BusyBox is one executable that behaves like many small Unix commands.

For example:

/usr/bin/busybox

can act as:

sh
ls
cat
mount
ip
ifconfig
nc
ps

The usual trick is symlinks:

/usr/bin/sh  -> busybox
/usr/bin/ls  -> busybox
/usr/bin/cat -> busybox

When the same binary is launched as /usr/bin/sh, it runs the shell applet.

When it is launched as /usr/bin/ls, it runs the list-directory applet.

That makes it very useful for early operating-system work because one small binary can provide enough commands to inspect and repair a minimal system.

Why this package is static for now

Most normal Linux programs are dynamically linked.

That means the program is not complete by itself. At runtime it needs:

the dynamic loader
shared libraries
the C library

For musl systems, that usually includes something like:

/lib/ld-musl-x86_64.so.1

ONIX will eventually package the C library and loader properly too.

But Phase 409 is earlier than that.

So this BusyBox build is static:

/usr/bin/busybox contains the code it needs to run

That lets us test the BusyBox .stone before solving every runtime library ownership question.

This is not meant to hide the future work. It only keeps the learning step small:

first prove .stone BusyBox
later package the rest of the system dependencies

Important distinction: Nix source, musl build, boulder stone

This phase still uses Nix for one thing:

find the pinned BusyBox source tarball

That is acceptable here because source acquisition is not the final installed system payload.

There is one extra subtlety.

Boulder currently creates an AerynOS-style build container. That container has a glibc toolchain. ONIX is intentionally staying musl-based.

So Phase 409 uses a careful bootstrap bridge:

BusyBox source tarball
        |
        v
build BusyBox in the Alpine/musl forge VM
        |
        v
create a small prepared payload tarball
        |
        v
boulder packages that payload into a .stone
        |
        v
onix-busybox-...stone
        |
        v
moss local repo

What is not allowed is:

copy Nix's already-built BusyBox into the final image and call it done

Phase 409 does not do that.

What the script does

Run:

make phase 409

The host-side script:

vm/phase4/build-busybox-stone.sh

does this:

  1. Reads the pinned nixpkgs_2 revision from flake.lock.

  2. Asks Nix for the matching BusyBox source tarball path.

  3. Computes the source tarball SHA-256.

  4. Copies the recipe template and source tarball into the forge VM.

  5. Builds BusyBox in the Alpine/musl forge VM with CONFIG_STATIC=y.

  6. Verifies the built BusyBox binary is static.

  7. Creates a prepared payload tarball containing /usr/bin/busybox, applet links, and package notes.

  8. Generates a concrete stone.yaml from:

    vm/phase4/stone-recipes/onix-busybox/stone.yaml.in
    
  9. Runs boulder build inside the forge VM to package the prepared payload.

  10. Runs moss inspect --check on the produced .stone.

  11. Extracts the .stone and checks the payload.

  12. Installs the package into a disposable moss target.

  13. Copies the .stone back to the host.

  14. Adds it to:

    artifacts/onix-local-repo/
    

What the recipe does

The generated recipe packages the prepared musl-static payload.

The important recipe parts are:

install:
  copy usr/ into the install root
  normalize modes
  clear inherited setgid bits from package-created directories

The source build still happens in this phase, just before the boulder packaging step. That preserves the musl-static payload while we are still learning how to give boulder a native musl build environment.

The installed package contains:

/usr/bin/busybox
/usr/bin/sh
/usr/bin/ash
/usr/bin/awk
/usr/bin/cat
/usr/bin/getty
/usr/bin/hostname
/usr/bin/ifconfig
/usr/bin/ip
/usr/bin/nc
/usr/bin/netstat
/usr/bin/nslookup
/usr/bin/ping
/usr/bin/route
/usr/bin/uname
/usr/share/onix/packages/onix-busybox.applets
/usr/share/onix/packages/onix-busybox.md

Why /usr/bin and not /bin inside the stone?

Boulder/Moss currently keep package payloads /usr-centric. The previous attempt to package /bin/busybox proved this: boulder explicitly ignored non-/usr files during artifact analysis.

So Phase 409 packages BusyBox under /usr/bin.

Phase 410 will be responsible for image-level compatibility:

/bin -> usr/bin

or, on an image with a real /bin directory:

/bin/busybox -> ../usr/bin/busybox
/bin/sh      -> busybox

The applet list is intentionally broader than the final system may need.

At this point we are still learning which bootstrap proofs need which commands. Later ONIX can shrink this to an explicit config.

Why it builds inside the forge VM

The forge VM already has:

boulder
moss
musl userspace
build tools

That makes it the right place to build ONIX bootstrap stones.

The host orchestrates the build, the forge compiles the musl-static BusyBox binary, and boulder cuts the .stone:

host script       = conductor
Alpine forge      = musl source build
boulder           = .stone packager
moss              = .stone verifier/installer

Expected output

You should see the source policy first:

==> Phase 409 source-built BusyBox stone
source     : /nix/store/...-busybox-1.37.0.tar.bz2
version    : 1.37.0
sha256     : ...
nix role   : source acquisition only
source build: Alpine/musl forge VM
stone cut  : boulder packages the musl-static payload into a .stone

Then the forge builds the source, prints the generated recipe, cuts the .stone, and verifies the result.

The important success lines are:

==> success
stone : /home/mason/stone-lab/onix-busybox/out/onix-busybox-...
repo  : /home/mason/stone-lab/onix-busybox/repo/stone.index

Then the host copies the stone back and refreshes the local repo:

==> success
onix-busybox stone: artifacts/onix-stones/onix-busybox-...
local repo index   : artifacts/onix-local-repo/stone.index

What this phase proves

Phase 409 proves:

  • we can build a real system package from source,
  • the output is a .stone,
  • moss accepts and verifies it,
  • the BusyBox binary is static or static-PIE and built in the musl forge,
  • the required applet symlinks exist,
  • the package installs into a disposable moss target,
  • the host has a local repo containing onix-busybox.

That is the first local replacement package for Phase 4.

Small build choices we learned here

Two details matter:

  1. file may describe the binary as:

    static-pie linked
    

    That is still self-contained for our purpose. It is a static position independent executable.

  2. The BusyBox tc applet is disabled in this bootstrap build.

    Alpine’s current kernel headers no longer expose old CBQ traffic-control structs used by the BusyBox tc applet. ONIX does not need tc for the Phase 4 shell/network/SSH proofs, so Phase 409 leaves it out.

What this phase does not do

Phase 409 does not yet install BusyBox into the ONIX disk image.

The current boot image is not changed.

That is intentional.

The safe order is:

409 — build and verify the stone
410 — install/use it in the image
411 — boot and prove shell/network/SSH still work

If Phase 409 fails, the booting image remains untouched.

How to inspect the result

After success, inspect the host artifacts:

ls -lh artifacts/onix-stones/
ls -lh artifacts/onix-local-repo/

You can inspect the package with host Moss:

artifacts/host-tools/bin/moss inspect artifacts/onix-stones/onix-busybox-*.stone

You can check the local repo index exists:

test -f artifacts/onix-local-repo/stone.index

The next phase should consume this package from the local repo instead of copying a BusyBox payload directly from Nix.