10 Commits
Author SHA1 Message Date
NeilClack 240be2540f Update Radiantwave
build-prod.yml / update-and-build (push) Canceled after 0s
2026-08-08 01:44:03 -05:00
NeilClack 1f3e194aa5 Chore: Update Radiantwave-dev 2026-08-08 06:25:05 +00:00
NeilClack e3120f27c2 Pull back from radiantwave-cpp-dev to radiantwave-dev 2026-08-08 00:02:09 -05:00
NeilClack 8abb028c82 fix wpctl volume pinning 2026-08-07 23:58:25 -05:00
NeilClack 1e0380a8c4 remove automated builds, favoring intentional builds 2026-08-07 23:58:02 -05:00
NeilClack 4580319f19 Update radiantwave-dev 2026-08-07 22:17:52 -05:00
NeilClack 42b68842ff Fix various small issues 2026-08-07 22:17:24 -05:00
NeilClack 835e1b0f0c Remove gitea authentication setup 2026-08-07 20:41:09 -05:00
NeilClack 2e3d88b57d Update Plymount dontUnpack = true; 2026-08-07 17:47:04 -05:00
NeilClack e0a95e015c Attempt Gitea auth 2026-08-07 17:41:24 -05:00
8 changed files with 203 additions and 112 deletions
+1 -5
View File
@@ -1,8 +1,4 @@
on:
push:
branches:
- dev
workflow_dispatch:
jobs:
@@ -31,7 +27,7 @@ jobs:
- name: Rename kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-dev-iso-${ISO_DATE}.iso"
FILENAME="radiantwave-kiosk-dev-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
-4
View File
@@ -13,10 +13,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
# - name: Configure git auth for Gitea
# run: |
# git config --global url."https://oauth2:${{ secrets.GIT_TOKEN }}@gitea.radiantwavetech.com/".insteadOf "https://gitea.radiantwavetech.com/"
- name: Update radiantwave
run: |
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
+17 -8
View File
@@ -72,7 +72,7 @@ in
};
system.activationScripts.cleanRadiantFiles = ''
rm -rf /home/kiosk/.local/share/radiantwave/audio
rm -rf /home/kiosk/.local/radiantwave/audio
'';
# Virtual machine declaration
@@ -108,7 +108,7 @@ in
users.users.kiosk = {
isNormalUser = true;
uid = 1000;
extraGroups = ["audio" "video" "input" "networkmanager" "wheel"];
extraGroups = ["audio" "video" "input" "networkmanager" "wheel" "seat"];
openssh.authorizedKeys.keys = myKey;
password = "Fuckp@ssw0rds";
};
@@ -173,11 +173,13 @@ in
Type = "oneshot";
};
script = ''
# Wait until WirePlumber exposes at least one sink
# Wait until WirePlumber exposes at least one sink.
# `wpctl list` output is tab-separated: ID, name, media/object type,
# then `*` if the node is the current default. `cut -f1` grabs the ID.
sinks=""
for i in {1..30}; do
sinks=$(${pkgs.wireplumber}/bin/wpctl list audio sinks 2>/dev/null \
| ${pkgs.gnused}/bin/sed -nE 's/^.*[^0-9]([0-9]+)\. .*$/\1/p')
| ${pkgs.coreutils}/bin/cut -f1)
if [ -n "$sinks" ]; then
break
fi
@@ -193,6 +195,10 @@ in
# Fallback in case the sink list came up empty
${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0 2>/dev/null || true
${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ 0 2>/dev/null || true
# Persist 100% as WirePlumber's default for any brand-new sink so it
# comes up at full volume even before this service runs on next boot.
${pkgs.wireplumber}/bin/wpctl settings device.routes.default-sink-volume 1.0 --save 2>/dev/null || true
'';
};
@@ -207,7 +213,7 @@ in
# --- Set ownership of Radiantwave files ---
systemd.tmpfiles.rules = [
"d /home/kiosk/.local/share/radiantwave 0770 kiosk kiosk -"
"d /home/kiosk/.local/radiantwave 0770 kiosk kiosk -"
];
# --- Backup service: runs before nixos-upgrade ---
@@ -220,8 +226,8 @@ in
User = "kiosk";
};
script = ''
BACKUP_DIR="/home/kiosk/.local/share/radiantwave-backup"
SOURCE_DIR="/home/kiosk/.local/share/radiantwave"
BACKUP_DIR="/home/kiosk/.local/radiantwave-backup"
SOURCE_DIR="/home/kiosk/.local/radiantwave"
mkdir -p "$BACKUP_DIR"
@@ -244,7 +250,10 @@ in
ExecStartPre = "${pkgs.coreutils}/bin/sleep 90";
};
script = ''
if ${pkgs.procps}/bin/pgrep -x radiantwave > /dev/null; then
# The installed `radiantwave` is a makeWrapper script that execs the real
# binary (`.radiantwave-unwrapped`), so the process comm is not exactly
# `radiantwave`; match the exec'd binary's command line instead.
if ${pkgs.procps}/bin/pgrep -f '\.radiantwave-unwrapped' > /dev/null; then
echo "RadiantWave is running, upgrade successful"
exit 0
fi
Generated
+13 -13
View File
@@ -200,11 +200,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1785967620,
"narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=",
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436",
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
"type": "github"
},
"original": {
@@ -220,11 +220,11 @@
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1785742851,
"narHash": "sha256-WX8hpYpgoEwKRKRkszjCjx+dgZYXE8DSN15+0Sest9g=",
"lastModified": 1786170011,
"narHash": "sha256-Vx/3kwIQFRYDZQtVdcdGgJPnNa2Y44HRYZyJAeug6OI=",
"ref": "main",
"rev": "b54dbca2d5e7d6d35b6e596565a0d963a6922c4d",
"revCount": 244,
"rev": "312f5e2a90e03f32ce61d6db54f46b9adac60933",
"revCount": 250,
"type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
},
@@ -240,18 +240,18 @@
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1786139696,
"narHash": "sha256-fLcmVYU2BNpl0P2M9WgoJohL3t0n1EIJQz1TAe/NwrE=",
"lastModified": 1786170011,
"narHash": "sha256-Vx/3kwIQFRYDZQtVdcdGgJPnNa2Y44HRYZyJAeug6OI=",
"ref": "dev",
"rev": "cad834f2321f925e46f36797a11282e9c73fdf47",
"revCount": 6,
"rev": "312f5e2a90e03f32ce61d6db54f46b9adac60933",
"revCount": 250,
"type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git"
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
},
"original": {
"ref": "dev",
"type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git"
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}
},
"root": {
+6 -4
View File
@@ -5,7 +5,8 @@
disko.inputs.nixpkgs.follows = "nixpkgs";
nixos-facter-modules.url = "github:numtide/nixos-facter-modules";
radiantwave.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=main";
radiantwave-dev.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git?ref=dev";
radiantwave-dev.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=dev";
# radiantwave-dev.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git?ref=dev";
nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
};
@@ -35,6 +36,7 @@
nativeBuildInputs = [ pkgs.librsvg ];
src = ./assets/RWT-Circular-Color-ForOnDark.svg;
dontUnpack = true;
buildPhase = ''
mkdir -p $out/share/plymouth/themes/radiantwave
@@ -52,7 +54,7 @@
'';
};
mkKioskSystem = { system, radiantwave, upgradeFlakeRef, extraModules ? [], diskModule, enableAutoUpgrade ? true, extraSpecialArgs ? {}}:
mkKioskSystem = { system, radiantwave, upgradeFlakeRef, extraModules ? [], diskModule, extraSpecialArgs ? {}}:
nixpkgs.lib.nixosSystem {
inherit system;
@@ -73,7 +75,7 @@
] ++ extraModules;
};
mkRpiKioskSystem = { radiantwave, upgradeFlakeRef, extraModules ? [], enableAutoUpgrade ? true }:
mkRpiKioskSystem = { radiantwave, upgradeFlakeRef, extraModules ? [] }:
nixos-raspberrypi.lib.nixosSystem {
specialArgs = {
inherit radiantwave upgradeFlakeRef;
@@ -140,7 +142,7 @@
# Commercial-dev
radiantwavekiosk-commercial-dev = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
radiantwave = radiantwave-dev;
diskModule = ./commercial-disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-commercial";
extraModules = [];
-29
View File
@@ -1,29 +0,0 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-label/nixos";
fsType = "xfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-label/EFIBOOT";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.enableRedistributableFirmware = true;
}
+166
View File
@@ -0,0 +1,166 @@
# 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`
```nix
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.
- [X] **Fix:** add `"seat"` to `extraGroups`.
**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`
```nix
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.
- [x] **Fix:** match on the actual process, e.g. `pgrep -f '/radiantwave'` or `pgrep -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`
```nix
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.
- [X] **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_DIR` under `.local/share/radiantwave`
- `configuration.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.
- `cleanRadiantFiles` is 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.
- [X] **Fix:** replace `share/radiantwave` with `radiantwave` in 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:
```nix
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-tokens` token in plaintext.
- Plaintext kiosk password (`Fuckp@ssw0rds`); the user is in `wheel` and 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/`).
- [X] **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.
- [X] **Fix:** use `enableAutoUpgrade` to gate `system.autoUpgrade.enable`, or remove the dead parameter.
### 10. Dead files
- `hardware/x86_64-nvme-uefi.nix` — not referenced by `flake.nix`.
- `vm-disk-config.nix` — not referenced by `flake.nix`.
- [ ] **Fix:** delete `hardware/x86_64-nvme-uefi.nix` and `vm-disk-config.nix`, or wire them into `flake.nix`.
---
## Verified not-bugs
- **Unprivileged `ping` works.** NixOS sets `net.ipv4.ping_group_range = mkDefault "0 2147483647"` (`nixos/modules/tasks/network-interfaces.nix:1786-1787`), so the 10s `loginShellInit` network 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's `plymouth-initrd-themes` runCommand rewrites initrd store paths again (`sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out,"`), so `ImageDir`/`ScriptFile` resolve in both initrd and runtime.
- **`sudo -n plymouth quit --wait` works.** The `security.sudo.extraRules` NOPASSWD rule (`configuration.nix:46-56`) matches; NixOS default sudoers `secure_path` includes `/run/current-system/sw/bin`.
- **`wlr-randr` parsing in `rotated_display.nix:5` is correct.** Output header is `DP-1 "…"` — the first field is the output name, so `grep -m1 '^\S' | awk '{print $1}'` yields the right name.
- **`radiantwave-dev` exposes the needed outputs.** `nixosModules.default` and `packages.default` exist for `x86_64-linux` and `aarch64-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.** `seatd` and `plymouth-quit` set `restartIfChanged = false`.
---
## Priority fix order
- [ ] 1. Add `"seat"` to kiosk `extraGroups` (`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-dev` to `radiantwave-dev` + `-dev` upgrade ref (`flake.nix:142-148`).
- [ ] 4. Parameterize the ISO config so `android-iso` installs `radiantwavekiosk-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).
-49
View File
@@ -1,49 +0,0 @@
{ lib, ... }:
{
disko.devices = {
disk.disk1 = {
device = lib.mkDefault "/dev/vda";
type = "disk";
content = {
type = "gpt";
partitions = {
boot = {
name = "boot";
size = "1M";
type = "EF02";
};
esp = {
name = "ESP";
size = "500M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
swap = {
name = "swap";
size = "16G";
content = {
type = "swap";
};
};
root = {
name = "root";
size = "100%";
content = {
type = "filesystem";
format = "xfs";
mountpoint = "/";
mountOptions = [
"defaults"
"pquota"
];
};
};
};
};
};
};
}