Logs the full output of the 9-agent deep-dive run on 2026-05-05 to
docs/research/2026-05-05-agent-wave/. Pulls every actionable finding
into one indexed location so v0.5.32 planning has a paper trail.
Files:
docs/research/2026-05-05-agent-wave/README.md — index
docs/research/2026-05-05-agent-wave/01-...real-hardware.md — Plymouth + LUKS edge cases
docs/research/2026-05-05-agent-wave/02-...firstboot-ux.md — SDDM + first-boot UX
docs/research/2026-05-05-agent-wave/03-...spike-plan.md — bootc-image-builder 1-week spike
docs/research/2026-05-05-agent-wave/04-...tier-2.md — AppArmor + nftables + audit + homed
docs/research/2026-05-05-agent-wave/05-...launch.md — threat model + v0.7 launch checklist
docs/research/2026-05-05-agent-wave/06-...log-capture.md — virtio-9p host-share for anaconda logs
docs/research/2026-05-05-agent-wave/07-...skel-branding.md — /etc/skel gap audit
docs/research/2026-05-05-agent-wave/08-...ci-hardening.md — SHA-pin actions + SBOM + SLSA L3
docs/research/2026-05-05-agent-wave/09-...failure-modes.md — real-hardware pessimistic audit
Plus the prior linter-applied:
docs/ROADMAP.md — Lessons learned section, v0.5.32 active block,
v0.6 promotion of veilor-postinstall + veilor-doctor,
v0.7 bootc spike scheduled
docs/THREAT-MODEL.md — drafted by Agent 5; in/out scope, comparison
matrix, v0.7 launch checklist
Top blockers identified for v0.5.32 (cross-cited in README):
1. Suspend/resume wifi death (kernel.modules_disabled=1)
2. veilor-firstboot.service WantedBy=graphical.target
3. kernel-upgrade grub drift
4. USBGuard hash-rules problem (already learned on onyx)
5. firewalld blocks tailscale0
6. /etc/skel/ empty
7. virtio-9p log capture replaces broken virtio-serial path
Wave + verifier pattern (per ROADMAP lessons learned #4) validated:
9 parallel agents on distinct topics produced converging blocker
list. The same pattern landed v0.5.31 four-bug fix from the prior
4-agent verification wave on v0.5.30 outcome.
275 lines
13 KiB
Markdown
275 lines
13 KiB
Markdown
# Roadmap
|
||
|
||
Versioned roadmap for veilor-os. Targets are intentionally short and
|
||
testable. No fluff. Items in earlier versions are blockers for later
|
||
ones unless explicitly noted.
|
||
|
||
For the historical record of what landed in each release, see
|
||
[`../CHANGELOG.md`](../CHANGELOG.md).
|
||
|
||
---
|
||
|
||
## Lessons learned through v0.5.x install grind
|
||
|
||
Five things v0.5.27–31 changed about how we plan:
|
||
|
||
1. **Anaconda + RPM-6.0 + `--cmdline` is brittle** — three install
|
||
failures, kernel cmdline written to four places before one worked.
|
||
`--location=none` skips `CollectKernelArgumentsTask`,
|
||
`kernel-install` reads `/etc/kernel/cmdline` not `/proc/cmdline`,
|
||
and `transaction_progress.py` masks real failures if patched too
|
||
broadly. Justifies promoting the bootc-image-builder spike to v0.7.
|
||
2. **Test procedure must gate every tag** — v0.5.27 only surfaced four
|
||
bugs in one VM run because the run walked every step in order.
|
||
`test/TESTING.md` and `test/test-runs/` are now load-bearing.
|
||
3. **Real hardware is not optional** — VM catches install logic, not
|
||
KMS / fbcon / firmware. Spare laptop + friend's laptop must run
|
||
pre-tag, every time.
|
||
4. **Multi-agent debug waves work, but only with a verifier** — the
|
||
v0.5.31 four-bug fix came from a 4-agent verification wave on
|
||
v0.5.30 outcome. Wave + verifier = signal; wave alone = noise.
|
||
5. **"We ask once, with sane defaults" is the distro UX** — every
|
||
v0.5 install bug we shipped a workaround for (locale, hostname,
|
||
USBGuard policy, drivers) is something `veilor-postinstall` could
|
||
ask the user about cleanly on first boot. That promotes
|
||
`veilor-postinstall` from v0.6 background item to flagship.
|
||
|
||
---
|
||
|
||
## v0.2 — green ISO + base hardening (DONE)
|
||
|
||
Reproducible CI build pipeline. UEFI+BIOS bootable live ISO from a single
|
||
kickstart. Single-prompt LUKS install. First-boot admin password flow.
|
||
Full overlay applied (sysctl, sshd, sudoers, tuned profiles, KDE black
|
||
theme, Fira Code, branded `/etc/os-release`). SELinux enforcing.
|
||
firewalld drop zone. fail2ban + auditd + USBGuard active. The build
|
||
chased five real bugs (DEST hardcoded, `set -eu` killing `cp`,
|
||
os-release symlink, missing admin user, `LABEL=` vs `CDLABEL=` in
|
||
livecd-tools) before greening.
|
||
|
||
Released `v0.2.5` on 2026-05-01. CI on every push to `main`.
|
||
|
||
---
|
||
|
||
## v0.5.27–v0.5.31 — install path stabilisation (DONE)
|
||
|
||
The bridge between v0.2 (greens at all) and v0.3 (looks polished). All
|
||
install-path bugs surfaced by the formal hybrid-VM test procedure
|
||
(`test/TESTING.md`). Five releases, ~hours of debug, three install
|
||
failures before greening.
|
||
|
||
- **v0.5.27 (DONE)** — `rd.luks.uuid` via `grubby --update-kernel=ALL`,
|
||
GRUB rebrand, `fbcon=nodefer`, ASCII gum cursor.
|
||
- **v0.5.28 (DONE)** — locale locked en_US.UTF-8, dropped updates repo,
|
||
patched anaconda `transaction_progress.py` to silence `Configuring
|
||
xxx.x86_64` scroll, excluded man-db.
|
||
- **v0.5.29 (DONE)** — narrowed anaconda patch (was masking real
|
||
failures), LUKS UX, initramfs assertion. Five-fix bundle from 7-agent
|
||
research wave.
|
||
- **v0.5.30 (DONE)** — broad error suppression, manual bootloader path,
|
||
virtio log capture for post-mortem.
|
||
- **v0.5.31 (DONE)** — `--location=none` was making anaconda skip
|
||
`CollectKernelArgumentsTask`; kernel-install reads
|
||
`/etc/kernel/cmdline` as source of truth, veilor never wrote it, so
|
||
BLS entries shipped with empty cmdline. Three-path write
|
||
(`/etc/kernel/cmdline` + `/etc/default/grub` + grubby) plus explicit
|
||
`kernel-install add`.
|
||
|
||
## v0.5.32 — next ship (active)
|
||
|
||
Outstanding from the grind, immediate priority for the next tag:
|
||
|
||
- **End-to-end VM green run** — v0.5.31 lands the kernel-cmdline fix
|
||
but no full hybrid-VM pass has signed it off. Run the procedure in
|
||
`test/TESTING.md` to install + reboot + login, file the report in
|
||
`test/test-runs/`, then tag.
|
||
- **Real-hardware run on the spare laptop** — VM is necessary not
|
||
sufficient. Friend's laptop is mate's-test, spare is ours. KMS,
|
||
fbcon, USB controller, real-firmware Secure Boot only show up here.
|
||
- **gum input render glitch** — duplicate "Install", stray T in
|
||
password fields on linux fbcon. Replace `gum input --password` with
|
||
bash `read -srp`; cosmetic only but visible on every install.
|
||
|
||
---
|
||
|
||
## v0.3 — UX polish (in progress)
|
||
|
||
The visible polish layer that v0.2 deferred for build velocity.
|
||
|
||
- **Plymouth black theme** — boot splash matching the desktop. No Fedora
|
||
drum, no white flash. `assets/plymouth/veilor/`.
|
||
- **SDDM theme** — black login background, single-user prompt with
|
||
`admin` pre-filled, no userlist.
|
||
- **Konsole profile** — black background, Fira Code, transparent panel
|
||
off (no compositor cost on resume).
|
||
- **Wallpaper SVG** — flat black with subtle veilor wordmark, 1080p +
|
||
4K + ultrawide variants.
|
||
- **Re-enable memory hygiene on installed system.** v0.2.5 stripped
|
||
`init_on_alloc=1 init_on_free=1` from the *live* cmdline because they
|
||
5x'd KVM boot time. Re-add post-install via `veilor-firstboot` so the
|
||
installed system gets the protection without the ISO penalty.
|
||
- **USBGuard auto-snapshot on first boot.** Currently the operator
|
||
runs `usbguard generate-policy` manually. v0.3 wires this into
|
||
`veilor-firstboot` after the password step (with a clear
|
||
"plug in trusted devices first" prompt).
|
||
|
||
Target: this month. None of it is a kickstart change — pure overlay
|
||
work.
|
||
|
||
---
|
||
|
||
## v0.4 — distribution + signing
|
||
|
||
Get veilor-os to a state where the ISO is downloadable, verifiable, and
|
||
trusted by Secure Boot without user shenanigans.
|
||
|
||
- **GPG-signed releases.** Tag → CI builds → CI signs ISO + sha256 with
|
||
veilor.org release key → GitHub Release artifact carries `.iso.asc`.
|
||
- **Reproducible builds.** Pin Fedora compose ID, lock package versions
|
||
via `dnf snapshot` or equivalent, document how to verify two builds
|
||
match.
|
||
- **Own MOK (Machine Owner Key) + sbsign for Secure Boot.** Currently
|
||
veilor-os relies on Fedora's signed shim chain. v0.4 ships our own
|
||
MOK, signs the kernel + initramfs at build time, optionally enrols
|
||
the MOK on first boot for users who want a cleaner trust path.
|
||
- **ISO download mirror** — static download page on veilor.org with
|
||
current + previous release, sha256, gpg signature. **Not** an RPM
|
||
mirror — veilor-os does not ship its own packages, only the spin
|
||
configuration.
|
||
- **Release process documented** — tagging, CI, signing, mirror sync
|
||
in `docs/RELEASE.md`.
|
||
|
||
---
|
||
|
||
## v0.5 — hardening tier 2
|
||
|
||
Hardening that builds on v0.2's foundation. Each item is opt-in unless
|
||
specified — defaults stay sane for a daily driver.
|
||
|
||
- **AppArmor profiles in addition to SELinux.** Stack-not-replace.
|
||
Targeted at the browser, the mail client, and anything that touches
|
||
attacker-controlled data. SELinux remains the primary MAC.
|
||
- **systemd-homed** — encrypted-per-user `~`, suspend-aware, key
|
||
unlocked at PAM login. Optional, opt-in via post-install helper.
|
||
- **nftables ruleset** alongside firewalld defaults. Default firewalld
|
||
policy stays drop; nftables provides advanced filtering for users
|
||
who want it.
|
||
- **Audit log shipping** — opt-in `auditd` -> remote syslog over TLS,
|
||
for users running a central log aggregator.
|
||
- **Installer kickstart split** — separate `veilor-os-install.ks` for
|
||
installer ISO (real LUKS partitioning, not the live-rootfs
|
||
simplification used in v0.2). Lets users install veilor-os as the
|
||
primary OS without going through the live boot first.
|
||
- **Audit baseline** — re-run the security audit (template in
|
||
`security/audit-template.md`) and target a lower risk score than v0.2.
|
||
|
||
---
|
||
|
||
## v0.6 — ergonomics (PROMOTED — install grind proved we need this)
|
||
|
||
Smooth the operator experience so day-to-day work doesn't fight the
|
||
hardening. `veilor-postinstall` and `veilor-doctor` were v0.6 background
|
||
items — promoted to **headline** features after v0.5.27–31 made it
|
||
clear that "we ask once, with sane defaults" is what separates a
|
||
distro from a kickstart.
|
||
|
||
- **`veilor-postinstall`** (PROMOTED — flagship of v0.6) — first-login
|
||
welcome menu, EndeavourOS-style but cleaner. Single TUI screen:
|
||
keyboard layout, locale (deferred from install per v0.5.28),
|
||
hostname override, package presets (dev / media / homelab), drivers
|
||
(NVIDIA / Intel / AMD), Bluetooth opt-in, USBGuard snapshot, audit
|
||
baseline run, `veilor-doctor` first run. Each step skippable, runs
|
||
once on first SDDM login, self-deletes the autostart after. This is
|
||
the **only** UX feature that ships in v0.6 day one — everything else
|
||
builds on it.
|
||
- **`veilor-doctor`** (PROMOTED — user-facing, not just dev tool) —
|
||
the post-install audit. Walks `getenforce`, `mokutil --sb-state`,
|
||
`firewall-cmd`, fail2ban, USBGuard policy, sysctl drift, and reports
|
||
drift from baseline. Runs from `veilor-postinstall` on day one, then
|
||
weekly via `systemd --user` timer. Plain-English output ("your
|
||
firewall is OK", "USBGuard policy has 3 unknown devices"); not a JSON
|
||
dump. **Stretch:** machine-readable mode for `veilor-server` later.
|
||
- **`veilor-update`** — wraps `dnf upgrade` AND `flatpak update` in
|
||
one command. Per `feedback_system_update.md`, partial-update is a
|
||
recurring trap; veilor's update tool covers both by default. Adds
|
||
pre-check (snapshot available?), auditd pause, post-update SELinux
|
||
validation.
|
||
- **Opt-in installer ISO** — flip from live-only to live + installer,
|
||
user picks at boot menu. Installer uses the v0.5 kickstart with full
|
||
LUKS + btrfs subvols + zram.
|
||
- **First-boot UX** — replace TTY password prompt with a small
|
||
Plymouth-rendered dialog. Less raw.
|
||
- **Bluetooth opt-in helper** — single command to enable + bring up
|
||
the daemon + add the user to the right group.
|
||
|
||
---
|
||
|
||
## v0.7 — public flex + bootc spike
|
||
|
||
Take veilor-os out of "private repo, contained audience" mode. Order
|
||
matters: people demand threat model FIRST when a security distro goes
|
||
public, benchmarks come after.
|
||
|
||
1. **Threat model published** (FIRST — gating item) — what veilor-os
|
||
defends against, what it does not. Honest scope. No claim of
|
||
anti-state-actor; concrete on lost-laptop, USB-attack, browser
|
||
compromise, supply-chain. Reviewers will demand this before reading
|
||
anything else.
|
||
2. **Public docs site** — Hugo or mdBook on `veilor.org`, generated
|
||
from `docs/`. Single source of truth.
|
||
3. **Repo public** — flip GitHub visibility, announce.
|
||
4. **Comparison + benchmarks** — published numbers vs stock Fedora KDE
|
||
on cold boot, idle RAM, idle network egress, suspend/resume time.
|
||
After threat model, not before.
|
||
5. **Press kit** — wallpapers, logo, screenshots, feature one-liner.
|
||
|
||
### bootc-image-builder spike (PROMOTED from v1.0+)
|
||
|
||
The v0.5.27–31 grind cost us hours on anaconda + RPM-6.0 +
|
||
`--cmdline` mode brittleness: three install failures, kernel-cmdline
|
||
written to four different places before one worked, transaction-progress
|
||
patches that masked real bugs. **bootc-image-builder builds a
|
||
`Containerfile` once and gets a bootable image** — no anaconda, no
|
||
kickstart, no `%post --nochroot` vs `%post`, no
|
||
`CollectKernelArgumentsTask`. A v0.7 spike (NOT v1.0) evaluates whether
|
||
the next major rev should rebase on it. Spike outcome determines
|
||
whether `veilor-atomic` (stretch goal) becomes the mainline.
|
||
|
||
---
|
||
|
||
## v1.0 — production
|
||
|
||
The line where veilor-os is recommended for a non-author user as a
|
||
daily driver.
|
||
|
||
- **Multi-arch.** x86_64 today; v1.0 ships aarch64 ISO too (laptops
|
||
on ARM are real now). Build matrix in CI.
|
||
- **LTS commitment** — major versions tied to Fedora's release cadence,
|
||
patch releases for security only, documented EOL per major.
|
||
- **Recovery ISO** — minimal rescue image with veilor tools (LUKS
|
||
unlock, btrfs scrub, sysctl reset, fail2ban unban) for "I cannot log
|
||
in to my system" days.
|
||
- **TPM2 integration** — sealed LUKS unlock against TPM2 PCRs (opt-in,
|
||
default stays password). Ships as helper script, not silent default.
|
||
- **Signed update channel** — beyond GPG-signed ISOs, a signed metadata
|
||
repo so `veilor-doctor` can detect available updates without trusting
|
||
Fedora's mirrorlists alone.
|
||
|
||
---
|
||
|
||
## Stretch goals — not on the v0.x → v1.0 critical path
|
||
|
||
These are spin variants that share veilor-os DNA but need their own
|
||
kickstart or build tool.
|
||
|
||
- **`veilor-server`** — no KDE, no GUI, hardened headless Fedora for
|
||
homelab / VPS (e.g. nullstone). Same overlay, different package set.
|
||
**Not blocked**, but waits on `veilor-doctor` machine-readable mode
|
||
(v0.6) so headless installs have a way to report drift without a TUI.
|
||
- **`veilor-kiosk`** — single-app Plasma session, locked-down user,
|
||
read-only root. **Not blocked.**
|
||
- **`veilor-atomic`** — rpm-ostree / bootc-image-builder rebase.
|
||
Status now depends on the **v0.7 bootc spike**: if the spike shows
|
||
bootc fixes the anaconda-grind class of bugs, `veilor-atomic`
|
||
becomes the v1.0+ mainline rather than a stretch variant. If not,
|
||
it stays a parallel track.
|