Per docs/research/2026-05-05-agent-wave/README.md priority list.
All 7 land together to keep iteration cycles useful — partial fixes
bury the lookahead findings agents already mapped.
## 1. CRITICAL — suspend/resume wifi death (Agent 9, B2)
`veilor-modules-lock.service` runs `kernel.modules_disabled=1` 30s
after graphical.target. iwlwifi/iwlmvm/cfg80211 reload on resume
from S3/S0ix → with modules locked, resume breaks wifi until
reboot. Same architectural class as the LUKS bug — security feature
breaks legitimate kernel state transitions.
The unit already has `ConditionKernelCommandLine=!module.sig_enforce=1`
(self-skip when signed-modules enforcement is on cmdline). Adding
`module.sig_enforce=1` to the kernel cmdline retains the security
property (no unsigned modules) without runtime lock-down → resume
works.
Files: kickstart/veilor-os.ks line 61 + overlay/usr/local/bin/veilor-installer
generated bootloader directive both gain `module.sig_enforce=1`.
## 2. veilor-firstboot.service WantedBy=graphical.target (Agent 2)
Was `WantedBy=multi-user.target` only. Real installs default to
graphical.target so the unit never ran on installed systems — admin
pw stayed at install-time + chage -d 0 expired, SDDM PAM bounced
to chauthtok screen (recoverable but ugly UX).
Now `WantedBy=graphical.target multi-user.target`. Live ISO +
multi-user installs both resolve via this list.
## 3. USBGuard hash → id-based baseline (Agent 9, A3)
Mirrors memory feedback_usbguard_dock.md — onyx had hash+parent-hash
rules that broke on dock replug; we shipped no rules.conf so first
boot blocks the USB keyboard.
Adds overlay/etc/usbguard/rules.conf with HID-class allow rule
(`allow with-interface match-all { 03:*:* }`) — covers every USB
keyboard, mouse, gamepad, fingerprint reader, NFC. Survives dock
replug + kernel-bump vendor renumeration. Mass-storage stays
implicit-block; user explicitly allows post-firstboot via
`ujust veilor-usbguard-enroll` (planned v0.6).
## 4. firewalld trusted zone with tailscale0 pre-bound (Agent 9, D1)
User uses Tailscale daily (memory: project_tailscale_mesh.md).
Default firewalld zone = drop, blocks tailnet traffic on tailscale0.
Adds overlay/etc/firewalld/zones/trusted.xml with
`<interface name="tailscale0"/>`. After `tailscale up` brings the
interface up, NetworkManager dispatcher associates it with the
trusted zone automatically — no user intervention.
Default zone stays drop. Only the tailscale0 interface gets ACCEPT.
## 5. /etc/skel branding (Agent 7)
Was completely empty. Result: per-user KDE config (~/.config/kdeglobals
etc.) pre-empty, so the moment user opened System Settings, KDE wrote
fresh ~/.config/* and silently shadowed our /etc/xdg/kdedefaults/*.
Visual brand evaporated on first click.
Seeds:
/etc/skel/.config/kdeglobals (copy of assets/kde/veilor-default.kdeglobals)
/etc/skel/.config/breezerc (copy of assets/kde/breezerc)
/etc/skel/.config/kwinrc (Plasma 6 wayland defaults: opengl, animspeed=0,
blur off, click-to-focus)
/etc/skel/.config/konsolerc (default profile = Veilor)
/etc/skel/.local/share/konsole/Veilor.profile + .colorscheme
User who opens System Settings now writes against branded baseline,
not against vanilla Breeze.
## 6. KMS modeset args + initramfs keymap (Agents 1 + 9)
Real laptop boot has a 5-15s blank between vt switch and SDDM start
because simpledrm releases before i915/nvidia-drm/amdgpu claim. Plus
non-US users get locked out at LUKS prompt because initramfs ships
en-US keymap by default (RHBZ 1405539, RHBZ 1890085).
Adds to bootloader cmdline (live + installed):
i915.modeset=1 amdgpu.modeset=1 nvidia-drm.modeset=1
rd.vconsole.keymap=us
`rd.vconsole.keymap=us` is a placeholder; the v0.6 firstboot keymap
picker will rewrite it from /etc/vconsole.conf. Until then, en-US
users get correct LUKS keyboard; non-US users still need the v0.6
fix (per Agent 1).
## 7. virtio-9p log capture (Agent 6)
The v0.5.30 virtio-serial wiring depends on rsyslog inside the live
ISO (anaconda's setupVirtio writes a rsyslog forward rule), which
the live ks doesn't install — files were 0-byte across three
install runs.
test/run-vm.sh now adds a `-virtfs local,...,mount_tag=hostlogs`
share pointing at `test/test-runs/<timestamp>/`. veilor-installer
runs `_dump_logs_to_host` via EXIT trap that mounts the share at
/mnt/hostlogs and rsyncs /tmp/{anaconda,program,storage,packaging,dnf}.log
+ /var/log/veilor-installer.log + dmesg + journalctl + the generated
ks. Runs on success AND failure AND ^C.
No-op on real hardware (9p tag absent) — VM-only debug.
## Validate
bash -n overlay/usr/local/bin/veilor-installer # OK
ksvalidator kickstart/veilor-os.ks # clean
## Out-of-scope for v0.5.32 (deferred to v0.6)
Per Agent 1 follow-ups: argon2id retune for slow CPUs, recovery key
generation in firstboot, TPM2/FIDO2 unlock helpers. Per Agent 9
follow-ups: Plasma Wayland fallback X11 install, lid-close handling,
SELinux relabel progress UX. Per Agent 4: AppArmor stack +
nftables preset + audit log shipping CLI.
Per Agent 8 (CI hardening): SHA-pin actions + dependabot + SBOM +
SLSA L3 attestation — separate workflow-only commit.
|
||
|---|---|---|
| .. | ||
| test-runs | ||
| auto-install-keymap.sh | ||
| auto-install.sh | ||
| boot-checklist.md | ||
| METHOD-CHANGELOG.md | ||
| README.md | ||
| run-vm.sh | ||
| TESTING.md | ||
test/
Test harnesses for veilor-os ISO builds.
Files
| File | Purpose |
|---|---|
run-vm.sh |
Manual smoke test — boot the latest ISO interactively in QEMU/KVM. SSH key injection via cloud-init seed + monitor sendkey fallback for live-image login. |
auto-install.sh |
Autonomous end-to-end install test. Boots ISO, drives the gum installer via QEMU monitor sendkey, waits for anaconda to finish + reboot, SSHs into the installed system, runs validation checklist. Prints PASS/FAIL summary. |
auto-install-keymap.sh |
Sourced helper. Provides km_send_str, km_send_chord, km_send_key, km_screendump, km_wait_socket, etc. Reusable by other automation. |
boot-checklist.md |
Manual post-install checklist (run on a real spare laptop). |
Running the autonomous installer test
./test/auto-install.sh build/out/veilor-os-*.iso
Hardcoded inputs (deterministic — do not edit during a test run):
- Disk: first
/dev/vda(the only disk in QEMU) - Hostname:
veilor(installer hardcoded since v0.5.4) - LUKS passphrase:
testpass1234 - Admin password:
adminpass1234 - Locale:
en_GB.UTF-8
Expected runtime: 20–30 minutes wall clock (anaconda dominates).
Outputs
/tmp/veilor-auto-install.log— full driver log/tmp/veilor-auto-install-NN-<step>.png— milestone screenshots/tmp/veilor-auto-install-final-ssh.txt— final SSH session capture (uname/lsblk/cmdline/failed units)
Exit codes
0— all validation checks passed1— any failure (anaconda crashed, SSH never came up, validation check failed)2— preflight failure (missing tool, bad ISO arg, missing OVMF)
Prerequisites
qemu-system-x86_64,qemu-img,socat,ssh,ssh-keygenedk2-ovmf(OVMF UEFI firmware at/usr/share/edk2/ovmf/OVMF_{CODE,VARS}.fd)mkisofsorxorriso(for cloud-init seed ISO; harness falls back to TTY1 driving if seed cannot be built or cloud-init does not run on the installed system)convertfrom ImageMagick (optional — converts PPM screendumps to PNG; harness keeps PPM if absent)- KVM access (
/dev/kvmreadable by the user)
What it validates
Post-install on the booted system:
/etc/os-release→NAME=veilor-oshostnamectl --static→veilorsystemctl is-active→activeforsshd fail2ban usbguard tuned auditd firewalld chronyd sddmgetenforce→Enforcing(preferred) orPermissive(acceptable for v0.5.x)lsblk -fshowscrypto_LUKS+btrfs/etc/crypttabhas a LUKS entrygetent passwd adminreturns the user/usr/local/bin/{veilor-power,veilor-doctor,veilor-update}are present and executable/proc/cmdlinecontainsinit_on_alloc=1
Troubleshooting
- Stuck at boot banner: ISO didn't autostart
veilor-installeron tty1. Checkserial.logandauto-install-vm-NN-*.pngscreenshots. The harness aborts after 5 minutes of identical screen frames. - SSH never up: cloud-init may not have run on the installed system (no
cidatamount). The harness falls back to TTY1 driving — typing the LUKS passphrase, logging in as admin, and hand-injecting the SSH key. If both paths fail, validation cannot proceed. screendumpproduces unreadable PPM: install ImageMagick (dnf install ImageMagick) so the harness converts to PNG.