From 153b1273c3426ed1fcbae5baea7dff8cb630f575 Mon Sep 17 00:00:00 2001 From: Brandon Li Date: Sun, 13 Sep 2026 13:21:59 -0500 Subject: [PATCH] Refuse to run the Linux setup as root setup-linux.sh accepted being run as root and simply set SUDO="". That quietly broke everything user-scoped: PM2 keeps its process list in $HOME/.pm2 and the login entry goes in $HOME/.config/autostart, so under sudo both landed in /root. The install reported success, then `pm2 list` as the real user showed nothing - it was talking to a different daemon - and the autostart entry sat in a home directory that never logs in. Both scripts now refuse, and name the account to use when SUDO_USER says how they were invoked. setup-linux.sh still uses sudo for apt, which is the only part that needs it. Co-Authored-By: Claude Opus 5 --- scripts/install-autostart.sh | 10 ++++++++++ setup-linux.sh | 18 +++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/scripts/install-autostart.sh b/scripts/install-autostart.sh index d13325d..0a19dd7 100755 --- a/scripts/install-autostart.sh +++ b/scripts/install-autostart.sh @@ -31,6 +31,16 @@ done info() { printf ' %s\n' "$1"; } warn() { printf ' ! %s\n' "$1" >&2; } +# Same reason as setup-linux.sh: PM2's process list lives in $HOME/.pm2 and the +# login entry in $HOME/.config/autostart. As root both go to /root, invisible to +# the account that actually logs in. +if [ "$(id -u)" -eq 0 ]; then + echo " [X] do not run this as root${SUDO_USER:+ - run it as $SUDO_USER}." >&2 + echo " PM2 and the login entry are per-user; as root they land in /root" >&2 + echo " and your own 'pm2 list' will be empty." >&2 + exit 1 +fi + info "project root: $ROOT" # ── PM2 ───────────────────────────────────────────────────────────────────── diff --git a/setup-linux.sh b/setup-linux.sh index ed71eda..d8e3e16 100755 --- a/setup-linux.sh +++ b/setup-linux.sh @@ -29,12 +29,20 @@ echo # ── sudo ──────────────────────────────────────────────────────────────────── command -v apt-get >/dev/null 2>&1 || die "this script expects apt (Raspberry Pi OS, Debian, Ubuntu)" -SUDO="" -if [ "$(id -u)" -ne 0 ]; then - command -v sudo >/dev/null 2>&1 || die "not root and sudo is not installed" - SUDO="sudo" - info "some steps need sudo; you may be prompted" +# Must NOT run as root. Almost everything here is user-scoped: PM2 keeps its +# process list in $HOME/.pm2, and the login entry goes in $HOME/.config/autostart. +# Run under sudo and both land in /root - PM2 starts a daemon your own account +# cannot see, and the autostart entry sits in a home directory that never logs +# in. It looks like it worked, then `pm2 list` is empty. +if [ "$(id -u)" -eq 0 ]; then + if [ -n "${SUDO_USER:-}" ]; then + die "do not run this with sudo - run it as $SUDO_USER; it will ask for sudo only where it needs it" + fi + die "do not run this as root - run it as the user that will own the instance" fi +command -v sudo >/dev/null 2>&1 || die "sudo is required (for apt) and is not installed" +SUDO="sudo" +info "apt steps need sudo; you may be prompted" # ── system packages ───────────────────────────────────────────────────────── # xdotool raises the browser window (pygetwindow has no X11 backend, so the