Commit Graph
9 Commits
Author SHA1 Message Date
Kros DaiandClaude Opus 5.5 27b7e76c5a 🐛 fix(build): read region profiles from settings package
- 🐛 default/ ships in omarchy-settings, so published builds silently bundled no regions
- ✅ cover the published package path, a package without profiles, and an unreadable one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuATgjU4mnqpqSLAKMQ14g
2026-10-08 15:32:46 -04:00
Kros DaiandClaude Opus 5.5 e121561851 ✨ feat(install): pick the region from the timezone
- ✨ the timezone the user already chose selects the region, so no new prompt is needed
- 🔒 populate only the selected region's keys so global installs never trust them
- ✅ cover the mapping, autoinstall override, marker, keyring setup, and builder staging

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuATgjU4mnqpqSLAKMQ14g
2026-10-08 15:03:31 -04:00
David Heinemeier Hansson 595d38cb04 Carry installer input-method selection into the target (#237)
Install test / install (push) Failing after 13s
Unit tests / unit (push) Failing after 17s
* Carry the installer input-method choice into the target

* Support Archinstall 4.5 sanity checks

* Constrain VM keyboard choices to supported credential layouts

* Cover VM keyboard offsets and reject absent choices
2026-10-07 21:21:55 +02:00
Ryan Hughes 1daf1202d4 Install and validate matching kernel headers in the ISO 2026-09-15 00:06:40 -04:00
Ryan Hughes b507a20b7e Install linux-omarchy by default except on T2 Macs 2026-09-14 18:45:34 -04:00
OmarchybotandCodex XHigh 268bac16d3 Name the install medium when pacstrap rejects a package off it (#120)
* Name the install medium when pacstrap rejects a package off it

A failed install showed "Omarchy installation stopped", the pacstrap error, a log tail, and a link to Discord. Somewhere in that tail was the whole answer -- pacman rejecting a package as corrupt -- and nothing on the screen connected it to the USB stick it came off.

Nothing else can put it there. The offline mirror is bind-mounted onto the target's package cache for the duration of pacstrap, so a package rejected under that path was read straight off the medium; nothing else ever writes there. That is worth saying in the words that name the fix rather than leaving it as a package name nobody recognises.

Which way the medium failed is a separate question, and usually unanswerable after the fact: pacstrap runs with --noconfirm, which answers yes to pacman's "delete it?", so the evidence is unlinked through the bind mount before anything can weigh it. The usual verdict therefore names the medium and gives both remedies in the order worth trying -- verify the download first, because it is cheap and rules out the common case. When the package does survive, the sha256 repo-add recorded at build time separates a bad write from a bad read, and the wording follows.

Co-Authored-By: Codex XHigh <codex@openai.com>

* Keep the media diagnosis whole and print it once

Two things only visible by looking at the rendered screen.

The diagnosis was recorded in the support log before the failure screen was drawn, and the log tail on that screen reads the same file -- so the verdict appeared twice, once as the banner and again eight lines below it. The same finding printed twice reads as two findings. It is recorded after the render now, and the tail carries the installer's own output the way it did before.

The package name shared a line with the sentence explaining it, and the screen is only as wide as the logo. npth's name already pushed the mismatch wording past the edge, and a firmware package would have taken the whole sentence with it. Every verdict puts the name on a line of its own, and the test walks all three with a sixty-three character package name to keep them there.

Co-Authored-By: Codex XHigh <codex@openai.com>

* Break the media diagnosis between what happened and what to do

The package name and the remedy beneath it ran together as one block, so the line telling someone to verify their download read as another clause about the package rather than the first thing to go and do. A blank line separates them in all three verdicts.

The renderer dropped blank lines, on the assumption that any it saw were slack rather than shape, so the break is drawn now instead of skipped.

* Give the log tail back the rows the diagnosis spends

The tail sizes itself from the terminal height less a constant for everything drawn above it, and the diagnosis is seven rows that constant never knew about. On a forty-row console the failure screen came to forty-one and scrolled its own logo off the top. The tail is the part that should give way, so it is told what was spent above it.

The test that came with this first asserted the logo was still on screen, which it cannot: it reads the output stream, and the stream keeps every row ever emitted whether or not it stayed visible. It passed with the fix reverted. It checks the mechanism instead -- a tail that reaches fewer lines of the log when a diagnosis is present -- against two logs identical line for line but for the one path that decides whether there is a diagnosis at all.

---------

Co-authored-by: Codex XHigh <codex@openai.com>
2026-08-23 21:20:13 +02:00
OmarchybotandCodex XHigh 6d02625f7f Publish a checksum beside every released ISO (#119)
The release script computed the ISO's sha256 and echoed it to the releaser's terminal, where nobody downloading the ISO could ever see it, and the uploader shipped the ISO and its signature but nothing to check the download against. So "verify your download" was not advice anyone could act on.

That matters more for this ISO than for most. The offline pacman mirror lives inside the airootfs and is stored uncompressed, and the installer bind-mounts it onto the target's package cache, so pacstrap reads packages straight off the medium. A flipped block there meets no decompressor and no squashfs block checksum on the way; pacman's integrity check is the first thing in the chain to notice, minutes into the install, as "invalid or corrupted package" against a package name that says nothing about the download.

The sidecar names the ISO alone rather than the build path, so it verifies from whatever directory it was downloaded into. A release that cannot write it stops, because the sidecar left over from the previous release reads as a checksum for this one. The uploader now tallies every copy instead of letting the last one decide the exit status, and warns when there is no checksum to publish.

Co-authored-by: Codex XHigh <codex@openai.com>
2026-08-23 12:59:32 +02:00
OmarchybotandCodex XHigh df80b320cb Stop the install dying on non-UTF-8 command output (#118)
* Stop the install dying on non-UTF-8 command output

efibootmgr prints what firmware gave it, and an HP ProBook's NVRAM held a legacy BBS entry whose device path was raw binary. `_read_efibootmgr` captured that with `text=True`, so Python decoded it strictly and a byte in a boot entry nothing here reads killed the whole "Installing Arch + Omarchy" phase. Two machines have hit it now, on 0x80 and 0xe0.

Every text capture in the orchestrator had the same exposure — partition labels reach lsblk and blkid the same way firmware strings reach efibootmgr — so they all go through one `capture()` that replaces what it cannot decode. The file reads here already did this; the command reads were the gap.

Replacing bytes has its own failure mode, and it is worse than the crash: a mangled UUID would be written into fstab and the kernel cmdline, and `_validate_pre_mounted_filesystems` reads it back from the same command, agrees with itself, and ships a machine that cannot find its root. So `require_text()` refuses a value the installed system depends on — UUIDs, device names, the btrfs device handed to mount — while the boot-entry labels stay tolerant on purpose: the decisions taken from those are advisory, and refusing a junk one would abort the install this change exists to let finish.

The regression test runs a stand-in efibootmgr emitting the reported byte sequence, so it exercises the decode rather than a mock. test_keyboard.py loads the module through the package now that keyboard.py imports a sibling.

Closes #116

🤖 Generated by Opus 5 in Claude Code. Reviewed by Codex XHigh.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Say accurately why the boot-entry parsing stays tolerant

The previous commit called the decisions taken from a firmware label "advisory". They are not: a label match selects entries for deletion and rewrites the boot order, and a missing one aborts validation. Staying tolerant is still right, for a reason the comment did not give — an entry's text is its label and its device path together, the junk lives in the path, and nothing mangled reaches efibootmgr from there anyway, since only four-digit ASCII boot numbers become arguments and a boot order is filtered through the entries that parsed. A label that loses a byte costs a stale entry left behind, not a broken system.

The test docstring credited one machine with a fixture that carries the bytes from two.

Co-Authored-By: Codex XHigh <noreply@openai.com>

---------

Co-authored-by: Codex XHigh <noreply@openai.com>
2026-08-23 12:57:03 +02:00
David Heinemeier HanssonandClaude Fable 5 0c1333837f Add an integration test suite that boots ISO scenarios in QEMU (#109)
* Move the unit tests under test/unit

test/ is growing an integration suite; the fast, VM-free tests get their
own directory so the two kinds cannot be confused. test/all keeps its
role as the aggregate runner for everything that needs no built ISO.

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

* Add an integration suite that boots ISO scenarios in QEMU

test/integration installs an ISO once — unattended, from a generated
cidata drive — and saves a reusable base image; each scenario in
test/integration.d/ then boots a throwaway overlay with its own copy of
the firmware vars. Shared machinery (VM lifecycle, QMP screendump + OCR
console driving, virtual keystrokes, guest SSH, the cidata build) lives
in base-test.sh, so a new scenario is one file.

The first scenario proves omarchy-system-factory-reset hands a machine
on without destroying a shared ESP: a Windows entry and a foreign Linux
with its own machine-id, boot directory, and UKIs must survive both the
staged reset and the first-boot provisioning that follows.

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

* Let omarchy-iso-make keep the host package cache

Purging /var/cache/pacman/pkg needs interactive sudo, which blocks
unattended builds. --keep-pkg-cache skips the purge so test rigs and
agents can build an ISO without a prompt.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 18:35:24 +02:00