hardened Fedora KDE; primary on Forgejo
Find a file
veilor-org 01a37a98d4 v0.5.29: narrow anaconda patch + LUKS UX + initramfs assertion
Five-fix bundle from 7-agent research wave on the v0.5.28-final
gen_grub_cfgstub failure.

## 1. Narrow the anaconda transaction_progress patch (CRITICAL)

The v0.5.28 patch was too broad. It rewrote
`process_transaction_progress` so every 'error' token in the
transaction queue became a `log.warning`. That queue carries four
distinct error classes:

  - cpio_error      — payload extraction (genuinely fatal)
  - script_error    — RPM 6.0 cmdline-mode scriptlet warning-as-error
                      (the ONE we want to ignore)
  - unpack_error    — payload corruption (genuinely fatal)
  - error           — generic transaction error (genuinely fatal)

By swallowing all four we silently masked grub2-efi-x64's posttrans
failure mid-install. /boot/efi/EFI/fedora/ ended up incomplete →
gen_grub_cfgstub then failed at the bootloader install phase with
"gen_grub_cfgstub script failed" because its `set -eu` script
couldn't read the missing files.

v0.5.29 narrows the patch: override only the `script_error` callback
inside transaction_progress.py to log a warning and NOT enqueue
'error'. The consumer (`process_transaction_progress`) reverts to
upstream behaviour where cpio_error / unpack_error / error still
raise PayloadInstallationError. Real install-fatal events keep
aborting; only the F43-RPM-6.0 scriptlet regression is silenced.

The patch is applied via `python3 -c` regex rewrite (more robust
than nested sed across multi-line method bodies).

## 2. LUKS UX — `tries=5,timeout=0` (FIX)

Default cryptsetup-generator unit allows ONE passphrase try with a
1m30s wait. One typo on a long passphrase = wait 1m30s, then the
device-wait timer trips, then dracut emergency shell after 3min total.
Brutal. Adding `rd.luks.options=luks-XXX=tries=5,timeout=0` gives
five typo-friendly retries with no auto-timeout.

## 3. fbcon=nodefer on installed-system cmdline (FIX)

Live ISO cmdline already has `fbcon=nodefer` (added in v0.5.27 to fix
the real-laptop black-screen-after-dracut). The installed-system
bootloader directive in the generated install ks did NOT carry it.
Same KMS handoff happens on the installed system on the same hardware.
Now both have the flag.

## 4. /etc/crypttab fallback assertion (BELT-BRACES)

Anaconda's custom-partitioning code path normally writes /etc/crypttab
for `--encrypted` part directives. Edge cases observed in F43+ where
it doesn't. Without crypttab, systemd-cryptsetup-generator can still
work from kernel cmdline alone, but cleanup paths and second-stage
unlock both fall over. Adding a fallback `echo` that writes the
canonical line if it's missing post-anaconda.

## 5. Initramfs LUKS module assertion (DEFENSIVE)

Force-include `crypt + systemd-cryptsetup + plymouth` modules in
initramfs via /etc/dracut.conf.d/10-veilor-luks.conf. dracut autodetects
these when it sees an active LUKS mapping, but %post runs before the
LUKS state is fully observable from the chroot. Plus we wipe stale
initramfs (`rm -f /boot/initramfs-*.img`) before `--regenerate-all`
so the regen actually rewrites bytes. Final assertion runs
`lsinitrd | grep -q cryptsetup` and surfaces a [ERR] line in build
output if the module didn't make it.

## What this should fix

After the man-db fix in v0.5.28-final, install proceeded past
"Configuring xxx" cleanly but died at "Installing boot loader" with
gen_grub_cfgstub. Root-cause was the over-broad patch from #1 above.

After v0.5.29:
  - Install transaction completes (man-db excluded; non-man-db
    scriptlet warnings still suppressed; real errors still raise)
  - gen_grub_cfgstub runs against complete /boot/efi/EFI/fedora/
  - Bootloader install completes
  - Reboot to disk lands at GRUB veilor-os entry
  - Kernel + initramfs load (cryptsetup confirmed present)
  - Plymouth LUKS prompt appears with text fallback
  - User has 5 tries, no timeout
  - Unlock → btrfs subvol mount → systemd → SDDM

Files: kickstart/veilor-os.ks (+45 lines), overlay/usr/local/bin/veilor-installer (+50 lines).
Verified: bash -n clean, ksvalidator clean.

References:
  pyanaconda transaction_progress.py:110-136 (4 producers of 'error')
  pyanaconda bootloader/efi.py:194-201 (gen_grub_cfgstub call site)
  /usr/bin/gen_grub_cfgstub (set -eu wrapper for grub2-mkconfig stub)
  Fedora wiki Changes/RPM-6.0
  dnf5 issue #2507 (RPM 6.0 scriptlet propagation regression)
2026-05-05 05:12:24 +01:00
.github ci: drop updates repo (3x 404 on its zchunk repodata) 2026-05-03 04:15:12 +01:00
assets v0.5.27: rd.luks.uuid via grubby, GRUB rebrand, fbcon=nodefer, ASCII gum cursor 2026-05-05 01:43:00 +01:00
build ci: switch refs from veilorveilor-org (GH org slug); domain veilor.org 2026-04-30 13:59:20 +01:00
docs v0.5.28 (partial): lock locale to en_US, roadmap post-install menu 2026-05-05 02:48:36 +01:00
kickstart v0.5.29: narrow anaconda patch + LUKS UX + initramfs assertion 2026-05-05 05:12:24 +01:00
overlay v0.5.29: narrow anaconda patch + LUKS UX + initramfs assertion 2026-05-05 05:12:24 +01:00
scripts v0.5.2: move veilor-installer + veilor-firstboot to /usr/local/bin 2026-05-02 05:33:22 +01:00
test v0.5.27: rd.luks.uuid via grubby, GRUB rebrand, fbcon=nodefer, ASCII gum cursor 2026-05-05 01:43:00 +01:00
upstream v0.3 theme: match onyx exactly — solid black wallpaper, Linux Konsole scheme, Breeze_Light cursor 2026-04-30 17:18:14 +01:00
.gitignore chore: gitignore agent worktrees + un-track accidental embedded repos 2026-05-02 01:08:14 +01:00
CHANGELOG.md docs: CHANGELOG v0.2.0-v0.2.5, README rewrite, ROADMAP, release notes update (#5) 2026-05-02 03:42:39 +01:00
CONTRIBUTING.md ci: switch refs from veilorveilor-org (GH org slug); domain veilor.org 2026-04-30 13:59:20 +01:00
LICENSE veilor-os v0.1 scaffold — kickstart + hardening + 3-mode power + DuckSans-ready KDE black theme 2026-04-30 03:43:33 +01:00
README.md docs: CHANGELOG v0.2.0-v0.2.5, README rewrite, ROADMAP, release notes update (#5) 2026-05-02 03:42:39 +01:00

veilor-os

Hardened minimal Fedora KDE spin. Black-on-black. Locked down by default.

Build veilor-os ISO License: MIT Status: pre-release

veilor-os is a Fedora 43 KDE Plasma remix for operators who want a clean, fast, opinionated desktop with serious hardening already wired in. Boot the ISO, set an admin password, work. No installer wizard. No initial-setup screen. No telemetry. No "would you like to enable X" prompts.


Status

Pre-release v0.2.5 — first feature-complete ISO that actually applies the veilor-os overlay to the installed system. The build pipeline is green on CI; the live ISO boots to KDE on KVM and bare metal. See CHANGELOG.md for the full v0.2.0 → v0.2.5 story (it is worth reading — five real bugs caught and documented).

What is done: hardening (SELinux, sysctl, USBGuard, fail2ban, firewalld), KDE black theme, Fira Code system font, 3-mode power management, single-prompt LUKS install, first-boot admin password flow, reproducible CI build, EFI+BIOS bootable live ISO.

What is planned (see docs/ROADMAP.md): Plymouth black theme, SDDM theme, signed ISOs (own MOK + GPG), AppArmor + nftables, veilor-update / veilor-doctor helpers, public docs site.


Quick install

# 1. Download the ISO (after public release; CI artifact for now)
sha256sum -c veilor-os-43-*.iso.sha256

# 2. Flash to USB. Replace /dev/sdX with your USB device — triple-check.
sudo dd if=veilor-os-43-*.iso of=/dev/sdX bs=4M status=progress conv=fsync
sync

# 3. Boot from USB, pick "Install veilor-os" from the menu.
# 4. Set a strong LUKS passphrase — the only prompt during install.
# 5. Reboot, remove USB.
# 6. On first boot: TTY prompts for an admin password (≥14 chars, mixed case,
#    digit, symbol). Once accepted, SDDM starts. Log in as `admin`.

Full install + first-boot walkthrough: docs/INSTALL.md.


What veilor-os ships

Layer Hardening
Boot Secure Boot, lockdown=integrity, slab_nomerge, randomize_kstack_offset=on, vsyscall=none. LUKS2 (aes-xts-plain64, argon2id, mem=1GB). zram swap (no disk swap, no cold-boot leak).
Kernel Locked sysctls: ptrace=2, kptr_restrict=2, dmesg_restrict=1, perf_event_paranoid=3, BPF JIT hardening, full ASLR, no SUID core dumps.
MAC SELinux enforcing, targeted policy + custom veilor-systemd module.
Network firewalld zone = drop, ssh only inbound. systemd-resolved with DNS-over-TLS (Cloudflare/Quad9 fallback), LLMNR off. NTS-authenticated chrony time.
SSH password auth off, root login off, single admin user, X11 forwarding off, MaxAuthTries 3.
Auth root locked, single admin user with sudo. pwquality minlen=14, 4 character classes. First-boot password forced via chage -d 0.
Audit auditd rules covering passwd/shadow/sudoers/ssh/cron/sysctl/kernel modules and all privileged binaries.
IDS fail2ban with sshd + pam-generic jails, journal backend, firewalld rich-rule action.
USB USBGuard daemon, default-block, empty allowlist on first boot.
Services off abrt*, cups, geoclue, avahi-daemon, bluetooth, ModemManager, gssproxy, atd, pcscd, kdeconnectd, PackageKit.
UX KDE Plasma minimal, BreezeBlackPure colour scheme, Fira Code system font, veilor-power save | mid | perf with udev AC/battery auto-switch.

Full reference: docs/HARDENING.md.


60-second tour — what's different from stock Fedora KDE

  • No Anaconda Initial Setup wizard after first boot. Single LUKS passphrase prompt is the entire install interaction. Admin user is pre-created; password is set once on TTY1, then SDDM starts.
  • Root is locked. passwd -S root reports L. There is no su - to root, ever. Use sudo.
  • No PackageKit, no Flatpak by default. Updates happen with sudo dnf upgrade on your terms, not in the background.
  • Default firewall zone is drop, not FedoraWorkstation. The only thing your machine answers is sshd on its assigned port.
  • USBGuard blocks every USB device by default. First-boot procedure: plug in everything you trust, run usbguard generate-policy, done.
  • Black-on-black KDE. Wallpaper, panel, Konsole all match. No "white flash" anywhere in the session.
  • veilor-power save | mid | perf swaps the full tuned profile, CPU governor, EPP, battery threshold, and screen-dim policy in one command. Wired to AC/battery udev events too — laptop drops to save when unplugged automatically.

How veilor-os compares

Feature veilor-os Stock Fedora KDE Kicksecure
SELinux enforcing OOTB yes yes yes
AppArmor planned (v0.5) no yes
Secure Boot yes (Fedora keys) yes (Fedora keys) configurable
LUKS2 with argon2id default optional default
Single-prompt install (LUKS only) yes no no
Root account locked by default yes no yes
firewalld default zone = drop yes no n/a (uses nftables)
USBGuard default-block yes no yes
fail2ban + auditd OOTB yes no partial
DNS-over-TLS by default yes no yes
NTS-authenticated NTP yes no yes
init_on_alloc/free (post-install) yes (planned re-enable) no yes
Telemetry / phone-home none minimal none
KDE Plasma branded theme yes (black) Breeze n/a (XFCE)
Power-profile CLI yes (3-mode) partial no
Reproducible kickstart-built ISO yes yes yes (from Debian)
Base distro Fedora 43 Fedora 43 Debian

veilor-os is not trying to compete with Whonix-style anonymity or Qubes-style isolation. It is a hardened daily-driver desktop — fast, clean, locked down, with no manual post-install hardening required.


Repo layout

kickstart/   veilor-os.ks                 full kickstart definition
build/       Containerfile + build-iso.sh    reproducible ISO builder
overlay/     files dropped into installed root via %post
scripts/     hardening, SELinux policy, theme apply, firstboot
assets/      fonts, KDE colour scheme, branding, plymouth (planned)
docs/        BUILD / INSTALL / HARDENING / POWER / ROADMAP
test/        boot-checklist + KVM runner
.github/     CI workflows + PR template + CODEOWNERS

Build instructions: docs/BUILD.md. Roadmap: docs/ROADMAP.md. Contributing: CONTRIBUTING.md. Changelog: CHANGELOG.md.


License

MIT — see LICENSE. Fira Code ships from Fedora's fira-code-fonts package under SIL OFL 1.1. Fedora packages remain under their respective licences. Kickstart, overlay, scripts, and docs in this repo are MIT.