From a8335bfdd60ace72a7fd0fbcc0e1d6997e2e9663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Tue, 4 Aug 2026 11:34:33 +0000 Subject: [PATCH] scripts: validate the sudoers entry before installing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setup wrote /etc/sudoers.d/officer-service with tee and then chmod'd it. Two problems, both with the same worst case: a malformed or wrongly-permissioned file there breaks sudo completely, and you cannot sudo to repair it — on a remote machine that means physical access or a rescue boot. Generate into a temp file, gate on `visudo -c`, and only then install. Use install(1) rather than tee+chmod so the content and the 0440 mode land in one step; tee creates at the default umask first, and sudo refuses to read a sudoers file with loose permissions, so the old ordering had a window where sudo could reject its own configuration. The re-run guard also grepped for the username anywhere in the file, so a comment mentioning it counted as configured. Match the actual rule instead. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/setup.sh | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/scripts/setup.sh b/scripts/setup.sh index 8715496e..e243f704 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -271,14 +271,29 @@ echo "── Sudoers (Linux user isolation) ──" SERVICE_USER="$(whoami)" SUDOERS_FILE="/etc/sudoers.d/officer-service" -if [ -f "$SUDOERS_FILE" ] && grep -q "$SERVICE_USER" "$SUDOERS_FILE" 2>/dev/null; then +# Match the actual rule, not just the username appearing somewhere in the file — a comment mentioning +# the user would otherwise read as "configured". +if [ -f "$SUDOERS_FILE" ] && grep -qE "^${SERVICE_USER}[[:space:]]+ALL=" "$SUDOERS_FILE" 2>/dev/null; then skip "sudoers entry for $SERVICE_USER" else case $PM in apt|pacman) - echo "$SERVICE_USER ALL=(ALL) NOPASSWD: ALL" | sudo tee "$SUDOERS_FILE" > /dev/null - sudo chmod 0440 "$SUDOERS_FILE" - ok "Created sudoers entry for $SERVICE_USER at $SUDOERS_FILE" + # Validate BEFORE this lands in /etc/sudoers.d. A malformed file there breaks sudo COMPLETELY, + # and you cannot sudo to repair it — on a remote machine that is unrecoverable short of physical + # access or a rescue boot. `visudo -c` is the standard gate and costs nothing. + # + # install(1) rather than tee+chmod: it writes the content and the 0440 mode in one step. tee + # creates the file at the default umask first, and sudo refuses to read a sudoers file with + # loose permissions, so that ordering leaves a window where sudo can reject its own config. + SUDOERS_TMP="$(mktemp)" + echo "$SERVICE_USER ALL=(ALL) NOPASSWD: ALL" > "$SUDOERS_TMP" + if sudo visudo -c -f "$SUDOERS_TMP" >/dev/null 2>&1; then + sudo install -m 0440 -o root -g root "$SUDOERS_TMP" "$SUDOERS_FILE" + ok "Created sudoers entry for $SERVICE_USER at $SUDOERS_FILE" + else + fail "visudo rejected the sudoers entry for '$SERVICE_USER' — not installing it" + fi + rm -f "$SUDOERS_TMP" ;; brew) warn "Sudoers setup is Linux-only — skipping on macOS" @@ -624,9 +639,9 @@ if [ ! -f "$STARSHIP_DEST" ]; then cp "$SCRIPT_DIR/starship.toml" "$STARSHIP_DEST" ok "starship config deployed" elif cmp -s "$SCRIPT_DIR/starship.toml" "$STARSHIP_DEST"; then - skip "starship config (already current)" + skip "starship config" else - skip "starship config (yours differs — kept; cp scripts/starship.toml ~/.config/ to take this one)" + warn "starship config kept — yours differs (cp scripts/starship.toml ~/.config/ to take this one)" fi # Oh-My-Zsh