rig bootstrap should take the users file — one command, box ready #51

Closed
opened 2026-07-19 16:05:15 +00:00 by dan-claude-bot · 1 comment
dan-claude-bot commented 2026-07-19 16:05:15 +00:00 (Migrated from github.com)

rig bootstrap should take the users file — one command, box ready

The ask

Today bring-up is at least two commands, three on a VM host:

rig bootstrap dev --hostname foo
box setup-host              # host=yes only, and box is a separate CLI
rig users apply ./users     # the users file, finally

rig bootstrap already knows everything else about what this box is — class,
host, join, hostname — and writes /etc/rig/role to say so. The users file
is the last piece of "what this box is" that bootstrap does not take. It
should take it, and (proposed) require it:

rig bootstrap dev --hostname foo --users ./users

One command, and you have a box with its people on it.

Why required rather than optional

A bootstrapped box with no users converges to a box only root can enter. On
class=human that is a half-built machine waiting for a second command the
operator has to remember — and rig users close-root is explicitly gated
behind "once your admin key works", which needs an admin to exist. Requiring
--users makes the complete path the default path instead of the documented
one.

Ordering on host=yes — smaller than it first looks

The apparent problem: box setup-host owns the incus group and rig never
installs Incus, so inlining users apply would hit users-apply.sh:180 and
die pointing at box setup-host.

But box's own installer already runs setup-host (box/bin/box:502:
"install.sh runs it for you, so this is for re-applying by hand"). So on a
host=yes machine, installing the box CLI has already built the stack —
incus group, boxnet, ACL, box-net profile, firewall. There is nothing to
wait for and no phase to orchestrate. The prerequisite is simply:

install box            # host=yes only — its installer runs setup-host
rig bootstrap dev --hostname foo --users ./users
   ├─ traits + tailnet join + /etc/rig/role marker
   └─ users apply: create users → converge groups → box grant each box-role user

Note the intra-apply order: box grant requires the account to exist
(grant-user.sh:62 does a getent passwd check), so the grant step must
follow useradd, not precede it.

Correction: bootstrap already installs box

An earlier revision of this issue asked "should rig install box on
host=yes?" as the open question standing between this and one-command
bring-up. That was wrong — bootstrap already does it, deliberately and
with the boundary reasoned out in place, at commands/bootstrap.sh:437-512:
it installs the box CLI globally and lets box's own installer run
setup-host, under BOX_YES=1 for non-interactivity. The delegation law is
preserved exactly as the comments there state — rig installs box, and box
installs Incus.

So on host=yes the incus group normally exists by the time a users phase
would run, because bootstrap put it there. Nothing about the ordering needs
solving.

What remains

The early host=yes precondition fires only in the narrow case where box
was never installed — RIG_SKIP_BOX_INSTALL=1, or curl absent, both of
which bootstrap already handles by warning and continuing. That refusal
should also be gated on the users file actually containing a role-box
user, so an admins-only file is not refused on an Incus-less host.

No box setup-host call and no new install path belong in this change —
both already exist upstream in the same script.

Other decisions

  • Breaking change. Every existing rig bootstrap invocation gains a
    required flag. Worth a major bump and a CHANGELOG entry that names the
    migration.
  • --no-users is the escape hatch, and it is explicit. control-plane,
    workload and runner are class=server — machines whose door is the
    control plane's automation rather than a human's. They are still better
    off with named human accounts: a server nobody logs into routinely is
    exactly where shared-root access rots, and per-human users keep
    attribution intact for the times someone does go in. So --users is
    required for every role, and skipping it is a deliberate --no-users
    rather than a default.
  • Where the file lives. The users file is passed per invocation and
    never persisted (README.md: "rig never persists it"). Bootstrap taking a
    path must not change that.
  • The tenant roles. rig bootstrap <claude|codex|grok|staging> [--user]
    is a different family with its own flags — does --users apply there at
    all, or only to the host roles?
