Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ Boot order is disk first: the empty disk falls through to the ISO on the first b

Encrypted autoinstalls are not fully unattended — the LUKS passphrase prompt still needs someone at the first boot.

## Install timing

The orchestrator times every phase on a monotonic clock and, when the install succeeds, writes the result to the target as `/var/log/omarchy-install-timing.json` and `/var/lib/omarchy/leaderboard/timing.json` (same bytes): a schema version, a run id minted before the first phase, the elapsed nanoseconds for the run, for each phase a stable id and its own elapsed nanoseconds, the ISO's identity (ref, mirror, offline database hash), the class the installer observed (full-disk or protected, encrypted, virtualised, page cache warmed) and a hardware sketch with nothing that identifies a person. The finish screen shows the run as a lap time, the same span it has always shown, as m:ss.mmm on both sides of the minute, and h:mm:ss.mmm from an hour, with the first eight characters of the run id beside it, so a photo of the screen can be matched to the file.

The document is sealed: an Ed25519 keypair is generated in the live environment after the last phase, `timing.sig` and `install.pub` land beside the document, and the private key is never written anywhere. Check a result with nothing but openssl:

```bash
openssl pkeyutl -verify -pubin -rawin -inkey install.pub -in timing.json -sigfile timing.sig
```

That makes the result tamper-evident, not true: a document and a keypair can be fabricated on any machine. Nothing here contacts a server; sharing a result is a separate, explicit step on the installed system. See `plans/install-leaderboard.md`.

## Testing the ISO

Run `./bin/omarchy-iso-boot [release/omarchy.iso]`.
Expand Down
6 changes: 6 additions & 0 deletions bin/omarchy-iso-installer
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ simulate_install() {
finished_at="$EPOCHREALTIME"
write_simulation_state "$state_file" "$started_at" "$finished_at" \
"Installation complete" "$target" "$(( total - 1 ))" "$total" "$finished_at"
# The orchestrator publishes the phase sum on a monotonic clock and a run
# id; the finish screen shows both, so the preview supplies them too.
jq --argjson ns "$(awk -v s="$started_at" -v f="$finished_at" 'BEGIN { printf "%d", (f - s) * 1000000000 }')" \
--arg run_id "$(cat /proc/sys/kernel/random/uuid)" \
'. + {total_elapsed_ns: $ns, run_id: $run_id}' "$state_file" >"$state_file.tmp"
mv -f -- "$state_file.tmp" "$state_file"
sleep 0.3
}

Expand Down
36 changes: 29 additions & 7 deletions configs/airootfs/usr/local/bin/omarchy-install-dashboard
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,26 @@ install_duration() {
local path line duration

if [[ -f $STATE_FILE ]]; then
# The orchestrator times the run on a monotonic clock and publishes it in
# nanoseconds; that is the lap time, shown the way a lap time is read
# anywhere in motorsport: m:ss.mmm, one shape whether the run took thirty
# seconds or six minutes, and h:mm:ss.mmm from an hour, the way endurance
# racing shows it. Older state files only carry wall-clock stamps and keep
# the m/s form.
duration="$(jq -r '
((.started_at // 0) | tonumber? // 0) as $started
| ((.finished_at // 0) | tonumber? // 0) as $finished
| if $started <= 0 or $finished <= 0 or $finished < $started then empty
else (($finished - $started) | round) as $secs
| if $secs >= 3600 then "\($secs / 3600 | floor)h \($secs % 3600 / 60 | floor)m \($secs % 60)s"
else "\($secs / 60 | floor)m \($secs % 60)s"
((.total_elapsed_ns // 0) | tonumber? // 0) as $ns
| if $ns > 0 then
($ns / 1000000 | floor) as $ms
| (if $ms >= 3600000 then "\($ms / 3600000 | floor):\(("0" + ($ms % 3600000 / 60000 | floor | tostring))[-2:])" else "\($ms / 60000 | floor)" end)
+ ":\(("0" + (($ms % 60000) / 1000 | floor | tostring))[-2:]).\(("00" + ($ms % 1000 | tostring))[-3:])"
else
((.started_at // 0) | tonumber? // 0) as $started
| ((.finished_at // 0) | tonumber? // 0) as $finished
| if $started <= 0 or $finished <= 0 or $finished < $started then empty
else (($finished - $started) | round) as $secs
| if $secs >= 3600 then "\($secs / 3600 | floor)h \($secs % 3600 / 60 | floor)m \($secs % 60)s"
else "\($secs / 60 | floor)m \($secs % 60)s"
end
end
end
' "$STATE_FILE" 2>/dev/null || true)"
Expand All @@ -492,10 +505,19 @@ install_duration() {
return 0
}

# The first eight characters of the run's id. A photo of this screen can be
# matched to a submitted result by it, which is the cheapest witness there is.
run_code() {
[[ -f $STATE_FILE ]] || return 0
jq -r '(.run_id // "") | .[0:8]' "$STATE_FILE" 2>/dev/null || true
}

render_finish() {
local duration effect_canvas_width
local duration effect_canvas_width code
duration="$(install_duration || true)"
duration="${duration:-Complete}"
code="$(run_code || true)"
[[ -n $code ]] && duration="${duration} ${DIM}#${code}${RESET}"
# ttfx centers its text two columns right of plain centering, so hand it a
# canvas two columns narrower and the animated logo lands exactly on the
# static one left_padding already drew. Otherwise the logo jumps a column
Expand Down
Loading