Confirm the Start Omarchy Now prompt after provisioning setup (#100)

* Confirm the Start Omarchy Now prompt after provisioning setup

First-boot account setup now ends on a celebration screen whose Start
Omarchy Now button gates the SDDM handoff, so the provisioning test
must press it — same as the installer's Reboot Now prompt — once the
pending flag clears.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add a centered greeter before the installer keyboard step

Open the ISO configurator with the same greeter the deferred-provisioning
first boot uses — vertically centered logo, the Omarchy tagline, and a
single button — so install and first boot bookend setup identically. The
installer's button reads "Start install"; first boot's reads "Start setup".

Co-Authored-By: Claude <noreply@anthropic.com>

* Animate the installer greeter logo with a skippable ColorShift

Match the first-boot greeter: a looping tte ColorShift over the centered
logo with a "Press Return to Start Install" hint instead of a button.
Return begins the install at any time.

Co-Authored-By: Claude <noreply@anthropic.com>

* Theme the installer greeter ColorShift to the Omarchy palette

Match the first-boot greeter: sweep the logo ColorShift through the
Tokyo Night accent colors instead of tte's default rainbow.

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix installer greeter ColorShift: green base, no flash, clean handoff

Mirror the first-boot greeter fixes: indexed ANSI colors (green base with
a cyan accent) because the framebuffer console can't render tte truecolor;
one long tte invocation so the loop never flashes; stty sane + clear after
Return so the keyboard step starts clean.

Co-Authored-By: Claude <noreply@anthropic.com>

* Dismiss the greeter in the QEMU test drivers

The installer and first-boot flows now open with a greeter (animated logo
+ tagline). Wait for the tagline and press Return before the keyboard
step, in both drive paths, so the harness gets past the greeter.

Co-Authored-By: Claude <noreply@anthropic.com>

* Kill the installer greeter animation cleanly

Run tte directly instead of inside a backgrounded `while` subshell, so
killing the tracked PID actually stops the effect. Killing the subshell
orphaned tte, which kept painting the logo over the keyboard step.

Co-Authored-By: Claude <noreply@anthropic.com>

* Guard the greeter wait against set -e in the configurator too

Harmless today (no set -e), but keeps the greeter's animation teardown
robust if that changes.

Co-Authored-By: Claude <noreply@anthropic.com>

* Also settle the terminal in emulators, not just real VTs

wait_for_stable_terminal skipped terminal emulators on the assumption
they're already at final size, but a fresh terminal (or sudo's pty)
reports a stale 24x80 for a moment at startup too. Drop the VT-only gate
so the greeter centers there as well.

Co-Authored-By: Claude <noreply@anthropic.com>

* Test harness: drive the first-boot timezone step and direct SDDM handoff

Match the deferred-provisioning first-boot flow changes: the owner now picks
a timezone after the email step, and setup hands straight off to SDDM instead
of pausing on a celebration screen with a Start Omarchy Now button. Drive the
new Timezone screen (accept the geo-guessed default) and drop the button
confirmation.

Co-Authored-By: Claude <noreply@anthropic.com>

* Don't bake hostname/timezone into deferred installs; set them at first boot

Deferred provisioning defers the user step to first boot, so the machine's
owner should name the machine and pick the timezone there — not inherit values
chosen at install time. Stop setting hostname/timezone in the configurator's
deferred branch: the orchestrator already skips an empty timezone (the system
stays UTC until first boot), and it now falls back to a neutral "archlinux"
hostname for the install so archinstall still succeeds. The first-boot
omarchy-provision-owner form collects and applies both.

Harness: drive the new Hostname screen and assert both hostname and timezone
actually landed on the running system after first boot.

Co-Authored-By: Claude <noreply@anthropic.com>

* Match the installer greeter: solid green logo, no color animation

Same fix as the first-boot greeter — tte's ColorShift judders on the 16-color
framebuffer console (truecolor crush). Show the logo in solid green and drop
the animation so both greeters look identical and flash-free.

Co-Authored-By: Claude <noreply@anthropic.com>

* Harden the provision harness: SSH-blip wait, timezone timeout, hostname assert

- The pending-flag wait treated an SSH connection failure (rc 255) the same as
  "flag absent" (rc 1), so a transient blip during finalization would exit early
  and snapshot the base mid-finalization. Only break on a clean rc 1; keep
  waiting on 0 or 255.
