8.7 KiB
KioskConfig Review Report
Verification of kioskconfig (target: radiantwavekiosk-dev) against the app source in radiantwave-rebuild/ (flake input radiantwave-dev → radiantwave-cpp.git?ref=dev).
Severity legend: Critical = blocks boot/launch · High = wrong behavior in production · Medium = wrong behavior in a variant · Low = hygiene.
Critical
1. Kiosk user is missing the seat group — cage/app can't get a seat
Location: configuration.nix:111
extraGroups = ["audio" "video" "input" "networkmanager" "wheel"]; # missing "seat"
Why it breaks: NixOS services.seatd owns /run/seatd.sock as root:seat (nixos/modules/services/desktops/seatd.nix, default group = "seat"). wlroots uses libseat, which connects to the seatd socket. Without seat group membership libseat_open_seat fails, and there is no logind fallback: getty autologin creates a tty (not graphical) session, which the logind backend rejects. The NixOS seatd test (nixos/tests/seatd.nix) explicitly adds the user to seat.
Result: exec cage -- radiantwave exits immediately — the app never appears on screen.
- Fix: add
"seat"toextraGroups.
Also affected: radiantwave-rebuild/nixos/vm.nix:85 has the same omission.
High
2. Healthcheck can never match → 10-minute rollback loop
Location: configuration.nix:247
if ${pkgs.procps}/bin/pgrep -x radiantwave > /dev/null; then
Why it breaks: The installed radiantwave is a makeWrapper script — nix/package.nix:132-134 renames the real binary to .radiantwave-unwrapped, and the wrapper ends with exec .radiantwave-unwrapped. The kernel sets comm from the exec'd file, truncated to 15 chars: .radiantwave-unw. pgrep -x radiantwave (exact match) never matches.
Result: Every autoUpgrade (dates = "*:00/10" → every 10 min) is followed ~90s later by nixos-rebuild switch --rollback, so the system oscillates forward/backward forever and upgrades never stick.
- Fix: match on the actual process, e.g.
pgrep -f '/radiantwave'orpgrep -x .radiantwave-unw, or use a different liveness check.
Related design flaw: after switch, the running app is still the old binary (the login session persists; loginShellInit doesn't re-run), so even a correct healthcheck can't validate the new build — only a reboot can.
3. radiantwavekiosk-commercial-dev deploys production code
Location: flake.nix:142-148
radiantwavekiosk-commercial-dev = mkKioskSystem {
radiantwave = radiantwave; # should be radiantwave-dev
...
upgradeFlakeRef = "...KioskConfig.git?ref=dev#radiantwavekiosk-commercial"; # should be ...-dev
Result: a "dev" commercial kiosk runs the production binary and auto-upgrades to the production config. Same bug class as finding #5's root cause: hand-wired per-variant wiring.
- Fix:
radiantwave = radiantwave-dev;and#radiantwavekiosk-commercial-dev.
4. Backup + tmpfiles use the wrong data directory
Locations:
configuration.nix:210— tmpfiles:d /home/kiosk/.local/share/radiantwave 0770 kiosk kiosk -configuration.nix:223-224— backup:BACKUP_DIR/SOURCE_DIRunder.local/share/radiantwaveconfiguration.nix:74-76—cleanRadiantFiles:rm -rf /home/kiosk/.local/share/radiantwave/audio
Why it's wrong: the app uses ~/.local/radiantwave/ (verified: config_manager.cpp:36, database_manager.cpp:36, logger.cpp:70, audio_downloader.cpp:22, scroller_page.cpp:766). ~/.local/share/radiantwave is the wrong path.
Result:
-
Backup rsyncs an empty/nonexistent dir every upgrade → pre-upgrade backup is useless.
-
cleanRadiantFilesis a silent no-op (audio never actually cleaned). -
The app creates its own dirs via
create_directories, so the wrong-path tmpfiles rule is harmless functionally — but wrong. -
Fix: replace
share/radiantwavewithradiantwavein all three places.
Caution: clarify cleanRadiantFiles intent — if the path were "fixed" naively it would wipe downloaded audio on every activation.
Medium
5. Android ISO installs the wrong config
Locations: flake.nix:215-236, iso-config.nix:8-12
android-iso reuses ./iso-config.nix, which hardcodes:
targetSystem = self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel;
nixos-install --system installs the plain (non-rotated) radiantwavekiosk closure even though the ISO ships radiantwavekiosk-android via isoImage.storeContents. The rotated variant never gets installed.
- Fix: parameterize the ISO config (a TODO already exists in
commercial-iso-config.nix) or add an android-specific ISO config.
Low
6. -d -s launch flags are dead
Locations: rotated_display.nix:7, configuration.nix:145
Both invoke radiantwave -d -s, but main.cpp:17 (SDL_AppInit(void **appstate, int argc, char *argv[])) never parses argc/argv — there is no getopt/argv handling anywhere in the source. The flags are silently ignored.
- Fix: implement the flags in the app's CLI parsing, or drop them from the launch commands.
7. Secrets committed
Locations: configuration.nix:64, configuration.nix:113
-
Gitea
nix.settings.access-tokenstoken in plaintext. -
Plaintext kiosk password (
Fuckp@ssw0rds); the user is inwheeland has SSH key + NetworkManager access, so the password effectively grants root. -
Fix: rotate both; the repo already has
.sops.yaml/ age encryption for secrets.
8. CI trigger mismatch (AGENTS.md stale)
Location: .gitea/workflows/build-dev.yml:1-6
The workflow triggers on push to dev + workflow_dispatch, but AGENTS.md documents a repository_dispatch (radiantwave-dev-built) trigger that isn't in the workflow. If the app repo dispatches that event, CI won't fire. Also note the workflow lives in .gitea/workflows/ (AGENTS.md says .forgejo/workflows/).
- Fix: Ignore this; Gitea does not yet support repository_dispatch
9. Dead enableAutoUpgrade parameter
Location: flake.nix:56
mkKioskSystem accepts enableAutoUpgrade ? true but never uses it; all variants auto-upgrade unconditionally. If the intent was to disable auto-upgrade on dev systems, it doesn't work.
- Fix: use
enableAutoUpgradeto gatesystem.autoUpgrade.enable, or remove the dead parameter.
10. Dead files
-
hardware/x86_64-nvme-uefi.nix— not referenced byflake.nix. -
vm-disk-config.nix— not referenced byflake.nix. -
Fix: delete
hardware/x86_64-nvme-uefi.nixandvm-disk-config.nix, or wire them intoflake.nix.
Verified not-bugs
- Unprivileged
pingworks. NixOS setsnet.ipv4.ping_group_range = mkDefault "0 2147483647"(nixos/modules/tasks/network-interfaces.nix:1786-1787), so the 10sloginShellInitnetwork wait works as the kiosk user. iputils built without setcap is fine. - Plymouth theme is correct in both phases. The flake's sed rewrites
/usr/→ store path, and the NixOS module'splymouth-initrd-themesrunCommand rewrites initrd store paths again (sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out,"), soImageDir/ScriptFileresolve in both initrd and runtime. sudo -n plymouth quit --waitworks. Thesecurity.sudo.extraRulesNOPASSWD rule (configuration.nix:46-56) matches; NixOS default sudoerssecure_pathincludes/run/current-system/sw/bin.wlr-randrparsing inrotated_display.nix:5is correct. Output header isDP-1 "…"— the first field is the output name, sogrep -m1 '^\S' | awk '{print $1}'yields the right name.radiantwave-devexposes the needed outputs.nixosModules.defaultandpackages.defaultexist forx86_64-linuxandaarch64-linux(RPi dev OK).- Disk configs match target hardware.
disk-config.nix→/dev/nvme0n1(NUC),commercial-disk-config.nix→/dev/sda. - Rollback churn won't kill the session.
seatdandplymouth-quitsetrestartIfChanged = false.
Priority fix order
- 1. Add
"seat"to kioskextraGroups(configuration.nix:111). Unblocks the app. - 2. Fix the healthcheck matcher (
configuration.nix:247) and wrong data dirs (configuration.nix:74-76, 210, 224). - 3. Wire
radiantwavekiosk-commercial-devtoradiantwave-dev+-devupgrade ref (flake.nix:142-148). - 4. Parameterize the ISO config so
android-isoinstallsradiantwavekiosk-android. - 5. Rotate committed secrets.
Open item
Whether the seat-group issue is field-confirmed. If a deployed NUC currently boots into the app, finding #1 isn't biting and the mechanism needs re-checking (e.g. different seatd group config or a graphical session somewhere).