# `rig bootstrap` should take the users file — one command, box ready ## The ask Today bring-up is at least two commands, three on a VM host: ```sh rig bootstrap dev --hostname foo box setup-host # host=yes only, and box is a separate CLI rig users apply ./users # the users file, finally ``` `rig bootstrap` already knows everything else about what this box is — class, host, join, hostname — and writes `/etc/rig/role` to say so. The users file is the last piece of "what this box is" that bootstrap does not take. It should take it, and (proposed) **require** it: ```sh rig bootstrap dev --hostname foo --users ./users ``` One command, and you have a box with its people on it. ## Why required rather than optional A bootstrapped box with no users converges to a box only root can enter. On `class=human` that is a half-built machine waiting for a second command the operator has to remember — and `rig users close-root` is explicitly gated behind "once your admin key works", which needs an admin to exist. Requiring `--users` makes the complete path the default path instead of the documented one. ## Ordering on `host=yes` — smaller than it first looks The apparent problem: `box setup-host` owns the `incus` group and rig never installs Incus, so inlining `users apply` would hit `users-apply.sh:180` and die pointing at `box setup-host`. But **box's own installer already runs setup-host** (`box/bin/box:502`: "install.sh runs it for you, so this is for re-applying by hand"). So on a `host=yes` machine, installing the box CLI has already built the stack — `incus` group, boxnet, ACL, `box-net` profile, firewall. There is nothing to wait for and no phase to orchestrate. The prerequisite is simply: ``` install box # host=yes only — its installer runs setup-host rig bootstrap dev --hostname foo --users ./users ├─ traits + tailnet join + /etc/rig/role marker └─ users apply: create users → converge groups → box grant each box-role user ``` Note the intra-apply order: `box grant` requires the account to exist (`grant-user.sh:62` does a `getent passwd` check), so the grant step must follow `useradd`, not precede it. ### Correction: bootstrap already installs box An earlier revision of this issue asked "should rig install box on `host=yes`?" as the open question standing between this and one-command bring-up. **That was wrong — bootstrap already does it**, deliberately and with the boundary reasoned out in place, at `commands/bootstrap.sh:437-512`: it installs the box CLI globally and lets box's own installer run `setup-host`, under `BOX_YES=1` for non-interactivity. The delegation law is preserved exactly as the comments there state — rig installs *box*, and box installs Incus. So on `host=yes` the `incus` group normally exists by the time a users phase would run, because bootstrap put it there. Nothing about the ordering needs solving. ### What remains The early `host=yes` precondition fires only in the narrow case where box was never installed — `RIG_SKIP_BOX_INSTALL=1`, or `curl` absent, both of which bootstrap already handles by warning and continuing. That refusal should also be gated on the users file actually containing a role-`box` user, so an admins-only file is not refused on an Incus-less host. No `box setup-host` call and no new install path belong in this change — both already exist upstream in the same script. ## Other decisions - **Breaking change.** Every existing `rig bootstrap` invocation gains a required flag. Worth a major bump and a CHANGELOG entry that names the migration. - **`--no-users` is the escape hatch, and it is explicit.** `control-plane`, `workload` and `runner` are `class=server` — machines whose door is the control plane's automation rather than a human's. They are still better off with named human accounts: a server nobody logs into routinely is exactly where shared-root access rots, and per-human users keep attribution intact for the times someone does go in. So `--users` is required for every role, and skipping it is a deliberate `--no-users` rather than a default. - **Where the file lives.** The users file is passed per invocation and never persisted (`README.md`: "rig never persists it"). Bootstrap taking a path must not change that. - **The tenant roles.** `rig bootstrap <claude|codex|grok|staging> [--user]` is a different family with its own flags — does `--users` apply there at all, or only to the host roles?
dan-claude-bot commented 2026-07-19 16:20:58 +00:00 (Migrated from github.com)

Correcting the issue body: it originally posed "should rig install box on host=yes?" as the open question blocking one-command bring-up. That was wrong — commands/bootstrap.sh:437-512 already installs the box CLI and lets box's own installer run setup-host, with the delegation boundary reasoned out in place. The ordering concern this issue opened with does not exist; only the users phase was ever missing. Body updated.

Correcting the issue body: it originally posed "should rig install box on `host=yes`?" as the open question blocking one-command bring-up. That was wrong — `commands/bootstrap.sh:437-512` already installs the box CLI and lets box's own installer run `setup-host`, with the delegation boundary reasoned out in place. The ordering concern this issue opened with does not exist; only the users phase was ever missing. Body updated.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/rig#51
No description provided.