Skip to content

Phase A migration: run customization in the install chroot#17

Merged
AdamJHall merged 6 commits into
mainfrom
phase-a-migration
Jul 4, 2026
Merged

Phase A migration: run customization in the install chroot#17
AdamJHall merged 6 commits into
mainfrom
phase-a-migration

Conversation

@AdamJHall

Copy link
Copy Markdown
Owner

What

Moves the Tier-1/2 customization stages (packages, flatpak, grub-theme, kde,
dotfiles, setup, services) out of Phase B and into the Phase A chroot, so
the first boot lands on an already-set-up desktop instead of a bare system that
still needs archwright bootstrap to do the heavy lifting. aur/yay/snapper
stay in Phase B (they need a booted system / a real user session).

Also bumps archinstall to 4.4 and moves Plymouth into Phase A.

How

  • Round 1 — chroot-aware Runner (Chroot) + new mount/finalize stages
    that open the target at /mnt after archinstall returns and tear it down at
    the end, so the customization stages can run arch-chroot /mnt ….
  • Round 2 — re-homes the customization stages into the Phase A chroot,
    guarded to skip cleanly when the chroot isn't open.
  • e2e harness updated to match: the local repo is injected between two install
    passes (dotfiles now applied in Phase A), and the ISO is pinned to 2026.07.01.

Testing

Full e2e matrix green in QEMU, including features-min (reflector, kernel-zen,
plymouth, hooks, setup, services). One test-only fix landed here: the feature
validator now reads the ESP-mounted /boot (0700 root:root under archinstall's
dmask=0077) via sudo, so a present custom kernel is no longer misreported as
missing. archwright's install output was correct throughout.

Follow-up (not in this PR)

Promote postInstall's bundled side-effects (swapfile, locales, user shell,
multilib, repos, kernels) into first-class numbered stages, for --only
addressability + dry-run/command-plan test coverage. Deferred to its own commit.

🤖 Generated with Claude Code

AdamJHall and others added 6 commits June 30, 2026 17:16
… A round 1)

Foundation for migrating Phase B customization into the Phase A chroot so
first boot lands on an already-set-up system.

- run.Runner: ChrootRoot/AsUser target — when set, Cmd/Root/Shell/RootShell
  transparently wrap in arch-chroot (Root as root, Cmd as the user via
  `sudo -iu <user> --`). Host path stays byte-identical. Adds chroot-safe
  Has/PathExists probes for Round 2 to replace host LookPath/Stat.
- archinstall postInstall now leaves the target mounted; extracted
  ensureTargetMounted (idempotent)/unmountTarget/isMounted.
- New Install-phase stages bracket the chroot: mount(20) opens it and points
  the Runner at /mnt; finalize(99) stages the Phase B binary+config and
  unmounts. Phase A: preflight(0) archinstall(10) mount(20) finalize(99).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-home the Tier 1/2 customization stages from Phase B into Phase A so first
boot is an already-set-up desktop. Each stage flips Phase()->Install with a new
Order between mount(20) and finalize(99); the chroot-aware Runner routes their
existing commands through arch-chroot (root, or the user via sudo -iu).

- packages(30), flatpak(40), grub-theme(50), kde(60), dotfiles(70), setup(80),
  services(90) now run in the chroot. Phase B keeps yay(10), snapper(25),
  aur(40) — aur stays post-boot (makepkg can't run as root).
- ensureTool/dotfiles/setup swap host probes (LookPath/os.Stat/UserHomeDir) for
  the chroot-safe Runner.Has/PathExists and the configured user's /home/<user>.
- grub-theme installs via cloneBuildRoot (root, no inner sudo) since the chroot
  is already root — removes the user->root escalation that needed a password.
- Stage-anchored hooks (e.g. after:packages GPU drivers) now fire in the chroot
  because the stages are real Phase A stages the run loop brackets.
- Tests assert the arch-chroot-wrapped plans via a chroot helper; registry,
  selection, and from/to windows updated to the new topology. README stage
  table + phase docs updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The customization stages run only inside the target chroot the mount stage
opens. For an encrypted layout mount skips the (unimplemented) LUKS remount, so
without a guard packages/flatpak/etc. would run against the LIVE ISO — e.g.
`pacman -S` into the ISO. Add requireChroot(): each customization stage no-ops
(with a warning) when ChrootRoot is unset (encrypted layout, or a stage run in
isolation without mount).

Also bump the vm-e2e Phase A install timeout 2400s->3600s: Phase A now carries
the package/flatpak/dotfiles/clone work that used to live in Phase B.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dotfiles stage moved into Phase A, so a descriptor's injected file:// source
repo must exist in the target home before that stage runs — but the harness used
to inject it in the Phase A→B window, after Phase A. Split the install for
inject_repo descriptors at the mount-stage boundary: pass 1 `--to mount` builds
the base system and leaves /mnt mounted, we inject the repo into the target home,
pass 2 `--from mount` runs the customization stages (mount is idempotent). Drop
the now-redundant inject from inject_phase_b.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pin the QEMU smoke-test live ISO to the 2026.07.01 archive build, in
lockstep with the archinstall 4.4 bump.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ESP is mounted at /boot with fmask=0077,dmask=0077 (archinstall's
secure default), so /boot is 0700 root:root. The feature validator runs
as the unprivileged e2e user, which can't traverse /boot, so
`[[ -e /boot/vmlinuz-linux-zen ]]` reported a present kernel image as
missing and failed kernel-zen. Read the kernel image + grub.cfg via
sudo instead. archwright's install was correct throughout; only the
test's permission assumption was wrong.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AdamJHall AdamJHall merged commit c8fa28d into main Jul 4, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant