From b5ed8cad4d7864e0e2959c465127c1f24598dde8 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Sat, 23 May 2026 11:50:08 -0400 Subject: [PATCH] installer: slim finalizer bootstrap --- finalize.sh | 23 ++++-- test/offline-finalizer-bootstrap-test.sh | 92 +++++++++++++++++++----- 2 files changed, 90 insertions(+), 25 deletions(-) diff --git a/finalize.sh b/finalize.sh index 486cfddf..83eefc3d 100644 --- a/finalize.sh +++ b/finalize.sh @@ -1,10 +1,9 @@ #!/bin/bash # -# The in-target portion of an Omarchy install: package-level setup, system -# configuration, login wiring, post-install. Self-contained — works whether -# invoked by install.sh (online) or by the Python orchestrator (offline, via -# arch-chroot). The caller is responsible for system sanity checks (guards), -# UI styling, and log capture. +# The in-target portion of an Omarchy install. This is intentionally boring: +# the caller has already prepared the system; all this script does is run the +# target-side setup scripts. The ISO parent owns UI/error handling, while the +# online path re-establishes its tty-backed traps below. set -eEo pipefail @@ -14,11 +13,23 @@ export OMARCHY_INSTALL="${OMARCHY_INSTALL:-$_OMARCHY_INSTALLER_DIR/install}" export OMARCHY_INSTALL_LOG_FILE="${OMARCHY_INSTALL_LOG_FILE:-/var/log/omarchy-install.log}" export PATH="$_OMARCHY_INSTALLER_DIR/bin:$OMARCHY_PATH/bin:$PATH" +# Do not source helpers/all.sh here. That bundle unconditionally pulls in +# presentation and interactive error handling, both of which assume a +# controlling tty. The ISO runs this file through arch-chroot with +# stdout/stderr captured by the parent. Keep the offline bootstrap to the +# non-interactive primitives the scripts below use. source "$OMARCHY_INSTALL/helpers/mode.sh" detect_install_mode export_legacy_mode_flags +source "$OMARCHY_INSTALL/helpers/chroot.sh" +source "$OMARCHY_INSTALL/helpers/logging.sh" -source "$OMARCHY_INSTALL/helpers/all.sh" +# Online installs still run finalize.sh directly after install.sh execs it, so +# re-establish the interactive UI/error traps only for that tty-backed path. +if install_mode_is online; then + source "$OMARCHY_INSTALL/helpers/presentation.sh" + source "$OMARCHY_INSTALL/helpers/errors.sh" +fi # Mark every shipped migration as "done" so future updates only run the new # ones. Idempotent; safe to re-run. diff --git a/test/offline-finalizer-bootstrap-test.sh b/test/offline-finalizer-bootstrap-test.sh index 90b9cf4c..4b684b1c 100755 --- a/test/offline-finalizer-bootstrap-test.sh +++ b/test/offline-finalizer-bootstrap-test.sh @@ -1,36 +1,90 @@ #!/usr/bin/env bash -# Ensure the offline/chroot finalizer can source helpers with no controlling tty. +# Ensure the offline/chroot finalizer reaches target-side scripts with no +# controlling tty. This specifically protects against finalize.sh sourcing the +# interactive helper bundle (presentation/errors) before the parent can capture +# a useful failure. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +mkdir -p \ + "$TMP/install/helpers" \ + "$TMP/install/packaging" \ + "$TMP/install/config" \ + "$TMP/install/login" \ + "$TMP/install/post-install" \ + "$TMP/omarchy/migrations" \ + "$TMP/home" + +cp "$ROOT/install/helpers/mode.sh" "$TMP/install/helpers/" +cp "$ROOT/install/helpers/chroot.sh" "$TMP/install/helpers/" +cp "$ROOT/install/helpers/logging.sh" "$TMP/install/helpers/" + +cat >"$TMP/install/packaging/all.sh" <<'SCRIPT' +run_logged "$OMARCHY_INSTALL/packaging/marker.sh" +SCRIPT + +cat >"$TMP/install/packaging/marker.sh" <<'SCRIPT' +echo packaging-marker +SCRIPT + +cat >"$TMP/install/config/all.sh" <<'SCRIPT' +echo config-marker >>"$OMARCHY_INSTALL_LOG_FILE" +SCRIPT + +cat >"$TMP/install/login/all.sh" <<'SCRIPT' +install_mode_is offline +echo login-marker >>"$OMARCHY_INSTALL_LOG_FILE" +SCRIPT + +cat >"$TMP/install/post-install/all.sh" <<'SCRIPT' +stop_install_log +touch "$HOME/finalizer-completed" +SCRIPT + +if grep -Eq '^[[:space:]]*(source|\.)[[:space:]].*helpers/all\.sh' "$ROOT/finalize.sh"; then + echo "finalize.sh must not source helpers/all.sh" >&2 + exit 1 +fi output="$({ - setsid -w bash -c ' - set -eEo pipefail - export OMARCHY_INSTALL="$1/install" - export OMARCHY_PATH="${OMARCHY_TEST_OMARCHY_PATH:-/usr/share/omarchy}" - export OMARCHY_INSTALL_MODE=offline - export OMARCHY_CHROOT_FINALIZER=1 - export HOME="$(mktemp -d)" - export USER=ryan - - source "$OMARCHY_INSTALL/helpers/mode.sh" - detect_install_mode - export_legacy_mode_flags - source "$OMARCHY_INSTALL/helpers/all.sh" - echo helpers-loaded - ' bash "$ROOT" &1)" printf '%s\n' "$output" -if [[ $output != *helpers-loaded* ]]; then - echo "expected helpers-loaded marker" >&2 +if [[ ! -f "$TMP/home/finalizer-completed" ]]; then + echo "expected finalizer completion marker" >&2 + exit 1 +fi + +if ! grep -q 'packaging-marker' "$TMP/omarchy-install.log"; then + echo "expected run_logged script output in install log" >&2 + exit 1 +fi + +if ! grep -q 'login-marker' "$TMP/omarchy-install.log"; then + echo "expected sourced target scripts to run" >&2 exit 1 fi if [[ $output == *$'\033[?25h'* ]]; then - echo "offline finalizer helper bootstrap leaked cursor escape" >&2 + echo "offline finalizer leaked cursor escape" >&2 + exit 1 +fi + +if [[ $output == *'Inappropriate ioctl'* || $output == *'/dev/tty'* ]]; then + echo "offline finalizer attempted tty access" >&2 exit 1 fi