diff --git a/CHANGELOG.md b/CHANGELOG.md index 7063c93..a9fabff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ on the way to cutting its first release, and this file starts there. ### Changed +- `bootstrap --host yes` installs a pinned box release instead of `main` (#103) - Release and labels machinery is consumed from heavy-duty/ceremony@0.1.0 by reference — the workflows shrink to caller stubs, the guard scripts and their tests move upstream (#112, ceremony#13) ## 0.3.0 — 2026-07-21 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0cf609..abf2747 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,9 @@ heavy-duty/ceremony's machinery, consumed by reference: is the doctrine, `.github/workflows/release.yml` here is the ≤20-line caller pinning it, and the guards run in `ci.yml` from the same pin. Bare `X.Y.Z` tags, no `v`; the tag's source tarball is the package -`install.sh` downloads — rig ships no other artifact. +`install.sh` downloads — rig ships no other artifact. Each release deliberately +bumps and drills the `BOX_RELEASE` pin in `commands/bootstrap.sh`; it must never +float to a moving ref. What stays rig's is the **drill** — the real-hardware gate before the handoff of a release PR: tenant guests minted and converged via box, diff --git a/README.md b/README.md index cd6c7c4..abe895a 100644 --- a/README.md +++ b/README.md @@ -358,23 +358,17 @@ box is present) and **opt-out** (`RIG_SKIP_BOX_INSTALL=1`, plus a graceful skip with a manual-command pointer when curl or the network is missing — box is the host *extra*, so a failed box install never aborts a bootstrap that otherwise succeeded). Source is pinnable with `BOX_REPO` / `BOX_REF` (default -`heavy-duty/box@main`). If `/dev/kvm` is absent, rig warns (a host that exists to +`heavy-duty/box@0.9.0`). If `/dev/kvm` is absent, rig warns (a host that exists to run VMs should have it) but does not fail — the shape is rehearsed in containers, which legitimately lack it. (The world-readable global install path — box under `/opt/box` readable by every non-root user — depends on box PR #71; until that merges box's root install lands in `/root`.) -> **The box install is unpinned — on purpose, and out loud.** `coolify install` -> demands a version pin; the box step tracks a moving `heavy-duty/box@main`. -> Not because box self-updates (it doesn't — it has Coolify's shape, not the -> runner's) but because there is nothing to pin *to*: box cuts no tags and no -> releases, and its installer resolves `refs/heads/` — branches only — so -> a `BOX_REF=v0.5.0` would 404 even if the tag existed. Issue #12's call was -> that silently tracking `main` on the box that runs the agents is the option -> not to pick — hence this paragraph. `BOX_REPO` / `BOX_REF` are the pin -> points the day box cuts a tag (or you point at a frozen branch of your own -> fork); `RIG_SKIP_BOX_INSTALL=1` opts out entirely for a host whose box you -> manage by hand. +> **The box install is release-pinned.** A rig release carries one box release +> pin, so two machines bootstrapped from the same rig install the same box. +> `BOX_REPO` / `BOX_REF` remain explicit overrides for development and +> pre-release drills; `RIG_SKIP_BOX_INSTALL=1` opts out entirely for a host +> whose box you manage by hand. `dev-server` is the closed-door VM-hosting shape — `tag:local`, box CLI installed as above, operators entering as themselves (`--root-door open` turns it into the diff --git a/commands/bootstrap.sh b/commands/bootstrap.sh index b39554b..f4a7013 100755 --- a/commands/bootstrap.sh +++ b/commands/bootstrap.sh @@ -671,7 +671,9 @@ fi # hardening + the tailnet, and box is the host EXTRA, so a failed box install # must never abort a bootstrap that otherwise fully succeeded. # -# PIN POINTS: BOX_REPO / BOX_REF override the source (default heavy-duty/box@main). +# PIN POINTS: BOX_REPO / BOX_REF override the source (default +# heavy-duty/box@0.9.0). BOX_RELEASE is bumped deliberately when rig releases, +# after the pinned combination has passed the release drill. # BOX_YES=1 makes box's installer non-interactive AND keeps setup-host (so the # Incus stack is actually built, not just the CLI dropped on PATH). # @@ -684,8 +686,9 @@ fi # on box PR #71. Until that merges, box's root install lands in /root and non-root # users cannot reach it, so this step is only fully correct once box#71 is merged. if [ "$HOST" = "yes" ]; then + BOX_RELEASE=0.9.0 BOX_REPO="${BOX_REPO:-heavy-duty/box}" - BOX_REF="${BOX_REF:-main}" + BOX_REF="${BOX_REF:-$BOX_RELEASE}" BOX_INSTALL_URL="https://raw.githubusercontent.com/${BOX_REPO}/${BOX_REF}/install.sh" BOX_MANUAL="curl -fsSL ${BOX_INSTALL_URL} | BOX_YES=1 bash" if [ "${RIG_SKIP_BOX_INSTALL:-}" = "1" ]; then diff --git a/test/cli.sh b/test/cli.sh index d4796b7..1c2a5e6 100644 --- a/test/cli.sh +++ b/test/cli.sh @@ -167,8 +167,16 @@ check "bootstrap: box install is guarded on host=yes" 0 "" \ # setup-host, so box builds Incus rather than only dropping the CLI on PATH). check "bootstrap: box install runs box's installer non-interactively" 0 "" \ grep -q "BOX_YES=1 bash" "$ROOT/commands/bootstrap.sh" -# Pin points: BOX_REPO / BOX_REF override the source, default heavy-duty/box@main. -check "bootstrap: box source is pinnable, defaults to heavy-duty/box@main" 0 "" \ +# The default is a released semver pin carried in rig's tree, never a moving +# branch. BOX_REF remains an override so explicit main and release-branch refs +# still work for development and pre-release drills. +box_release="$(sed -n 's/^[[:space:]]*BOX_RELEASE=//p' "$ROOT/commands/bootstrap.sh")" +check "bootstrap: box default is a released semver pin, not a moving ref" 0 "" \ + grep -qxE '[0-9]+\.[0-9]+\.[0-9]+' <<<"$box_release" +# shellcheck disable=SC2016 +check "bootstrap: BOX_REF overrides the released default" 0 "" \ + grep -qF 'BOX_REF="${BOX_REF:-$BOX_RELEASE}"' "$ROOT/commands/bootstrap.sh" +check "bootstrap: box repository remains pinnable" 0 "" \ grep -qF 'BOX_REPO:-heavy-duty/box' "$ROOT/commands/bootstrap.sh" # Opt-out for rehearsals / offline / hand-managed hosts. check "bootstrap: box install honors RIG_SKIP_BOX_INSTALL opt-out" 0 "" \