rig/test
dan-claude-bot a950569832 feat: users apply grants the box tier, not just the socket
Role `box` resolved to exactly one action, `usermod -aG incus`. That is
the socket — step 1 of the five `box grant` performs. Without the other
four (the user-<uid> project, its narrowing to boxnet and only boxnet,
the snapshot and backup allowances clone and `box export` ride, and the
shipped box-net profile installed into that project) the user's first
`box new` refuses for want of a box-net profile, so apply's promise —
the users file is the fleet's source of truth — was not kept for this
role. Worse, until an admin arrived by hand the user held an `incus`
membership with no converged project, and incus-user would lazily hand
them a stock unhardened NAT bridge: a state box's own contract forbids.

On host=yes apply now calls `box grant <user>` per box-role user. rig
calls box's grant rather than reimplementing four fifths of it — the
"rig never installs Incus" boundary is about installation, not
invocation, and grant is already script-callable: idempotent,
root-or-sudo, stdin-pinned, with its own run-as-the-user touch.

Three decisions the code carries in comment form:

- Ordering. The call sits after `useradd` (grant opens with a getent
  passwd and refuses an unknown account) and after the other groups, so
  a user whose grant fails still lands with everything rig owns outright.

- Failure granularity, split the way the host= guard beside it already
  splits. A missing box CLI on host=yes dies, like the missing incus
  group: a broken VM host, not a per-user accident. A per-user grant
  failure warns and continues — one box-role user somewhere in the fleet
  must not stop apply everywhere VMs don't live. host=no and marker-less
  boxes keep their existing skip-with-warning untouched.

- The group ADD is deferred to grant, while `incus` stays in the wanted
  set so the exact-convergence loop never strips a box-role user's
  socket. Grant's rollback only reaches a membership that run added, so
  rig opening the socket first would leave a failed grant unable to
  close it. And grant is the authority on whether the group belongs at
  all: for an incus-admin member it deliberately does not add `incus`.

An incus-admin member is warned, never fatal: box grant refuses them
today, which heavy-duty/box#99 fixes box-side with no rig change needed.

Closes #49

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 19:10:29 +00:00
..
cli.sh feat: users apply grants the box tier, not just the socket 2026-07-19 19:10:29 +00:00
db-integration.sh test(db): add real dump/restore round-trip probe + CI job + manual proof docs 2026-07-17 15:48:51 +00:00
labels-reconcile.sh fix: base the human auto-request on THIS handoff, not review history 2026-07-18 20:16:57 +00:00
release.sh test: pin exactly one on.push key 2026-07-19 16:14:42 +00:00