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
+31 -10
View File
@@ -20,14 +20,8 @@
# Both are re-runnable. Each remembers the steps it finished and skips them, so
# stopping halfway and coming back costs nothing.
#
# ── Privileges ──
# Run it as yourself — it asks for administrator rights when it needs them.
#
# Linux needs root: apt, systemd units, useradd, netplan, ufw, and creating
# directories owned by the service account. macOS must NOT be root: Homebrew
# refuses to run as one, and there is nothing to chown because the account
# running this IS the owner. Both scripts enforce that themselves; this checks
# first so the failure arrives before anything has been done.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -72,12 +66,39 @@ case "$KERNEL" in
Darwin)
[[ "$EUID" -eq 0 ]] && die "do not run this with sudo on macOS — Homebrew refuses to run as root. Run it as yourself."
;;
Linux)
[[ "$EUID" -ne 0 ]] && die "please run as root: sudo ./scripts/install.sh"
;;
Linux) ;;
*) die "unsupported system: $KERNEL. Officer installs on Linux and macOS." ;;
esac
SELF="$SCRIPT_DIR/install.sh"
# ── Privileges: asked for, not demanded ──
#
# Run this as YOURSELF. On Linux it needs root for apt, systemd units, useradd,
# netplan, ufw and for creating directories owned by the service account — so it
# asks, once, through sudo, and re-executes itself. Typing `sudo` yourself works
# too and changes nothing, but it should not be the price of starting.
#
# Variables are passed to sudo explicitly rather than with -E. `env_reset` is the
# sudoers default and strips the environment, which is how DATA_PATH was lost
# once already; naming them on the command line survives it.
#
# macOS never escalates. Homebrew refuses to run as root, and nothing in the
# macOS path needs it — the account running this IS the owner, so there is
# nothing to chown and nothing to drop privileges to.
if [[ "$KERNEL" != "Darwin" && "$EUID" -ne 0 ]]; then
command -v sudo >/dev/null 2>&1 || die "this needs root and sudo is not installed — run it as root"
say ""
say " This needs administrator rights. You will be asked for your password."
say ""
exec sudo \
OFFICER_ROOT="${OFFICER_ROOT:-}" \
SETUP_USERNAME="${SETUP_USERNAME:-}" \
MACHINE_ROLE="${MACHINE_ROLE:-}" \
bash "$SELF" "$@"
fi
say ""
say "${BOLD}Officer install${NC}"
say " system: $KERNEL"