forked from heavy-duty/rig
Reported from a real ci-box: `rig forgejo-runner install` read a registration token off the operator's terminal and then died with …/forgejo-runner-install.sh: line 250: useradd: command not found rig checked `id -u` and concluded it could administer the machine. Being root and being able to FIND the admin binaries are different facts, and only the first was asserted. `su` without `-`, sudo with a sanitised secure_path, and several container images all produce a root shell with no /usr/sbin on PATH, which is where useradd lives. Three call sites had it: both runner installers and users apply. The last is the worst — it runs mid-convergence, so a PATH-shorn root could fail partway through a user sweep rather than before it starts. require_admin_bins refuses rather than repairing PATH itself: a command that quietly prepends /usr/sbin teaches the operator nothing and leaves a misconfigured host misconfigured. The message names the remedy and, deliberately, not this script — echoing an internal path back at someone who typed `rig forgejo-runner install` is the unhelpful half of the original error. It sits beside each root check, so identity and capability are asserted together and before anything is spent. A secret typed for a run that could never succeed is the avoidable half of this bug, and there is a test for exactly that ordering. Closes #139 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
29 lines
1.6 KiB
Bash
29 lines
1.6 KiB
Bash
#!/usr/bin/env bash
|
|
# admin-path.sh — assert the admin binaries are REACHABLE, not merely that we
|
|
# are root.
|
|
#
|
|
# Being uid 0 and being able to find useradd are different facts, and rig
|
|
# asserted only the first. `su` without `-`, sudo with a sanitised secure_path,
|
|
# and several container images all hand you a root shell whose PATH carries no
|
|
# /usr/sbin — which is where useradd, usermod and groupadd live on Debian. The
|
|
# result was a bare `useradd: command not found` naming a line number inside a
|
|
# versioned install root, emitted AFTER a registration token had been read off
|
|
# the operator's terminal (#139).
|
|
#
|
|
# It REFUSES rather than repairing PATH itself. A command that quietly prepends
|
|
# /usr/sbin teaches the operator nothing and leaves a misconfigured host
|
|
# misconfigured; the same reason bootstrap refuses rather than guessing. The
|
|
# message carries the fix so the refusal costs one paste, not an investigation.
|
|
|
|
# require_admin_bins <bin>... — die unless every one resolves on PATH.
|
|
require_admin_bins() {
|
|
local missing=() b
|
|
for b in "$@"; do
|
|
command -v "$b" >/dev/null 2>&1 || missing+=("$b")
|
|
done
|
|
[ "${#missing[@]}" -eq 0 ] && return 0
|
|
# Names the REMEDY, not this script: the operator typed a `rig ...` command,
|
|
# and echoing the internal path back at them is the unhelpful half of the
|
|
# original `useradd: command not found`.
|
|
die "cannot find ${missing[*]} on PATH — it lives in /usr/sbin, which this root shell does not carry (a 'su' without '-' does this, and so do some container images). Re-run the same rig command with: PATH=/usr/sbin:/sbin:\$PATH"
|
|
}
|