Skip to content
Merged
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
4 changes: 2 additions & 2 deletions docs/image-producer.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ Candidate set, as the importer accepts it:
Build order inside the container:

1. A base system and `omarchy-settings`, alone, so its pacman platform guard (omacom/omarchy-mac#539) is resident before any platform package.
2. The root-owned image-target manifest `/var/lib/omarchy/image/target` (`format=1`, `platform=apple-silicon`), which deferred hardware setup (omacom/omarchy-mac#528) and the pacman platform guard (#539) both read. It also records `candidate_set`, `candidate_source_commit`, `builder_commit`, `builder_tree_clean` and `image_profile` (`lab` for `--lab-access`, `test` for a candidate-only set, else `release`), which the runtime ignores; after first boot the file is `target.booted`, so a booted Mac names the image it came from. Once the package set is recorded (step 5), the builder appends `package_set_sha256` and `built` (UTC, `YYYY-MM-DDTHH:MM:SSZ`), the values `IMAGE` and `PROVENANCE` record, before `@factory` is sealed, so a hardware report maps to one build's release assets (`image-builder/README.md`, Build identity). The image's own sha256 is not in it (root.img holds the file): `IMAGE`, `PROVENANCE` and the catalog carry it.
3. The runtime with `omarchy-base.packages`, then the Apple set: `omarchy-apple-silicon.packages` (an older runtime's `omarchy-apple.packages`), the kernel, m1n1, U-Boot and the Limine hook, plus `alsa-ucm-conf-asahi` and `asahi-audio` from the pinned asahi-alarm database. Every candidate set package is installed by its `omarchy-candidates/` name, so `[asahi-alarm]`, ordered before `[omarchy]` in the Apple profile, cannot supply `uboot-asahi` or `m1n1`.
2. The root-owned image-target manifest `/var/lib/omarchy/image/target` (`format=1`, `platform=apple-silicon`: upstream's platform is now `aarch64-apple`, but the runtime still reads `apple-silicon` and an older runtime (omacom/omarchy `5397950a2`) refuses `aarch64-apple`), which deferred hardware setup (omacom/omarchy-mac#528) and the pacman platform guard (#539) both read. It also records `candidate_set`, `candidate_source_commit`, `builder_commit`, `builder_tree_clean` and `image_profile` (`lab` for `--lab-access`, `test` for a candidate-only set, else `release`), which the runtime ignores; after first boot the file is `target.booted`, so a booted Mac names the image it came from. Once the package set is recorded (step 5), the builder appends `package_set_sha256` and `built` (UTC, `YYYY-MM-DDTHH:MM:SSZ`), the values `IMAGE` and `PROVENANCE` record, before `@factory` is sealed, so a hardware report maps to one build's release assets (`image-builder/README.md`, Build identity). The image's own sha256 is not in it (root.img holds the file): `IMAGE`, `PROVENANCE` and the catalog carry it.
3. The runtime with `omarchy-base.packages` and `omarchy-aarch64.packages` (when the runtime ships it), then the Apple set: `omarchy-aarch64-apple.packages` (an older runtime's `omarchy-apple-silicon.packages` or `omarchy-apple.packages`), the kernel, m1n1, U-Boot and the Limine hook, plus `alsa-ucm-conf-asahi` and `asahi-audio` from the pinned asahi-alarm database. Every candidate set package is installed by its `omarchy-candidates/` name, so `[asahi-alarm]`, ordered before `[omarchy]` in the Apple profile, cannot supply `uboot-asahi` or `m1n1`.
4. The runtime's `omarchy-apply-system --defer-provisioning --first-install`. The build chroot never sees the build host's hardware: a device tree naming the image's platform, UEFI without EFI variables, no PCI, USB, input or DMI devices. The host kernel must run with a device tree for the image's platform checks to find one. A runtime with #528 queues its hardware steps for first boot from the manifest; the first candidate set's runtime (`073e489b5`) predates it and runs them here, and its first boot runs only the Limine leaf (`mac-first-boot/deferred-steps`).
5. The image's GRUB defaults (the Limine command line's source, with `plymouth.ignore-serial-consoles` as on mx-mac) and Plymouth's `omarchy` theme, presets (`80-omarchy-mac*.preset`, so omarchy-mac's audio preset too), Node.js for owner provisioning, `mkinitcpio -P`, GRUB, `update-m1n1` under `LC_ALL=C`, the runtime's GRUB compatibility and Limine leaves, and first boot armed by the boot package's own `arm` command.
6. Seal (snapper's `/.snapshots` stays a btrfs subvolume through the copy), inspect, package. `PROVENANCE` and `IMAGE` record the builder commit, the set's receipt, manifest, source commit and signer, each installed package's repository and archive sha256, `package_set_sha256`, and `built`, the UTC time the build recorded its identity in the image-target manifest (the same `package_set_sha256` and `built` the manifest carries).
Expand Down
4 changes: 2 additions & 2 deletions image-builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A build takes about 15 minutes and 25 GB of disk. On a host with a desktop sessi

## What a build does

1. Installs a base system and `omarchy-settings` first, so its pacman platform guard is resident, then writes the root-owned image-target manifest (`/var/lib/omarchy/image/target`: `format=1`, `platform=apple-silicon`, read by deferred hardware setup and the platform guard, then the image's provenance, which the runtime ignores: `candidate_set`, `candidate_source_commit`, `builder_commit`, `builder_tree_clean` and `image_profile` of `lab`, `test` for a candidate-only set, or `release`), then installs the runtime with `omarchy-base.packages` and `omarchy-aarch64.packages` (as `omarchy-pkg-defaults apple-silicon` composes them) and, last, the Apple set: the runtime's Apple list (`omarchy-apple-silicon.packages`, or an older runtime's `omarchy-apple.packages`; a runtime with neither stops the build), the Aurora kernel, m1n1, U-Boot, the Limine hook, and the speaker stack's model profiles and DSP chain (`alsa-ucm-conf-asahi`, `asahi-audio`), which the runtime's audio step would otherwise fetch on a first boot that may have no network. Set packages are installed by their `omarchy-candidates/` name, so no other repository can supply them. Base names the pinned repositories lack are recorded as `unavailable=` in `PROVENANCE`.
1. Installs a base system and `omarchy-settings` first, so its pacman platform guard is resident, then writes the root-owned image-target manifest (`/var/lib/omarchy/image/target`: `format=1`, `platform=apple-silicon`, read by deferred hardware setup and the platform guard; upstream's platform is now `aarch64-apple`, but omacom/omarchy e1b0e5e9b still reads `apple-silicon` and an older runtime (5397950a2) refuses `aarch64-apple`, then the image's provenance, which the runtime ignores: `candidate_set`, `candidate_source_commit`, `builder_commit`, `builder_tree_clean` and `image_profile` of `lab`, `test` for a candidate-only set, or `release`), then installs the runtime with `omarchy-base.packages` and `omarchy-aarch64.packages` (as `omarchy-pkg-defaults aarch64-apple` composes them; `apple-silicon` on an older runtime) and, last, the Apple set: the runtime's Apple list (`omarchy-aarch64-apple.packages`, or an older runtime's `omarchy-apple-silicon.packages` or `omarchy-apple.packages`; a runtime with none stops the build), the Aurora kernel, m1n1, U-Boot, the Limine hook, and the speaker stack's model profiles and DSP chain (`alsa-ucm-conf-asahi`, `asahi-audio`), which the runtime's audio step would otherwise fetch on a first boot that may have no network. Set packages are installed by their `omarchy-candidates/` name, so no other repository can supply them. Base names the pinned repositories lack are recorded as `unavailable=` in `PROVENANCE`.
2. Runs the runtime's own `omarchy-apply-system --defer-provisioning --first-install` in an isolated chroot. The chroot never sees the build host's hardware: its device tree names the image's platform, it has UEFI (as U-Boot provides) without EFI variables, and no PCI, USB, input or DMI devices, so hardware setup installs the same packages on any aarch64 host whose kernel runs with a device tree (an Apple Silicon Mac, most arm64 boards; on an ACPI-only host the image's platform checks find no device tree and the build stops at the Limine activation). A runtime with deferred hardware setup (omacom/omarchy-mac#528) queues its hardware steps from the manifest; an older one runs them here for the image's platform.
3. Sets the kernel command line in `/etc/default/grub`, which the Limine command line is derived from; the image installs no GRUB (`quiet splash`, and `plymouth.ignore-serial-consoles` as on mx-mac, since the Mac's device tree registers a serial console), and Plymouth's `omarchy` theme, which omarchy-settings leaves to Arch Linux ARM's `bgrt` on Apple Silicon. Applies the Apple presets (`80-omarchy-mac*.preset`, including omarchy-mac's audio preset), stages owner provisioning with the pinned Node.js, rebuilds the initramfs, runs `update-m1n1` with `LC_ALL=C` so the device trees go into m1n1's stage 2 in one order, activates Limine through omarchy-mac-boot's `setup-boot` operation of the runtime's lifecycle dispatcher (once before the Limine gate is set, for the console settings, and once after, for the activation; a runtime whose dispatcher has no `setup-boot`, or a boot package without it, keeps the runtime's own `install/hardware/apple` console and Limine leaves), and arms first boot with the boot package's own `arm` command. Once the installed package set is recorded, it appends the build's identity to the image-target manifest (see [Build identity](#build-identity)).
4. Copies the root into a fresh image, keeping snapper's `/.snapshots` a btrfs subvolume (a file copy would flatten it into a plain directory and snapper would fail on the Mac), seals a snapshot of it into `@factory`, then inspects the images against the set's archives and packages them.
Expand All @@ -40,7 +40,7 @@ A build takes about 15 minutes and 25 GB of disk. On a host with a desktop sessi
- the pacman hooks that rebuild the UKI and redeploy Limine come from their packages, the Apple gate included
- the image-target manifest (its provenance matching the set, the build's profile and `@factory`'s copy; `mac-image-check provenance` matches it to `PROVENANCE`), first boot, owner provisioning, the Limine gate and the fresh-image `deferred-steps` contract; the hardware queue never runs an older runtime's `install/hardware/apple/pacman.sh`, which adds the unsigned `[omarchy-aarch64]`
- `/.snapshots` is an empty btrfs subvolume under snapper's root configuration, or absent with a deferred hardware step queued to create it; a plain directory fails
- the installed pacman configuration is omarchy-mac's Apple Silicon template for the channel (`/usr/share/omarchy-mac/pacman`; on an older set the runtime's `default/pacman/apple-silicon`, or `aarch64` on an older runtime still) with the runtime's aarch64 mirror list (`aarch64/mirrorlist-<channel>`, or a single `mirrorlist-aarch64`), plus the test image's pin below, and the installed-system checks (`builder/verify_installed_system.py`) pass, `alsa-ucm-conf-asahi`, `asahi-audio`, `vulkan-asahi` and `asahi-bless` included, and no `[omarchy-aarch64]` section or `TrustAll` SigLevel; Bluetooth counts as enabled when its hardware step is queued for first boot
- the installed pacman configuration is the runtime's Apple Silicon template for the channel (`default/pacman/aarch64-apple`; on an older set omarchy-mac's `/usr/share/omarchy-mac/pacman`, the runtime's `default/pacman/apple-silicon`, or `aarch64` on an older runtime still) with the mirror list beside the runtime's `aarch64-apple` template, else its aarch64 one (`aarch64/mirrorlist-<channel>`, or a single `mirrorlist-aarch64`), plus the test image's pin below, and the installed-system checks (`builder/verify_installed_system.py`) pass, `alsa-ucm-conf-asahi`, `asahi-audio`, `vulkan-asahi` and `asahi-bless` included, and no `[omarchy-aarch64]` section or `TrustAll` SigLevel; Bluetooth counts as enabled when its hardware step is queued for first boot
- `@factory` is sealed for the set without fresh-image or owner state

`bin/mac-image-check` also holds the payload to the installer engine's contract and checks `PROVENANCE` and `IMAGE` against the bytes beside them.
Expand Down
33 changes: 22 additions & 11 deletions image-builder/bin/build-mac-image
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ SUPPORTED_FW=(13.5 14.8.3)
ICON_SHA256=cf26ed5d2831db99c00d62ca046040e01a18e08e63363d629340d04ac6ec8c23
KERNEL=linux-aurora
# The hardware this image is for. It is written to the image-target manifest
# and is the only machine identity the build chroot sees.
# and is the only machine identity the build chroot sees. Upstream's name is now
# aarch64-apple (omacom/omarchy e1b0e5e9b), which still reads apple-silicon from
# a manifest; an older runtime (5397950a2, in released images and packages)
# refuses aarch64-apple in omarchy-hw-platform and install/helpers/image-target.sh,
# so the manifest keeps apple-silicon until no supported runtime needs it.
PLATFORM=apple-silicon
PLATFORM_COMPATIBLE=apple,arm-platform

Expand Down Expand Up @@ -643,19 +647,21 @@ runtime_list() {
}

# The runtime's Apple list, read once before anything installs:
# omarchy-apple-silicon.packages, else an older runtime's
# omarchy-aarch64-apple.packages, named for the platform, else an older
# runtime's omarchy-apple-silicon.packages, else an even older one's
# omarchy-apple.packages. A link is passed over: bsdtar reads it as empty, and
# the list it names is a member of its own.
read_apple_list() {
local archive name list="" text
archive=$candidates/$(candidate_archive omarchy)
for name in omarchy-apple-silicon omarchy-apple; do
for name in omarchy-aarch64-apple omarchy-apple-silicon omarchy-apple; do
if [[ $(bsdtar -tvf "$archive" "usr/share/omarchy/install/$name.packages" 2>/dev/null) == -* ]]; then
list=usr/share/omarchy/install/$name.packages
break
fi
done
[[ -n $list ]] || fail "the runtime ships no Apple package list (omarchy-apple-silicon.packages or omarchy-apple.packages)"
[[ -n $list ]] ||
fail "the runtime ships no Apple package list (omarchy-aarch64-apple.packages, omarchy-apple-silicon.packages or omarchy-apple.packages)"
text=$(bsdtar -xOf "$archive" "$list") || fail "could not read the runtime's ${list##*/}"
mapfile -t apple_names < <(awk 'NF && $1 !~ /^#/ { print $1 }' <<<"$text")
((${#apple_names[@]})) || fail "the runtime's ${list##*/} names no package"
Expand Down Expand Up @@ -760,6 +766,8 @@ write_image_target() {
[[ ${MAC_IMAGE_BUILDER_COMMIT:-} =~ ^[0-9a-f]{40}$ && ${MAC_IMAGE_BUILDER_CLEAN:-} =~ ^(true|false)$ ]] ||
fail "the build names no builder commit for the image target"
install -d -m 0755 "$target/var/lib/omarchy" "$target/var/lib/omarchy/image"
# platform=apple-silicon, not upstream's aarch64-apple: the new runtime reads
# either, an older one only apple-silicon (see PLATFORM above).
printf 'format=1\nplatform=%s\ncandidate_set=%s\ncandidate_source_commit=%s\nbuilder_commit=%s\nbuilder_tree_clean=%s\nimage_profile=%s\n' \
"$PLATFORM" "$set_name" "$source_commit" "$MAC_IMAGE_BUILDER_COMMIT" "$MAC_IMAGE_BUILDER_CLEAN" "$image_profile" \
>"$target/var/lib/omarchy/image/target"
Expand Down Expand Up @@ -844,22 +852,25 @@ release_build_pacman_config() {
rmdir "$target/var/cache/omarchy-image-repositories" "$target/var/cache/omarchy-image-packages"
}

# The installed configuration for an Apple Silicon Mac: omarchy-mac's
# template for the channel the inputs name (an older set's runtime
# apple-silicon one, or an even older runtime's aarch64 one), with the
# runtime's aarch64 mirror list (per channel, or the single
# mirrorlist-aarch64 of a runtime that keeps its own repositories). TEST IMAGES ONLY: a
# The installed configuration for an Apple Silicon Mac: the runtime's
# aarch64-apple template for the channel the inputs name (else omarchy-mac's,
# an older runtime's apple-silicon one, or an even older runtime's aarch64
# one), with the mirror list beside the runtime's aarch64-apple template, else
# its aarch64 one (per channel, or the single mirrorlist-aarch64 of a runtime
# that keeps its own repositories). TEST IMAGES ONLY: a
# test candidate set's runtime sorts below the channel's omarchy, so its
# [options] gain a marked IgnorePkg for the packages built from the set's
# source commit, which keeps a pacman -Syu from replacing them
# (builder/test_image_pin.py).
write_installed_config() {
local channel templates=$target/usr/share/omarchy/default/pacman repositories mirrorlist
channel=$(field omarchy_channel)
repositories=$target/usr/share/omarchy-mac/pacman
repositories=$templates/aarch64-apple
[[ -f $repositories/pacman-$channel.conf ]] || repositories=$target/usr/share/omarchy-mac/pacman
[[ -f $repositories/pacman-$channel.conf ]] || repositories=$templates/apple-silicon
[[ -f $repositories/pacman-$channel.conf ]] || repositories=$templates/aarch64
mirrorlist=$templates/aarch64/mirrorlist-$channel
mirrorlist=$templates/aarch64-apple/mirrorlist-$channel
[[ -f $mirrorlist ]] || mirrorlist=$templates/aarch64/mirrorlist-$channel
[[ -f $mirrorlist ]] || mirrorlist=$templates/mirrorlist-aarch64
[[ -f $repositories/pacman-$channel.conf ]] || fail "the image ships no Apple Silicon pacman configuration for $channel"
[[ -f $mirrorlist ]] || fail "the runtime ships no aarch64 mirror list for $channel"
Expand Down
11 changes: 8 additions & 3 deletions image-builder/builder/candidate_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,14 @@
HEX40 = re.compile(r'[0-9a-f]{40}')
HEX64 = re.compile(r'[0-9a-f]{64}')
ARCHIVE = re.compile(r'[A-Za-z0-9@._+:-]+\.pkg\.tar\.(xz|zst)')
# The runtime's Apple package list, by upstream's name, then an older runtime's.
APPLE_LISTS = ('usr/share/omarchy/install/omarchy-apple-silicon.packages',
# The runtime's Apple package list: omarchy-aarch64-apple.packages, named for
# the platform (omacom/omarchy e1b0e5e9b), else an older runtime's
# omarchy-apple-silicon.packages, else an even older one's omarchy-apple.packages.
APPLE_LISTS = ('usr/share/omarchy/install/omarchy-aarch64-apple.packages',
'usr/share/omarchy/install/omarchy-apple-silicon.packages',
'usr/share/omarchy/install/omarchy-apple.packages')
NO_APPLE_LIST = ('ships no Apple package list (omarchy-aarch64-apple.packages, '
'omarchy-apple-silicon.packages or omarchy-apple.packages)')
# Where each runtime package records the commit it was built from.
REVISION_FILES = {
'omarchy': 'usr/share/doc/omarchy/source-revision',
Expand Down Expand Up @@ -183,7 +188,7 @@ def apple_list(package):
entry = subprocess.run(['bsdtar', '-tvf', str(package), name], capture_output=True, text=True)
if entry.returncode == 0 and entry.stdout.startswith('-'):
return name, member(package, name).decode()
raise ValueError('the runtime ships no Apple package list (omarchy-apple-silicon.packages or omarchy-apple.packages)')
raise ValueError('the runtime ' + NO_APPLE_LIST)


def payload_paths(package):
Expand Down
Loading
Loading