- Bump the first-boot Timezone screen wait 60s -> 180s (tzupdate geo-guess over
  first-boot networking can lag; matches the installer's headroom).
- Make the applied-hostname check a hard failure (it's deterministic — we typed
  it), so a first-boot apply regression can't pass green; timezone stays a
  report since it's geo-guessed.

Co-Authored-By: Claude <noreply@anthropic.com>

* Seed hostname=omarchy/timezone=UTC in deferred install instead of empties

Write neutral valid defaults in the configurator's deferred branch rather than
empty strings, and drop the orchestrator's `config.hostname or "archlinux"`
fallback (hostname is always non-empty now). The first-boot wizard overwrites
both. This keeps the "owner sets them at first boot" behavior without depending
on archinstall tolerating empty hostname/timezone at config-load time.

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix set -e regression in the provision pending-wait loop

The previous hardening moved `ssh_guest "test -f pending"` out of the `while`
condition into a standalone command, but the harness runs `set -euo pipefail` —
so the moment the flag cleared (ssh returns 1, the intended "done" signal) it
tripped errexit and aborted the whole run right after provisioning, before the
session/acceptance phase. Capture the result with `|| rc=$?` so the non-zero is
the signal, not a fatal error. Also guard the follow-on hostname/timezone
substitutions with `|| got=""` so a transient SSH failure there can't abort
either (an empty value then correctly fails the hostname assertion).

Co-Authored-By: Claude <noreply@anthropic.com>

* Bring back the installer greeter ColorShift animation

Match the first-boot greeter: restore the static green logo + looping tte
ColorShift overlay. The framebuffer truecolor crush gives it a quick flash,
which is acceptable — both greeters keep the animation.

Co-Authored-By: Claude <noreply@anthropic.com>

* Skip the install celebration on deferred installs; reboot directly

A deferred-provisioning install has nothing to celebrate yet — the owner
finishes setup (and gets the send-off) at first boot. So the installer's
"Installed Omarchy in ..." screen and the Reboot Now prompt now belong to a
direct install only: for a deferred install the dashboard clears and reboots on
its own. .automated_script.sh detects deferred mode (the config's
defer_provisioning flag, or the cidata defer-provisioning marker) and passes
OMARCHY_UI_DEFER_PROVISIONING to the dashboard.

Harness: a deferred install no longer shows Reboot Now, so wait_for_install
recognizes the auto-reboot by the first-boot greeter tagline appearing.

Co-Authored-By: Claude <noreply@anthropic.com>

* Detect deferred mode with jq, not a line regex

The dashboard's deferred detection grepped user_configuration.json for the
defer_provisioning boolean on one line; a reformatted config would read as a
direct install and wrongly show the celebration. Parse it with jq using the
same path the orchestrator reads (.omarchy_install.defer_provisioning).

Co-Authored-By: Claude <noreply@anthropic.com>

* Drop Bosnian and Khmer from the installer keyboard picker

Match the first-boot picker: neither has a console keymap, so both silently
fell back to US. Remove them rather than offer a layout that can't apply.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
David Heinemeier HanssonandClaude authored and GitHub committed 2026-08-09 21:56:01 +02:00
1 parent 81de5087ea
commit f32247afc3
4 files changed
+172 -15

No files matched your search

+68 -6
View File
@@ -606,6 +606,11 @@ audio-panel|meta_l-ctrl-a|omarchy-keyboard-panel|omarchy.audio'
drive_configurator() {
log "Driving the installer wizard"
# A greeter (animated logo + tagline) opens the installer; Return begins.
wait_for_screen "Opinionated" 300
capture_console "success-installer-00-greeter"
press ret
# Keyboard is the first screen. Ctrl+C there is the hidden entry into deferred provisioning
# mode; a normal install just selects the layout.
wait_for_screen "keyboard layout" 300
@@ -710,7 +715,12 @@ drive_provision_owner() {
# verifier can prove the deferred step applied a non-default layout — UK
# leaves every letter identical to US, so the typed password (sent as raw
# keycodes) still matches the literal one the harness pipes to sudo.
wait_for_screen "keyboard layout" 600
# A greeter (animated logo + tagline) opens first boot; Return begins.
wait_for_screen "Opinionated" 600
capture_console "success-provision-00-greeter"
press ret
wait_for_screen "keyboard layout" 120
press up
capture_console "success-provision-01-keyboard-layout-uk"
press ret
@@ -743,13 +753,25 @@ drive_provision_owner() {
capture_console "success-provision-04-email"
press ret
# Hostname is deferred to first boot too.
wait_for_screen "Hostname" 60
type_text "$GUEST_HOSTNAME"
capture_console "success-provision-05-hostname"
press ret
# Timezone is deferred to first boot too; accept the geo-guessed default.
# Generous timeout: the tzupdate geo-guess over first-boot networking can lag.
wait_for_screen "Timezone" 180
capture_console "success-provision-06-timezone"
press ret
wait_for_screen "look right" 60
capture_console "success-provision-05-review"
capture_console "success-provision-07-review"
press ret
# Finalization (offline Node unpack, LUKS re-key on encrypted installs)
# runs before SDDM appears.
capture_console "success-provision-06-finalizing"
capture_console "success-provision-08-finalizing"
}
wait_for_install() {
@@ -766,6 +788,15 @@ wait_for_install() {
return 0
fi
# Deferred-provisioning installs skip the celebration and reboot on their own
# (no Reboot Now prompt); the first-boot greeter tagline appearing means the
# install finished and rebooted into setup.
if $PROVISION && grep -qi "Opinionated" <<<"$text"; then
log "Install finished and auto-rebooted into first-boot setup."
capture_console "success-installer-15-autoreboot"
return 0
fi
if grep -qi "installation stopped" <<<"$text"; then
capture_console "failure-installer-installation-stopped"
echo "Install failed — screenshot saved to $RUN_DIR" >&2
@@ -965,8 +996,17 @@ install_phase() {
# flag to clear before powering off.
if $PROVISION; then
log "Waiting for provisioning first-boot setup to finish"
local waited=0
while ssh_guest "test -f /var/lib/omarchy/provisioning/pending" 2>/dev/null; do
local waited=0 rc
while true; do
# Capture rc via `|| rc=$?` so a non-zero result doesn't trip `set -e`
# (this command is intentionally allowed to "fail" — that's the signal).
rc=0
ssh_guest "test -f /var/lib/omarchy/provisioning/pending" 2>/dev/null || rc=$?
# rc 0 = flag still present; rc 255 = SSH not up yet (finalization may
# still be running) — keep waiting. Only a clean "file absent" (rc 1)
# means provisioning finished, so we don't snapshot mid-finalization on a
# transient SSH blip.
(( rc == 0 || rc == 255 )) || break
if ((waited >= 900)); then
capture_console "failure-provision-finalization-timeout"
echo "Timed out waiting for provisioning first-boot setup to complete" >&2
@@ -975,7 +1015,29 @@ install_phase() {
sleep 10
((waited += 10))
done
capture_console "success-provision-06-setup-complete"
# The owner's hostname and timezone are set at first boot now, not baked
# into the install — confirm they actually landed on the running system.
# Hostname is deterministic (we typed it), so a mismatch is a hard failure;
# timezone is geo-guessed, so just report what landed.
local got_host="" got_tz=""
got_host=$(ssh_guest "cat /etc/hostname" 2>/dev/null | tr -d '\r\n') || got_host=""
got_tz=$(ssh_guest "timedatectl show -p Timezone --value" 2>/dev/null | tr -d '\r\n') || got_tz=""
if [[ $got_host != "$GUEST_HOSTNAME" ]]; then
capture_console "failure-provision-hostname-not-applied"
echo "First-boot hostname is '${got_host:-<empty>}', expected '$GUEST_HOSTNAME'" >&2
return 1
fi
log "hostname applied at first boot: $got_host"
if [[ -n $got_tz && $got_tz != "UTC" ]]; then
log "timezone applied at first boot: $got_tz"
else
echo "WARN: timezone is '${got_tz:-<empty>}' (expected the owner's choice, not UTC)" >&2
fi
# Deferred first-boot setup hands straight off to SDDM once the oneshot
# service exits — no celebration screen, no Start Omarchy button to confirm.
capture_console "success-provision-09-handoff"
fi
ssh_guest "echo $GUEST_PASSWORD | sudo -S cat /var/log/omarchy-install-timing.json 2>/dev/null" \