Critical install bug fix + cosmetic round-up + first formal test
procedure document.
## Critical: LUKS unlock on first boot
Generated installer kickstart's %post was injecting `rd.luks.uuid=…`
into `/etc/default/grub` only. Fedora 43 uses BLS (Boot Loader
Specification) entries in `/boot/loader/entries/*.conf`; those are
NOT regenerated by `grub2-mkconfig`. Result: the kernel boots without
`rd.luks.uuid=`, dracut's cryptsetup-generator never spawns the
unlock unit, plymouth has no password to ask for, and dracut-initqueue
loops on dev-disk-by-uuid for ~3min before dropping to emergency
shell.
The fix layers both write paths:
- `/etc/default/grub` — keeps the args around for future kernels
(kernel-install reads this when adding new entries).
- `grubby --update-kernel=ALL --args=...` — rewrites the `options`
line of every existing BLS entry so the kernel that boots NEXT
actually has the args.
Verified by reading `/proc/cmdline` from the dracut emergency shell
on a v0.5.26 install; old cmdline had only `root=UUID=… ro
rootflags=subvol=root` and was missing the LUKS arg entirely.
## GRUB / branding
- `/etc/default/grub` is sed'd to `GRUB_DISTRIBUTOR="veilor-os"` (was
already there, kept).
- BLS entries' `title` line is rewritten in-place to "veilor-os
(<kver>)" for every kernel — `grub2-mkconfig` does not touch BLS
titles, so this is the only path.
- `/boot/loader/entries/*-0-rescue-*.conf` is removed: the auto-built
rescue entry was leaking "Fedora Linux" into the GRUB menu and
showing a second boot option that nobody asked for. The rescue
kernel image itself is left in /boot.
- Hostname defaults to `veilor` (was inheriting the `localhost-live`
name anaconda writes when the kickstart's network directive is
ignored under cmdline mode).
- `/etc/machine-info` adds `PRETTY_HOSTNAME="veilor-os"` so
`hostnamectl status` and any consumer reading machine-info see the
brand.
## Boot UX
- `fbcon=nodefer` added to live-ISO bootloader cmdline. On real
laptops with a hardware GPU, the kernel modeset blanks the
framebuffer console mid-boot; without `nodefer` the installer
banner draws into a frozen framebuffer and the user sees a black
screen with a blinking cursor for ~30s. virtio-vga in QEMU doesn't
trigger this so it never reproduced in VM. Symptom report on
v0.5.26 was the trigger to investigate.
## Installer cosmetics
- `GUM_CHOOSE_CURSOR` and `GUM_INPUT_PROMPT` switched from `❯ ` to
`> `. The unicode arrow falls back to a fixed-width block on the
linux fbcon font and lipgloss then duplicates that block at col +23,
producing the "Install Install" double-render and the stray-T
artifact in password fields. Plain ASCII renders identically across
fbcon, virtio-vga, and X/Wayland gum runs.
- `VERSION_ID` bumped 0.5.8 → 0.5.27 in the os-release drop-in. The
installer banner reads this at runtime, so the live ISO + installed
system both now show "veilor-os 0.5.27".
## Test procedure
- `test/TESTING.md` — first canonical test procedure document. Splits
VM (cheap iteration, hybrid sendkey + human passwords) from real
hardware (mandatory for tag). Documents the standard test passwords
(`veilortest1` for both LUKS and admin), the kill-and-relaunch step
to skip CD on second boot, and the per-step pass/fail contract.
- `test/METHOD-CHANGELOG.md` — append-only audit trail for changes to
the procedure. Future releases that alter the test method must add
an entry here with the why.
- `test/test-runs/_TEMPLATE.md` — per-run report template. Each
tagged release should land a filled report alongside it.
## test/run-vm.sh
Decoupled QEMU monitor sock setup from auto-inject. Previously
`NO_INJECT=1` (used to suppress autotype noise into prompts) also
killed the monitor sock, leaving the VM undriveable. Monitor sock is
now always exposed; only the inject helper is gated on the pubkey
detection.
Live ISO boot chain showing extra step:
boot → text scroll → veilor-firstboot prompts admin pw → installer
veilor-firstboot.service was enabled in live ks but it's an INSTALLED
system feature (forces admin pw set on first real boot). Made no
sense to ask on live (no persistent admin user, throwaway VM, etc).
Live ks now: doesn't enable veilor-firstboot, masks the unit so
overlay-copied unit file can't auto-activate. Install ks chroot %post
already enables it (correct path).
After fix:
boot → text scroll → installer banner directly
User wants full chained pipeline:
GRUB veilor-os → plymouth text → branded gum installer →
install progress → reboot → installed system text-clean.
Live ISO was missing pieces from the install ks polish. v0.5.24
brings live ks into parity:
- bootloader --append: add plymouth.enable=0 (kills fedora splash,
exposes tty1 with gum installer banner immediately)
- chroot %post: GRUB_DISTRIBUTOR="veilor-os" (menu title)
- chroot %post: GRUB_CMDLINE_LINUX_DEFAULT="" (drop rhgb quiet)
- chroot %post: plymouth-set-default-theme details (text scroll
fallback if plymouth.enable=0 ignored)
- grub2-mkconfig regen with new branding
Result on next ISO build:
- Boot from ISO → GRUB shows "veilor-os" entry
- Pick veilor-os → text scroll (no fedora splash)
- TTY1 lands on gum installer banner + menu (no plymouth swallow)
- Install completes → reboot → installed system already has the
same text-mode boot + LUKS prompt config from v0.5.22-23
v0.5.21 set plymouth.enable=0 — plymouth-start.service still ran +
ate LUKS keystrokes. Boot fell to dracut emergency shell.
Better path: plymouth IS running but in TEXT mode via built-in
`details` theme (scrolling boot log, no graphics, no fedora logo).
LUKS prompt renders as text "Please enter passphrase for...:".
Plymouth still owns the prompt → keystrokes go through.
Changes:
- Drop plymouth.enable=0 from cmdline (let plymouth run)
- chroot %post: plymouth-set-default-theme details
- Drop rhgb quiet from GRUB_CMDLINE_LINUX_DEFAULT (all kernel msgs visible)
- dracut --force --regenerate-all (new theme baked into initramfs)
Result: text scroll boot → text LUKS prompt → text scroll → SDDM.
Onyx aesthetic. Branded plymouth theme deferred to v0.6.
User wants onyx-style boot: pure text scroll → LUKS prompt → text scroll
→ SDDM. No fedora splash, no plymouth UI.
Solution: keep plymouth PACKAGE installed (Fedora's dracut module
ships LUKS-prompt machinery via plymouth), but disable plymouthd at
runtime via kernel cmdline `plymouth.enable=0`.
Effect:
- plymouthd starts → reads cmdline → exits
- systemd-ask-password sees no plymouth daemon → falls back to
systemd-tty-ask-password-agent on /dev/console
- LUKS prompt rendered as text "Please enter passphrase for /dev/dm-0: "
- All kernel/systemd messages visible
- SDDM still launches at graphical.target (real install)
Applied to both:
- LIVE ks bootloader --append (so live boot text-mode + installer
visible on tty1, no splash hiding it)
- Generated install ks bootloader --append (so installed system
text-boots with LUKS prompt)
v0.6 will rebrand plymouth theme + re-enable for branded splash. For
v0.5.0 ship: minimal/text aesthetic matches user's onyx daily driver.
QEMU boot test of v0.5.1 (commit 3cbffaf) revealed both scripts
missing from /usr/local/sbin/ on running system, despite being in
overlay/usr/local/sbin/ in the source tree.
Root cause: Fedora's filesystem package (or post-install scriptlet)
rewrites /usr/local/sbin → /usr/local/bin symlink AFTER kickstart
%post --nochroot's overlay copy runs. The cp -a placed files in
/usr/local/sbin/ as a real directory; the symlink replacement
deleted them.
Confirmed via tty diagnostic: `ls -la /usr/local` shows
`lrwxrwxrwx ... sbin -> bin` with bin mtime predating sbin symlink
ctime by ~5min — overlay copy ran first, scriptlet rewrote sbin
second.
Fix: move both binaries to overlay/usr/local/bin/ where they're
safe from the symlink rewrite. Update all references:
- kickstart/veilor-os.ks chmod path + chown + diagnostic ls
- overlay/etc/systemd/system/getty@tty1.service.d/veilor-installer.conf ExecStart
- overlay/etc/systemd/system/veilor-firstboot.service ExecStart
- scripts/selinux/build-policy.sh fcontext + restorecon paths
- generated install ks template inside veilor-installer
Service drop-in stays at /etc/systemd/system/getty@tty1.service.d/
unchanged. The veilor-installer binary in /usr/local/bin/ is
discoverable via $PATH same as before.
Two user-facing commands shipped in overlay/usr/local/bin/.
Wraps dnf+flatpak update flow and read-only health diagnostic.
Uses gum if available, plain output otherwise. No kickstart wiring
yet beyond chmod — full integration in v0.6.0 release.
Co-authored-by: veilor-org <admin@veilor.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
- display-manager.service symlink: livecd-creator skips alias creation
vs Anaconda installer; without it sddm stays inactive at graphical.target
- admin user: replace `passwd -d` with throwaway pw `veilor` + chage -d 0
(SDDM rejects blank pw by default, breaks first-login flow)
Tested in QEMU v0.2.5: confirmed sddm enabled but inactive after boot,
and blank-pw login at SDDM returns "Login Failed".
Live ISO stalled at dracut for 5+min on KVM with init_on_alloc=1
init_on_free=1 — kernel zeroes every page on alloc/free, brutal in
virtualized memory. Keep slab_nomerge + lockdown=integrity +
randomize_kstack + vsyscall=none for live (cheap). Re-add memory
init flags on installed system via veilor-firstboot post-install
GRUB edit (planned v0.3).
- kde-theme-apply.sh: search /etc/os-release.d/veilor (where overlay
put it) before falling back to $REPO/overlay path. Rewire symlinks
cleanly: /etc/os-release → ../usr/lib/os-release.
- Kickstart: useradd admin in chroot %post since livecd-creator skips
the `user` directive (no installer phase). Blank pw + expired = forced
reset at first login same as before.
Found via debugfs: overlay copy succeeds (veilor-power, tuned profiles,
sshd-hardening, sudoers, systemd units all present in v0.2.1 rootfs) but
`mkdir + cp assets/scripts` aborted with set -eu — leaves /usr/share/
veilor-os missing → all chroot %post scripts fail. Switch to set +e on cp
plus persist trace log to /var/log/veilor-nochroot.log for next debug.
Agent A: missing livesys-scripts + anaconda-live = lorax can't build EFI/BOOT.
Agent B: livecd-creator ignores url=, only reads repo.repoList — added
explicit repo --name=fedora to feed it the base.
Both Fedora's own pipeline + livecd-creator now have what they need.
Live image plumbing in %post: enable livesys.service livesys-late.service
tmp.mount, reset machine-id.
Past grub2-mkimage. Failed at xorrisofs final ISO assembly because EFI/BOOT
dir not built — needs grub2-efi-x64-modules to compile standalone grubx64.efi.
CI made it through full install, configure, %post, squashfs build,
initrd rebuild — failed at final boot.iso wrap because grub2-mkimage
needed /usr/lib/grub/i386-pc/moddep.lst (BIOS legacy boot modules).
Hybrid BIOS+UEFI ISO requires both grub variants.