User hit `/usr/local/bin/veilor-installer: line 33: /usr/bin/tee:
input/output error` on real-hardware install. Cause: LOG was
`/var/log/veilor-installer.log`, which on the live ISO is backed by an
overlay over squashfs. A bad sector / flaky USB → tee write fails →
process substitution dies → installer aborts before the menu renders.
Two changes:
1. Move LOG to /run/veilor-installer.log — pure tmpfs, never touches
the live medium. Same path also unaffected by /var fill or overlay
weirdness.
2. Wrap the `exec > >(tee -a $LOG) 2>&1` redirect in a writability
probe. If the log can't be appended to (tmpfs OOM, fd exhaustion,
anything), skip the tee and run the installer without on-disk
persistence rather than crashing.
Persistence is a nice-to-have for post-mortem debugging; the installer
running is the must-have. This inverts the priority correctly.
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.22 plymouth details theme works (text scroll boot visible). But
LUKS prompt still never fires — dracut spins on dev-disk-by-uuid for
2+ min then drops to emergency shell.
Hypothesis: anaconda --cmdline mode skips/breaks the bootloader auto-
add of rd.luks.uuid arg. Without it, cryptsetup-generator in
initramfs has no UUID to create unlock unit for → no prompt → no
unlock → dracut times out.
Fix: chroot %post detects LUKS partition via blkid TYPE=crypto_LUKS,
injects `rd.luks.uuid=luks-<uuid>` into GRUB_CMDLINE_LINUX if not
already present. Belt-and-braces — if anaconda DID add it, sed
checks first.
Followed by grub2-mkconfig regen (already in script) so installed
grub.cfg picks up the new cmdline arg.
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.
v0.5.18 added crypt + systemd-cryptsetup to dracut.conf.d/99-veilor-
no-plymouth.conf. Boot test still failed: dracut-initqueue stuck
waiting on dev-disk-by-uuid → systemd-cryptsetup never fired.
Diagnosis: %post chroot used bash glob `for kver in /lib/modules/*/`.
In chroot, shell may be dash + nullglob unset → unmatched glob
expands literally to "/lib/modules/*/" → dracut --kver "/lib/modules/*/"
fails silently with `|| true`. Initramfs never regenerated → still
contains the v0.5.14 omit_dracutmodules-only config without crypt.
Fix: dracut --force --regenerate-all (walks /lib/modules internally,
no shell glob needed). One call regens all kernel initramfses with
the new dracut.conf.d in scope.
v0.5.17 boot stuck at dracut-initqueue waiting for LUKS device that
never unlocks. Plymouth removal also dropped the dracut machinery
that prompts user for LUKS passphrase. Pure-text systemd-tty-ask-
password-agent works in real root but isn't bundled into initramfs.
Fix: dracut.conf.d/99-veilor-no-plymouth.conf:
add_dracutmodules+=" crypt systemd-cryptsetup "
install_items+=" /usr/bin/systemd-tty-ask-password-agent "
Result: dracut bundles systemd-cryptsetup + ask-password binary into
initramfs. cryptsetup-generator creates unit at boot, ask-password-
agent prompts on tty1 in text mode "Please enter passphrase for...:".
sendkey-friendly + works on real hardware.
Per user: bottom-screen "fedora" logo + spinner during boot is fedora-
logos package + GRUB graphical theme. v0.5.17 strips it for now —
v0.6 will re-introduce plymouth with veilor-black theme + LUKS-prompt-
friendly config.
Changes:
1. Kernel cmdline: add `logo.nologo console=tty0`
- logo.nologo: suppress kernel boot logo (Tux/Fedora leaf)
- console=tty0: explicit text console output
- `quiet` already absent → all kernel msgs scroll
2. /etc/default/grub patches in chroot %post:
- GRUB_DISTRIBUTOR="veilor-os" (menu titles read "veilor-os" not
"Fedora Linux 43...")
- GRUB_THEME= (empty — no graphical theme)
- GRUB_TERMINAL_OUTPUT="console" (text-mode menu, no gfxterm)
- Drop GRUB_BACKGROUND
3. Regen grub.cfg + EFI grub.cfg with new branding
Result: pure text scroll boot, white-on-black, no fedora artifacts.
veilor-os menu title in GRUB picker. "Hackery dope" aesthetic.
For real users wanting splash → v0.6 ships plymouth + veilor theme.
v0.5.14 ships a working install but auto-install harness can't SSH-
validate post-reboot — admin user has no authorized_keys, hardened
sshd rejects all auth. SSH up + listening but no path to log in.
Fix: detect_seed_pubkey() searches /dev/sr* for a NoCloud cidata
volume (label "cidata"), parses ssh_authorized_keys: list from
user-data, returns first key. generate_ks() then embeds as
sshkey --username=admin "ssh-ed25519 AAAA... user@host"
right after the user= directive. Anaconda creates
/home/admin/.ssh/authorized_keys with right perms (700/600).
Real users: drop a NoCloud seed iso next to install media (or via
USB), pubkey lands automatically. auto-install.sh: existing run-vm.sh
seed logic already builds the cidata iso with host pubkey.
If no seed → directive line empty → anaconda treats as no-op → SSH
validation blocked but install otherwise unaffected.
v0.5.13 added omit_dracutmodules+=plymouth + dracut --force regen in
chroot %post. Boot test still showed plymouth-start.service running.
Theory: the chroot dracut --force --kver loop didn't fire (kver glob
may have been empty in chroot), or anaconda regenerated initramfs
AFTER our %post and ignored our config drop-in.
Simpler fix: don't ship plymouth at all. Add `-plymouth
-plymouth-plugin-label -plymouth-system-theme` to kickstart %packages.
With no plymouth package on disk, dracut can't bundle it into
initramfs regardless of dracut.conf state.
The /etc/dracut.conf.d snippet + /dev/null masks from v0.5.12-13 stay
as belt-and-braces — harmless once plymouth is absent.
v0.5.12 added /dev/null symlinks for plymouth services on real root.
Boot test confirmed plymouth STILL starts: it lives in initramfs
(dracut module 90plymouth) which has its own bundled service files,
unaffected by /etc/systemd/system/ masks on the installed btrfs.
Two-layer fix:
1. /etc/dracut.conf.d/99-veilor-no-plymouth.conf:
omit_dracutmodules+=" plymouth "
Then `dracut -f --kver $kver` to regenerate initramfs sans plymouth.
2. Keep /dev/null symlinks for post-pivot real-root masking.
Result: LUKS prompt rendered as text by systemd-tty-ask-password-agent
on tty1 — sendkey-friendly, hardware-realistic.
v0.5.11 used `systemctl mask plymouth-*.service` in generated kickstart
%post chroot block. systemctl needs systemd running, which it isn't in
anaconda chroot — calls failed silently (|| true).
Boot test confirmed: post-reboot showed both:
Started plymouth-start.service - Show Plymouth Boot Screen
Started systemd-ask-password-plymouth.path - Forward Password Requests
Fix: write /dev/null symlinks directly (`ln -sf /dev/null
/etc/systemd/system/<unit>`). Achieves what mask does without needing
systemd. Also adds the path-activated unit
(systemd-ask-password-plymouth.path) which actually pulls plymouth in
during dracut-initqueue.
v0.5.10 added plymouth.enable=0 + rd.plymouth=0 to kernel cmdline,
but `plymouth-start.service` still registered and ran in real-root
boot. LUKS prompt remained invisible — dracut-initqueue stuck
waiting for /dev/disk/by-uuid/<luks> to materialize.
Belt-and-suspenders: mask plymouth-{start,quit,quit-wait,read-write,
switch-root}.service in the generated kickstart's %post chroot so the
units can never start.
Effect: systemd-tty-ask-password-agent handles LUKS prompt directly
on tty1 with text "Please enter passphrase for disk ...:" — sendkey-
friendly + works on real hardware too.
v0.5.9 GRUB-installs cleanly. Disk boots, dracut reaches
cryptsetup.target, systemd-ask-password-plymouth.path armed. But
plymouth never switches from boot-splash mode to password-prompt mode
— sendkey'd passphrases bounce, dracut waits forever on
dev-disk-by-uuid.
Workaround: pass `plymouth.enable=0 rd.plymouth=0` to kernel cmdline.
Eliminates plymouth-ask-password-plugin as a layer; LUKS prompt
appears as plain text on tty1 ("Please enter passphrase for disk... :").
Bonus: aligns with hardening posture. Plymouth is graphical eye-candy
running in pid 1's namespace during early boot. Fewer moving parts =
smaller attack surface. veilor-os defaults to text boot; users wanting
splash can re-enable post-install.
Auto-install round 3 hit:
Configuring storage
Creating disklabel on /dev/vda
Creating luks on /dev/vda3
Creating lvmpv on /dev/mapper/luks-...
Creating btrfs on /dev/mapper/veilor-root
Running in cmdline mode, no interactive debugging allowed.
The exact error message is:
mount failed: wrong fs type, bad option, bad superblock on
/dev/mapper/veilor-root, missing codepage or helper program
LVM+btrfs combination causes mount failure under anaconda --cmdline.
mkfs.btrfs runs but post-create mount can't find a valid superblock.
Fix: drop LVM intermediary. Use native btrfs-on-LUKS — same pattern
Fedora KDE Spin uses by default. Cleaner, snapshot story unchanged
(btrfs subvols give us root/home split + rollback potential without
LVM's overhead).
New layout:
vda1: efi (600M)
vda2: ext4 /boot (1024M)
vda3: LUKS2 → btrfs (label=veilor)
├── subvol root → /
└── subvol home → /home
ksvalidator clean on the new template.
v0.5.5 fixed AnacondaError: 'LANG'. Auto-install harness then
hit next crash:
TypeError: expected str, bytes or os.PathLike object, not NoneType
File "/usr/lib64/python3.14/site-packages/pyanaconda/display.py", line 223
wl_socket_path = os.path.join(os.getenv("XDG_RUNTIME_DIR"), ...)
anaconda's display.setup_display() unconditionally tries to set up
Wayland socket path. tty1 has no XDG_RUNTIME_DIR set. None gets passed
to os.path.join → TypeError.
Two-part fix:
1. export XDG_RUNTIME_DIR=/run/user/0 + mkdir, so even if anaconda
probes it, the env var has a valid string value.
2. Pass --cmdline to anaconda. Fully unattended text-only mode, no
Wayland/X/TUI. Right fit for our gum-driven kickstart flow where
ks is self-contained (disk, pw, locale all pre-answered).
Combined effect: anaconda goes straight from CLI parse → kickstart
execute → reboot. No display subsystem at all.
Surfaced by test/auto-install.sh round 2.
Auto-install harness ran through gum installer cleanly but anaconda
crashed at startup:
File "/usr/lib64/python3.14/site-packages/pyanaconda/keyboard.py",
line 152, in activate_keyboard
sync_run_task(task_proxy)
...
pyanaconda.modules.common.errors.general.AnacondaError: 'LANG'
Anaconda's keyboard.activate_keyboard() reads $LANG and bombs if unset.
TTY1 (where veilor-installer runs) inherits no locale by default;
gum/whiptail don't set it.
Fix: export LANG + LC_ALL = user's chosen locale (defaulting to
en_GB.UTF-8) before invoking anaconda.
Found via test/auto-install.sh end-to-end run.
Workflow now publishes ISO as 1900M chunks. Test harness needs to:
1. gh release download --pattern '*.iso.part-*'
2. cat parts back into single ISO
3. verify sha256 of all parts
If invoked with no ISO arg, auto-fetches from ci-latest release.
Falls back to local ISO path if given as arg (existing behavior).
Reassembled ISO lives at ~/veilor-iso/ci-latest/.
test/auto-install.sh boots ISO, drives gum installer via QEMU
monitor sendkey with hardcoded test answers, waits for anaconda,
reboots into installed system, SSHs in, runs validation checklist.
Co-authored-by: veilor-org <admin@veilor.org>
GH release asset size limit = 2 GiB. Veilor ISO ~2.8 GiB (KDE base +
hardening + grafted /veilor/ tree). zstd -19 only achieves 96.67%
compression (squashfs already xz-compressed). Splitting is the fix.
Workflow now:
- Splits ISO with `split -b 1900M -d --suffix-length=2`
- Drops original ISO before upload (would fail at >2 GiB)
- Includes per-part sha256 for reassembly verification
- Release notes include cat reassembly command
test/auto-install.sh will need follow-up commit to download + cat
the parts before booting.
Two follow-ups to 75a68a1 (releases switchover):
1. action-gh-release got 403 "Resource not accessible by integration"
because default GITHUB_TOKEN has read-only on contents. Added
workflow-level `permissions: contents: write`.
2. Failure-path artifact upload still hit quota wall. Replaced with
inline `tail` of build/out/build.log + anaconda program.log
directly to job log. No artifact upload = no quota.
Artifact storage quota (50GB Pro tier) maxed out with ~18 iterations
of 2.7GB ISOs. Quota recalc 6-12h not in our cadence. Builds succeed
but upload step fails — wasting CI minutes + blocking testing.
Switch to GitHub Releases (no storage quota):
- Every successful build on main updates rolling `ci-latest`
prerelease draft. Replaces files in place.
- Tag-driven releases (v*.*.*) keep their existing publish path.
- Build logs remain as artifacts (small + opt-in failure only,
retention=1d).
User can `gh release download ci-latest --repo veilor-org/veilor-os`
or browse to releases page. No more artifact quota wall.
User boot-tested v0.5.2 + in-VM patch. Requested polish:
- Banner: replace slant-figlet `veilor-os` + "hardened. branded. yours."
tagline with figlet ANSI Regular `VEILOR OS` wordmark (5-line block).
No tagline. Border preserved by gum style call.
- Menu header: "Welcome. What would you like to do?" → "Welcome"
- Menu labels:
"Install veilor-os to disk" → "Install"
"Try live — desktop (KDE Plasma)" → "live - (KDE)"
"Try live — shell" → "live - shell"
"Reboot" / "Power off" unchanged
- Hostname prompt removed — hardcoded to "veilor". User can change
post-install via hostnamectl. Cuts one prompt from install flow.
Confirmation summary drops the Hostname row.
- Locale options trimmed: en_GB.UTF-8, en_US.UTF-8 only (was 4 incl
de_DE, fr_FR). i18n not v0.5 priority.
Verified in-VM rendering of the menu changes via sed-patch on v0.5.2
ISO. ksvalidator + bash -n clean.
QEMU boot test of v0.5.2 found service still status=1/FAILURE despite
file present at /usr/local/bin/veilor-installer. Root cause via
`bash -x`: `exec > >(tee -a "$LOG") 2>&1` ran BEFORE require_tty
check; process substitution replaces fd1 with a pipe, so [[ -t 1 ]]
returns false → require_tty bails out with [ERR] message.
Order was self-inflicted bug from v0.5.0. Fix: move require_tty
function definition + call BEFORE the tee redirect. Drop the
redundant require_tty call in the entry block (would fail post-redirect).
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>
* v0.5.1: gum installer + full veilor-os ks generation
Two changes, one commit (matches v0.5.1 milestone):
1. Swap whiptail → gum (charm.sh)
- Source /usr/share/veilor-os/assets/installer/colors.gum at top so all
prompts pick up branded GUM_* env vars.
- Render banner.txt via `gum style --border rounded`.
- Wrap every prompt behind prompt_choose / prompt_input / prompt_password
/ prompt_confirm / prompt_message / prompt_error helpers that dispatch
gum→whiptail based on `command -v gum`. Defensive: minimal images
without /usr/local/bin/gum still get a working TUI.
- Main menu items now use literal labels (case-matched), not 1..5 tags.
2. Generated kickstart now installs full veilor-os
Previously emitted a vanilla F43 KDE + ~12 hardening packages with no
overlay/scripts/branding. Now mirrors live ks (kickstart/veilor-os.ks
63-141) for %packages, plus:
- %post --nochroot copies overlay/, scripts/, assets/ from
/run/install/repo/veilor (single source — boot ISO mount path).
- %post (chroot) runs scripts/10-harden-base.sh, 20-harden-kernel.sh,
selinux/build-policy.sh, kde-theme-apply.sh.
- `chage -d 0 admin` so first login forces password change. (Account
itself is created by anaconda from the `user` directive — admin pw
collected via gum is passed through --plaintext.)
- `systemctl set-default graphical.target` (real install boots SDDM,
not the TTY1 installer like live).
- Drops live-only entries (livesys-scripts, anaconda-live, dracut-live,
isomd5sum, xorriso, livesys.service enables).
Tested: bash -n clean; ksvalidator on a substituted-placeholder copy
exits 0.
gum binary itself (/usr/local/bin/gum) is vendored by a separate
build-side change — not in this PR.
* fix: escape sed special chars + reject & | / in passwords
Reviewer found a password like aA1!@#%^&*()_-+={}[] becomes
aA1!@#%^__ADMIN_PW__*()_-+={}[] because sed expands & to matched
pattern. Two layers of defense:
1. validate_pw rejects & | / newline at input
2. sed_escape() helper escapes any remaining special chars before
substitution
---------
Co-authored-by: veilor-org <admin@veilor.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Drops in branded assets the v0.5.1 installer rewrite (whiptail -> gum)
will consume: ASCII banner, sourceable GUM_* env-var palette matching
the veilor-black KDE color scheme, and an INSTALLER.md walkthrough.
The existing v0.5.0 veilor-installer script is intentionally untouched
so the swap can land in a separate, focused PR.
Co-authored-by: s8n-ru <279801990+s8n-ru@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* v0.5.1 build: vendor gum binary + graft /veilor/ onto ISO
- gum 0.17.0 pinned by sha256, downloaded into overlay/usr/local/bin/
so installer can use Charm.sh TUI primitives.
- After livecd-creator produces ISO, extract+re-pack with /veilor/
containing overlay+scripts+assets so installer-generated ks can
copy them into target system at install time.
* fix: extract original ISO boot stanza programmatically (no hardcoded paths)
Reviewer found `-e images/efiboot.img` was wrong — Fedora livecd-creator
places efiboot.img in isolinux/ not images/. Plus missing
--mbr-force-bootable + -partition_* flags would produce hybrid MBR/GPT
mismatch refused by some BIOS firmwares.
Fix: extract original ISO's exact boot stanza via
`xorriso -report_el_torito as_mkisofs` and replay it via eval.
Guarantees exact match, immune to upstream Fedora layout changes.
---------
Co-authored-by: veilor-org <admin@veilor.org>
Pre-existing shellcheck failure blocking all PR merges. Standard
"double-quote array expansions" fix. No behavior change.
Co-authored-by: veilor-org <admin@veilor.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Lint flagged false positives on audit reports + CHANGELOG that
self-reference forbidden strings as findings. Restrict scan to
kickstart/, overlay/, scripts/, assets/, build/ — actual ship state.
Co-authored-by: veilor-org <admin@veilor.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Bugs found by agent linter on v0.5.0-alpha:
1. logvol missing --size: ksvalidator rejected. Added --size=8192 --grow.
2. bootloader --location=mbr on UEFI: conflicts with /boot/efi part.
Switched to --location=none (anaconda auto-detects EFI vs BIOS).
3. lsblk awk truncated multi-word disk models ("WD PC SN740" → "WD").
Now collapses model spaces to underscores, preserves full string.
Also added mmcblk to disk regex (eMMC support).
4. Heredoc with $VAR expansion + passwords containing $/`/" corrupted
generated ks. Now: single-quoted heredoc + sed placeholder
substitution. Plus input validator rejects "$\` chars in passwords.
ksvalidator clean on sample generated ks.
bash -n clean.
CI build still in flight (3328ffb). This pushes a new commit; CI will
run again with these fixes. Net delay: zero (3328ffb's installer was
broken anyway, so its ISO unusable for install path).
- 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).
Upstream bug in /usr/lib/python3.14/site-packages/imgcreate/live.py:
if self._isDracut:
args["rootlabel"] = "live:LABEL=%(fslabel)s" # WRONG
else:
args["rootlabel"] = "CDLABEL=%(fslabel)s"
For dracut path on EFI grub it writes `root=live:LABEL=...` but
dracut needs `live:CDLABEL=...` to look up ISO9660 by CD volume id.
Result: parse-livenet hook stalls indefinitely.
CI now sed-patches the file in-place before build. Reported upstream
livecd-tools as separate task.