#!/usr/bin/env bash # Panama's front door: the one command a fresh Fedora machine needs. # # bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) # bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server # # Deliberately dumb, because a copy of this script leaves the repository the # moment somebody curls it -- nothing here can be fixed by re-running # ./install, so there is as little here as possible: get git, get the clone, # hand off. Everything with judgment in it lives in `install`, which is also # where re-runs and upgrades already work. # # The one exception to dumb is the root path below, which cannot live in # `install`: a fresh VPS hands you a root login and nothing else, and the user # that `install` needs to exist is exactly what has not been created yet. set -euo pipefail REPO_URL="https://git.gbrown.org/gib/Panama.git" PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}" export PANAMA_PATH SERVER=0 INSTALL_ARGS=() for arg in "$@"; do case "$arg" in --server) SERVER=1; INSTALL_ARGS+=(--server) ;; *) printf 'boot: unknown argument: %s\n' "$arg" >&2 printf 'usage: boot [--server]\n' >&2 exit 2 ;; esac done # Panama assumes Fedora's repositories and package names. if ! grep -qi '^ID=fedora' /etc/os-release 2>/dev/null; then echo "This looks like something other than Fedora; Panama only supports Fedora." >&2 exit 1 fi # ── Root ───────────────────────────────────────────────────────────────────── # # On a desktop, root is a mistake: the clone and every dotfile would land in # root's home and configure the wrong user. On a fresh VPS it is the starting # condition -- Hetzner hands over a root login and nothing else -- so with # --server this walks the machine from that to a normal Panama install: a # user with sudo, keys, an optionally hardened sshd, and `install --server` # running as that user. Every step checks before acting, because the machine # may be anywhere along this path already: a user half-created by hand, keys # already copied, sshd already locked down. if [[ "$(id -u)" -eq 0 ]]; then if (( ! SERVER )); then echo "Run this as your own user, not root: the install configures YOUR desktop." >&2 echo "Setting up a fresh server from its root login is: boot --server" >&2 exit 1 fi # Everything here asks, and a root shell from `bash <(curl ...)` can have # the pipe as stdin, so every prompt reads the terminal explicitly. if ! (exec /dev/null; then echo "No terminal to ask on; run this from an interactive root shell." >&2 exit 1 fi printf 'Username for this server [gib]: ' read -r username /dev/null 2>&1; then echo "User $username already exists" # wheel is what makes sudo work on Fedora; a user created by hand may not # have it, and everything after this depends on it. id -nG "$username" | grep -qw wheel || usermod -aG wheel "$username" else echo "Creating $username with sudo (wheel)" useradd -m -G wheel "$username" fi # useradd leaves the account locked, and sudo asks for this password -- a # user who cannot sudo is a user the install cannot run as. if ! passwd -S "$username" 2>/dev/null | awk '{exit $2 != "PS" && $2 != "P"}'; then echo "Set a password for $username (sudo will ask for it):" passwd "$username" "$SSHD_DROPIN" systemctl reload sshd 2>/dev/null || systemctl reload ssh 2>/dev/null || true echo "Wrote $SSHD_DROPIN; make sure your key works before logging out." fi fi if ! command -v git >/dev/null 2>&1; then echo "Installing git, which the clone needs" dnf install -y git fi # Cloned straight into the user's home and owned by them: this is the # checkout `panama update` will pull from for the life of the machine, and # a root-owned .git in a user's home is a wound that never heals. PANAMA_PATH="$user_home/.local/share/Panama" if [[ -d "$PANAMA_PATH/.git" ]]; then echo "Panama is already cloned at $PANAMA_PATH; updating" runuser -u "$username" -- git -C "$PANAMA_PATH" pull --ff-only \ || echo "Could not fast-forward; installing from the clone as it is" >&2 else runuser -u "$username" -- mkdir -p "$user_home/.local/share" runuser -u "$username" -- git clone "$REPO_URL" "$PANAMA_PATH" fi echo "Handing off to install as $username" exec runuser -u "$username" -- env PANAMA_PATH="$PANAMA_PATH" \ "$PANAMA_PATH/install" --server /dev/null 2>&1; then echo "Installing git, which the clone needs" sudo dnf install -y git fi if [[ -d "$PANAMA_PATH/.git" ]]; then # An existing clone makes this the recovery command too. Only a fast-forward: # local work is never rewritten, and a diverged clone still installs from # what it has rather than stopping someone mid-repair. echo "Panama is already cloned at $PANAMA_PATH; updating" git -C "$PANAMA_PATH" pull --ff-only \ || echo "Could not fast-forward; installing from the clone as it is" >&2 else git clone "$REPO_URL" "$PANAMA_PATH" fi # `curl | bash` and `bash <(curl ...)` can leave stdin as the pipe, and the # first thing install runs is the interview, which has to be able to ask. # Reattach the terminal when there is one; without one the interview will say # so itself. # The probe actually opens /dev/tty rather than testing -r: a process with no # controlling terminal passes -r and then fails the redirect. if [[ ! -t 0 ]] && (exec /dev/null; then exec "$PANAMA_PATH/install" ${INSTALL_ARGS[@]+"${INSTALL_ARGS[@]}"}