ask for privileges, do not demand them

Run any of the three as yourself. On Linux they now ask through sudo and
re-execute, rather than refusing until you type it. Typing `sudo` still works and
changes nothing — it just stops being the price of starting.

This also fixes a trap that had nothing to do with taste. `sudo` strips the
environment by default (`env_reset`), so `OFFICER_ROOT=/somewhere sudo ./install.sh`
silently loses the variable and installs to the default path instead. The
re-exec passes OFFICER_ROOT, SETUP_USERNAME and MACHINE_ROLE to sudo BY NAME
rather than relying on -E, which env_reset ignores. This project has already lost
a variable to that once — see the DATA_PATH commit.

The invoking account is recovered the way it always was: sudo sets SUDO_USER,
which lib/base.sh already reads, including the check for a SUDO_USER that is
itself uid 0 on providers whose default account is root under an ordinary name.

macOS never escalates, in any of the three. Homebrew refuses to run as root, the
account running the script IS the owner, and the sections that needed root are
the ones the macOS path skips.

--help and argument errors still work with no privileges at all, since arguments
are parsed before any of this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-13 02:54:10 +00:00
co-authored by Claude Opus 5
parent 3cca07187e
commit ea87ffed04
3 changed files with 70 additions and 22 deletions
+20 -4
View File
@@ -129,14 +129,30 @@ fi
# It works out because the macOS path skips everything that needed root in the
# first place (see MACOS_SKIP in lib/base.sh). What is left — brew, the Xcode
# command line tools, the agent CLIs, bun — is all per-user by design.
# ── Privileges: asked for, not demanded ──
#
# Run this as YOURSELF. Linux needs root for apt, systemd units, useradd, netplan
# and ufw, so it asks through sudo and re-executes itself rather than making you
# type it. Variables go to sudo by name rather than with -E: `env_reset` is the
# sudoers default and strips the environment, which is how DATA_PATH was lost
# once already.
#
# macOS never escalates — Homebrew refuses to run as root, and the sections that
# needed root are the ones the macOS path skips.
if [[ "$OS" == "macos" ]]; then
if [[ "$EUID" -eq 0 ]]; then
fail "Do not run this with sudo on macOS — Homebrew refuses to run as root. Run it as yourself."
fi
else
if [[ "$EUID" -ne 0 ]]; then
fail "Please run as root: sudo ./machine-setup.sh"
fi
elif [[ "$EUID" -ne 0 ]]; then
command -v sudo >/dev/null 2>&1 || fail "This needs root and sudo is not installed — run it as root."
echo ""
echo " This needs administrator rights. You will be asked for your password."
echo ""
exec sudo \
OFFICER_ROOT="${OFFICER_ROOT:-}" \
SETUP_USERNAME="${SETUP_USERNAME:-}" \
MACHINE_ROLE="${MACHINE_ROLE:-}" \
bash "$SCRIPT_DIR/machine-setup.sh" "$@"
fi
# On macOS the account running the script IS the account, and there is nothing to