feat: server-class staging template — box mints, rig converges, cast registers #69
No reviewers
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:cli
scope:drill
scope:host
scope:installer
scope:templates
scope:tiers
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/box#69
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/staging-template"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Server-class boxes: the
stagingtemplatebox gains a server-class
stagingtemplate so staging VMs — registered in the control plane as servers, reachable tailnet-only — are minted by box instead of by a hand-rolledincus launchin a private infra repo.The layering (companion: heavy-duty/rig#22):
templates/staging/: Debian 13 cloud image, userops, build-sized resources, docker + rig (+ tmux, the #65 contract) preinstalled — and nothing that joins or admits. Strictly creds-free.box shell→sudo rig bootstrap workload), hardens sshd and joins the tailnet; it holds the auth key in process memory. box never sees it.Two new optional
box.envallowlist keys carry the server posture, and only those:BOX_REQUIRE_VM=1— no container fallback (exit 1, naming/dev/kvm) and no explicit--container(exit 2): the VM is the trust boundary and the guest runs docker. The refusal reads the effective mode (afterpick_mode), and its message holds for both tiers —/dev/kvmis a host fact, and admin and restricted mints go through the same daemon, so the fix is a KVM host, not a grant.BOX_AUTOSTART=1—boot.autostart=trueat launch, so the box returns from a host reboot without an operator; clones inherit it viaincus copy.There is still no key for a network or a
security.*flag; box's isolation stack is untouched (the guest joins the overlay outbound —docs/box-design.mdgains the overlay-join clarification and the snapshot-before-join rule).Rebased onto main
The branch was rebased onto current main (post #74 restricted tier, CI,
test/cli.sh):load_template: the new key arms re-applied onto main's version (spelled-out required-keys guard, SC2015/SC2034 comment blocks — all intact).cmd_new: theBOX_REQUIRE_VMrefusal sits in the fresh-mint branch afterpick_mode, downstream of main's new tier-aware box-net pre-flight.box tmuxrunstmux new-sessioninside every template's box (#65), and the operator babysitsrig bootstrap workloadthrough it.Template test suite (new)
test/cli.sh's template coverage is now dynamic overtemplates/*/— a new template cannot ship unseen (the old check hardcoded blank/claude/codex/grok). Per template:box.envis driven through the real, extractedload_template(the same source-the-pure-function trick asbox_tier): unknown keys and missingBOX_IMAGE/BOX_USERfail, with fixtures proving both dies.user-data.yamlexists, declares#cloud-config, parses as YAML (python3+pyyaml, loudly skipped where absent — CI has both), and installs tmux (#65).Staging-specific: both boot demands proven through the parser; docker + rig present; and a creds-free grep-refusal — no
tailscale/authkey/sshin effective cloud-init lines. Grep guards pin thecmd_newhalf: the refusal orders afterpick_mode, andboot.autostartis stamped only under theT_AUTOSTARTguard.Refusal paths were also driven end-to-end against a shimmed incus: explicit
--container→ exit 2; no/dev/kvm(mount-namespace) → exit 1 with the KVM message; KVM host → mints.Gate:
bash test/cli.sh— 123 passed, 0 failed;shellcheck -xclean overbin/* **/*.sh.Closes #68
🤖 Generated with Claude Code
Merge order (cross-repo)
Analyzed all open heavy-duty PRs (box #79/#78/#69, rig #30/#29/#21/#19) for file overlap, semantic dependencies, and mergeability. The recommended order:
test/cli.sh→ trivial rebase after #29.install.shrewrite,bin/box, CI). Lands first so the other box PRs rebase onto the new layout exactly once.install.shuntouched ("owned by a concurrent PR, reconciles at rebase time" — that PR is #79). Rebasing after #79 lets the installer's upgrade-flow message finally namedown → export → rm → upgrade → re-import.bin/box/test/cli.sh/CHANGELOG/docs/box-design.md→ mechanical rebase.Closed as superseded (both predate the traits redesign that landed via rig#27/#28, and their content is re-delivered on the new design by their successors' own account):
Notes:
This PR is step 5 — mechanical rebase over
bin/box/test/cli.sh/CHANGELOG/docs/box-design.mdonce #79 and #78 are in.Closing in favor of the thin-template layering decided today: tenant content moves to rig bootstrap roles (heavy-duty/rig#31), templates shrink to creds-free seeds (#81). The parts of this PR that are mint-time box concerns — the BOX_REQUIRE_VM / BOX_AUTOSTART box.env keys and the dynamic template test machinery — are being re-cut as a slim PR. The staging template itself returns as a thin seed once rig#31's staging role exists. Merge order updates accordingly: box track is now #79 → #78 → slim template-keys PR.
Pull request closed