forked from heavy-duty/rig
feat(coolify): warn when the role marker names a non-control-plane box — advisory, never a gate (#25)
Issue #25 named this consumer when it introduced /etc/rig/role: 'rig <cmd> sanity warnings later (e.g. coolify install on a non-control-plane box)'. Both coolify verbs now read the marker through the lib's read_role_marker (RIG_ROLE_MARKER overrides the path for fixtures, repo precedent) and warn when it names any role but control-plane — the likeliest story is the wrong SSH session about to put a control plane on a workload box. The marker stays advisory: it may be absent (pre-marker boxes, hand-built boxes) and absence stays silent — warning there would nag every legitimate run — and a present-but-different marker warns and proceeds, because an advisory file must never outrank the operator (contrast close-root, where the marker IS the gate: shutting the root door blind is irreversible in a way an extra Coolify is not). The check sits after arg validation and before the root check, so exit codes are untouched (usage stays 2, the root refusal stays 1) and the harness proves it non-root. Tests drive the live matrix through fixture markers (warns on workload, silent on control-plane and on absence, still exits 1 at the root check) and pin the warning's presence in both shipped scripts for root-run environments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
34f1986da0
commit
900697bdc2
3 changed files with 89 additions and 2 deletions
|
|
@ -7,6 +7,10 @@
|
|||
# already-filled bindings file is left untouched.
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
|
||||
# shellcheck source=SCRIPTDIR/lib/users-config.sh
|
||||
. "$HERE/lib/users-config.sh" # read_role_marker — the traits line bootstrap wrote
|
||||
|
||||
log() { printf 'rig-coolify-backup: %s\n' "$*"; }
|
||||
warn() { printf 'rig-coolify-backup: WARNING: %s\n' "$*" >&2; }
|
||||
die() { printf 'rig-coolify-backup: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
||||
|
|
@ -67,6 +71,18 @@ done
|
|||
[ -n "$PG_USER" ] || die "--pg-user must not be empty" 2
|
||||
[ -n "$PG_DB" ] || die "--pg-db must not be empty" 2
|
||||
|
||||
# --- role-marker sanity (issue #25) ------------------------------------------
|
||||
# Same advisory check as `rig coolify install`, same reasoning: this command
|
||||
# dumps the CONTROL PLANE's database, so a marker naming any other role almost
|
||||
# certainly means the wrong SSH session — but the marker is advisory and may be
|
||||
# absent, so WARN, never die, and warn before the root check so the harness can
|
||||
# prove it non-root (RIG_ROLE_MARKER points it at fixtures, repo precedent).
|
||||
MARKER_LINE="$(read_role_marker "${RIG_ROLE_MARKER:-/etc/rig/role}")"
|
||||
case "$MARKER_LINE" in
|
||||
""|"role=control-plane "*) ;;
|
||||
*) warn "this box's role marker says '${MARKER_LINE}' — not a control-plane box. The nightly dump targets Coolify's own database, which lives on role control-plane; if this is the wrong box, stop here and re-check your SSH session." ;;
|
||||
esac
|
||||
|
||||
# --- guards ----------------------------------------------------------------
|
||||
[ "$(id -u)" -eq 0 ] || die "must run as root"
|
||||
if [ -r /etc/os-release ]; then
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@
|
|||
# explicit act.
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
|
||||
# shellcheck source=SCRIPTDIR/lib/users-config.sh
|
||||
. "$HERE/lib/users-config.sh" # read_role_marker — the traits line bootstrap wrote
|
||||
|
||||
log() { printf 'rig-coolify: %s\n' "$*"; }
|
||||
warn() { printf 'rig-coolify: WARNING: %s\n' "$*" >&2; }
|
||||
die() { printf 'rig-coolify: ERROR: %s\n' "$1" >&2; exit "${2:-1}"; }
|
||||
|
||||
usage() {
|
||||
|
|
@ -32,6 +37,26 @@ if [ -z "$VERSION" ]; then
|
|||
die "--version <pin> is required" 2
|
||||
fi
|
||||
|
||||
# --- role-marker sanity (issue #25) ------------------------------------------
|
||||
# Coolify belongs on the control-plane box and nowhere else — but the marker is
|
||||
# ADVISORY, never a gate. It may legitimately be absent (a box bootstrapped
|
||||
# before rig wrote markers, or a hand-built one), and rig refuses to guess from
|
||||
# silence. When the marker EXISTS and names another role, the likeliest story
|
||||
# is an operator in the wrong SSH session about to put a control plane on a
|
||||
# workload box — so say it loudly. But WARN, never die: the operator may also
|
||||
# be deliberately repurposing the box, and an advisory file must never outrank
|
||||
# the human running the command (contrast close-root, where the marker IS the
|
||||
# gate — shutting the root door blind is irreversible in a way an extra
|
||||
# Coolify is not). Placed BEFORE the root check for the same reason arg errors
|
||||
# are: the harness proves it non-root, and reading a 0644 file needs no
|
||||
# privilege. RIG_ROLE_MARKER overrides the path so tests point it at fixtures
|
||||
# (repo precedent: users-apply, users-close-root).
|
||||
MARKER_LINE="$(read_role_marker "${RIG_ROLE_MARKER:-/etc/rig/role}")"
|
||||
case "$MARKER_LINE" in
|
||||
""|"role=control-plane "*) ;;
|
||||
*) warn "this box's role marker says '${MARKER_LINE}' — not a control-plane box. Coolify belongs on role control-plane; if this is the wrong box, stop here and re-check your SSH session. Repurposing it on purpose? Re-run 'rig bootstrap control-plane' first so the marker tells the truth." ;;
|
||||
esac
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "must run as root"
|
||||
|
||||
export AUTOUPDATE=false
|
||||
|
|
|
|||
46
test/cli.sh
46
test/cli.sh
|
|
@ -200,6 +200,52 @@ else
|
|||
echo "skip: coolify backup non-root refusal (running as root)"
|
||||
fi
|
||||
|
||||
# --- role-marker sanity: coolify verbs off the control plane (#25) -----------
|
||||
# Both coolify commands read /etc/rig/role and WARN — never die — when the
|
||||
# marker names a non-control-plane role: the likeliest story is the wrong SSH
|
||||
# session, but the marker is advisory and must not outrank the operator. The
|
||||
# warning fires BEFORE the root check (same testability rule as arg errors),
|
||||
# so a non-root run prints it and then hits the root refusal — provable here
|
||||
# with RIG_ROLE_MARKER pointed at fixtures (repo precedent: the close-root
|
||||
# marker gate). Counting fires proves silence too: a control-plane marker, an
|
||||
# absent marker, and a marker-less box must all stay quiet, because warning on
|
||||
# absence would nag every pre-marker box on every legitimate run.
|
||||
marker_warns() { # marker_warns <marker_path> <cmd...> — how many warnings fired
|
||||
local marker="$1"; shift
|
||||
env RIG_ROLE_MARKER="$marker" "$@" 2>&1 | grep -c "not a control-plane box" || true
|
||||
}
|
||||
MARKER_FIX="$(mktemp -d)"
|
||||
printf 'role=workload class=server host=no join=authkey\n' > "$MARKER_FIX/workload"
|
||||
printf 'role=control-plane class=server host=no join=authkey\n' > "$MARKER_FIX/control-plane"
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
check "coolify: warns on a non-control-plane marker" 0 "1" \
|
||||
marker_warns "$MARKER_FIX/workload" "$ROOT/commands/coolify-install.sh" --version 4.1.2
|
||||
check "coolify: control-plane marker stays silent" 0 "0" \
|
||||
marker_warns "$MARKER_FIX/control-plane" "$ROOT/commands/coolify-install.sh" --version 4.1.2
|
||||
check "coolify: absent marker stays silent (advisory, not a gate)" 0 "0" \
|
||||
marker_warns "$MARKER_FIX/absent" "$ROOT/commands/coolify-install.sh" --version 4.1.2
|
||||
# The warning must stay a warning: the run proceeds past it and stops at the
|
||||
# root check (exit 1), never turned into a marker refusal.
|
||||
check "coolify: the marker warns but never refuses" 1 "must run as root" \
|
||||
env RIG_ROLE_MARKER="$MARKER_FIX/workload" "$ROOT/commands/coolify-install.sh" --version 4.1.2
|
||||
check "coolify backup: warns on a non-control-plane marker" 0 "1" \
|
||||
marker_warns "$MARKER_FIX/workload" "$ROOT/commands/coolify-backup-install.sh"
|
||||
check "coolify backup: control-plane marker stays silent" 0 "0" \
|
||||
marker_warns "$MARKER_FIX/control-plane" "$ROOT/commands/coolify-backup-install.sh"
|
||||
check "coolify backup: the marker warns but never refuses" 1 "must run as root" \
|
||||
env RIG_ROLE_MARKER="$MARKER_FIX/workload" "$ROOT/commands/coolify-backup-install.sh"
|
||||
else
|
||||
echo "skip: coolify role-marker warning checks (running as root)"
|
||||
fi
|
||||
rm -rf "$MARKER_FIX"
|
||||
# Root runs skip the live checks above, so also pin the warning's presence in
|
||||
# both shipped scripts — a deleted advisory cannot ship green (repo precedent:
|
||||
# the staging/runner tag greps).
|
||||
check "coolify: marker warning present in the shipped script" 0 "" \
|
||||
grep -q "not a control-plane box" "$ROOT/commands/coolify-install.sh"
|
||||
check "coolify backup: marker warning present in the shipped script" 0 "" \
|
||||
grep -q "not a control-plane box" "$ROOT/commands/coolify-backup-install.sh"
|
||||
|
||||
# --- rig db (ad-hoc dump/restore) -------------------------------------------
|
||||
check "bare db shows usage, exit 2" 2 "usage:" "$ROOT/bin/rig" db
|
||||
check "db --help exits 0" 0 "usage:" "$ROOT/bin/rig" db --help
|
||||
|
|
|
|||
Loading…
Reference in a new issue