62 Commits
Author SHA1 Message Date
NeilClack e22b466bb3 Update RadiantWave - Fixed scaling issues 2026-08-23 18:03:14 -05:00
NeilClack bd9146e641 Allow kiosk to restart getty@tty1 via scoped polkit rule
Build Dev ISO / build-dev-iso (push) Successful in 4m23s
The RadiantWave app can now apply pending updates by restarting its own
TTY session (plain systemctl, no sudo): getty re-autologins kiosk and
the login shell relaunches cage + app from the new generation.

Also drop the cleanRadiantFiles activation script.
2026-08-23 17:54:01 -05:00
NeilClack 9b0036b4da Update RadiantWave ef723b2
Build Dev ISO / build-dev-iso (push) Successful in 4m48s
2026-08-23 17:33:57 -05:00
NeilClack d26cec2a53 fix: broken whitespace guard in archive-images.sh
Build Dev ISO / build-dev-iso (push) Successful in 4m19s
The case bracket expression [\ space\'\"] listed the letters s,p,a,c,e
as a character set instead of matching whitespace, rejecting every normal
path. Use the POSIX [[:space:]] class.
2026-08-23 15:55:05 -05:00
NeilClack 2e862c13a8 fix: replace fragile ssh archive one-liners with tools/archive-images.sh
Build Dev ISO / build-dev-iso (push) Failing after 3m18s
The inline find -exec broke through the double shell hop (the remote
shell consumed the ; separator). The script pipes its payload to remote
bash via stdin, tolerates zero matches, and fails loudly on missing
directories or failed moves.
2026-08-23 15:45:11 -05:00
NeilClack 84ec13b1f9 ci: restore dev ISO workflow, auto-build on dev push, use Attic
Build Dev ISO / build-dev-iso (push) Failing after 3m19s
2026-08-23 15:22:34 -05:00
NeilClack 588f0e4aa1 ci: pull closures from Attic caches in prod builds 2026-08-23 15:22:34 -05:00
NeilClack 46384e6cf7 Fix attic upload
build-dev / nix-build (push) Failing after 1s
2026-08-23 15:07:22 -05:00
NeilClack 6951d35310 fix: make manual dev checkout work (fetch all branch tips, drop bad cd) 2026-08-23 14:53:32 -05:00
NeilClack 7778da3867 fix: tolerate empty archive globs; clone dispatched ref in dev workflow 2026-08-23 14:49:44 -05:00
NeilClack 59e9f7ce29 Update RadiantWave and add Attic cache 2026-08-23 14:18:48 -05:00
NeilClack 3ec72c8479 Bring radiantwave up to date + dev 2026-08-23 11:24:47 -05:00
NeilClack 20d91df9eb Revert RadiantWave for testing the new update configuration 2026-08-23 11:23:21 -05:00
NeilClack 65a6b256f9 Fix dev/prod split and dev ISOs; consolidate zero-touch installer
- Wire -dev variants to the radiantwave-dev input (?ref=dev); prod keeps main
- Fix android-dev upgradeFlakeRef (was upgrading into production config)
- Parameterize one installer module (zero-touch-installer.nix); replace the
  four near-duplicate ISO configs; mkIso pairs each ISO with its closure +
  disk layout, fixing commercial-dev/android-dev ISO eval errors
- Add missing packages outputs (commercial-dev, android-dev, rpi, rpi-dev)
- Set networking.hostName + system.configurationRevision per variant
- Remove gitea access token and dead netrc/JWT config (repos are public)
- Drop flake.lock update step from CI (lock updates are manual)
- Refresh AGENTS.md: variants/ISO tables, facter report procedure, gotchas
2026-08-23 09:58:46 -05:00
NeilClack 64b2a9cfc4 Shrink splash screen 2026-08-23 08:20:10 -05:00
NeilClack 875f3da03d Add tools 2026-08-22 17:07:54 -05:00
NeilClack 9965e30152 Fix git urls 2026-08-22 17:07:47 -05:00
NeilClack a01c3d5521 Update RadiantWave 2026-08-22 16:29:56 -05:00
NeilClack 33c9ceefb0 Update RadiantWave
Enables the naming of audio files by editing audio file names in new_checksums.md5
2026-08-21 10:04:40 -05:00
NeilClack c9743de7bb Update RadiantWave 2026-08-21 09:54:11 -05:00
NeilClack 6ddf004e95 Update RadiantWave to remove WiFi Gate 2026-08-18 23:39:22 -04:00
NeilClack 439e646170 Remove archive command 2026-08-18 23:02:32 -04:00
NeilClack f8cb1746af Release RadiantWave (C++) 2026-08-18 04:44:58 -05:00
NeilClack a4f4d17d6e Add archive step to prod workflows; rename radiantwave-iso to radiantwave-home 2026-08-17 22:51:11 -05:00
NeilClack e7a5ffa290 Update Radiantwave to ec6b766 2026-08-17 22:47:16 -05:00
NeilClack 553b06ea92 Fix closure naming' 2026-08-17 22:45:18 -05:00
NeilClack 8e8da490e4 Update radiantwave reference and add dev variants to all images 2026-08-17 22:44:14 -05:00
NeilClack 75cce42de5 Add cleanup command for fileserver 2026-08-17 22:23:37 -05:00
NeilClack 572ab76100 Add name 2026-08-17 22:13:01 -05:00
NeilClack d37c794be4 Fix repository pointers 2026-08-17 22:08:47 -05:00
NeilClack b26081046e Update RadiantWave
build-dev.yml / update-and-build (push) Canceled after 0s
2026-08-17 21:35:20 -05:00
NeilClack 87367dab04 Temporarily remove healthcheck
build-dev.yml / update-and-build (push) Canceled after 1m40s
Healthcheck may be failing for reasons not related to a bad binary, preventing a good binary from booting.
2026-08-17 19:53:06 -05:00
NeilClack 0a35c97379 Remove user password 2026-08-17 19:49:15 -05:00
NeilClack 2fb99175f7 Re-size Plymouth image to 1920x1080 2026-08-17 19:49:01 -05:00
NeilClack 02cde0fabb fix: wait for Wayland compositor before rotating display, add logging
build-dev.yml / update-and-build (push) Canceled after 0s
2026-08-17 14:00:14 -05:00
NeilClack 143119477f ci: split prod builds into separate manually-triggered workflows
build-dev.yml / update-and-build (push) Canceled after 3m26s
2026-08-17 13:57:14 -05:00
NeilClack b584016db2 Remove unused build steps 2026-08-17 13:36:37 -05:00
NeilClack e09758a70e fix: switch radiantwave inputs to SSH for legacy Go repo
build-dev.yml / update-and-build (push) Failing after 4m9s
2026-08-17 12:54:06 -05:00
NeilClack 14463ad99b Just make RadiantWave-Legacy public
build-dev.yml / update-and-build (push) Failing after 9s
For now, to get builds working.
2026-08-17 12:52:11 -05:00
NeilClack 027d1a628f Update token
build-dev.yml / update-and-build (push) Failing after 8s
2026-08-17 12:50:20 -05:00
NeilClack fb2f861258 Revert back to Legacy Radiant Wave
build-dev.yml / update-and-build (push) Failing after 10s
2026-08-17 12:48:22 -05:00
NeilClack 974a610518 Update dev images to new radiantwave
build-dev.yml / update-and-build (push) Failing after 4m34s
2026-08-17 12:43:57 -05:00
NeilClack c71b5ebc84 fix: use SSH clone instead of actions/checkout
build-dev.yml / update-and-build (push) Failing after 3m12s
2026-08-17 12:18:31 -05:00
NeilClack 6656c44de4 fix: disable persist-credentials on checkout (public repo)
build-dev.yml / update-and-build (push) Failing after 28s
2026-08-17 12:17:34 -05:00
NeilClack 2788d27fdc fix: remove checkout token (repo is public)
build-dev.yml / update-and-build (push) Failing after 32s
2026-08-17 12:13:59 -05:00
NeilClack 72a564c9ef fix: add checkout token, adjust workflow triggers
build-dev.yml / update-and-build (push) Failing after 1s
2026-08-17 12:13:40 -05:00
NeilClack 2185792cf4 fix: use actions/checkout@v4 (v6 does not exist)
build-prod.yml / update-and-build (push) Canceled after 16s
2026-08-17 12:11:58 -05:00
NeilClack 3b9c501aa8 Fix actions URLs
build-prod.yml / update-and-build (push) Canceled after 6s
2026-08-17 12:07:10 -05:00
NeilClack 2abdfa2b9b revert upgradeFlakeRef URLs to KioskConfig to match renamed repo
build-prod.yml / update-and-build (push) Canceled after 0s
2026-08-17 11:02:19 -05:00
NeilClack 0cb1337f18 add radiantwave-legacy input with auth token, update flake.lock 2026-08-17 10:57:16 -05:00
NeilClack 50176d8fd5 repoint production to radiantwave-legacy, dev to radiantwave (ref=main)
- Replace radiantwave-dev input with radiantwave-legacy
- Production configs (kiosk, commercial, android, rpi) now use radiantwave-legacy
- Dev configs (kiosk-dev, commercial-dev, rpi-dev) now use radiantwave (ref=main)
- Fix KioskConfig -> kioskconfig case mismatch in all upgradeFlakeRef URLs
2026-08-17 10:51:05 -05:00
NeilClack 06c2a7cd0a Add plan to migrate to DRM
build-prod.yml / update-and-build (push) Canceled after 0s
2026-08-17 10:44:36 -05:00
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
23 changed files with 1675 additions and 711 deletions
+16 -19
View File
@@ -1,22 +1,26 @@
name: Build Dev ISO
on: on:
workflow_dispatch:
push: push:
branches: branches:
- dev - dev
workflow_dispatch: env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave-dev
extra-trusted-public-keys = radiantwave-dev:B8FhLu3MQ9JfeEIHIKNrKxnP+3akzzkqMbTZR4hRfj0=
jobs: jobs:
update-and-build: build-dev-iso:
runs-on: build-server runs-on: build-server
steps: steps:
- name: Checkout - name: Clone Repository
uses: actions/checkout@v6 run: git clone --depth 1 --no-single-branch ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Update radiantwave-dev - name: Checkout dev branch
run: | run: git checkout dev
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix flake update radiantwave-dev
- name: Prepare output directory - name: Prepare output directory
run: mkdir -p /home/user/radiantwave run: mkdir -p /home/user/radiantwave
@@ -31,10 +35,13 @@ jobs:
- name: Rename kiosk ISO - name: Rename kiosk ISO
run: | run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S) 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}" cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV" echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Move old dev images to archive
run: tools/archive-images.sh nclack@157.245.124.103 /mnt/infrastructure_data/files/images /mnt/infrastructure_data/files/images/archives 'radiantwave-kiosk-dev*'
- name: Copy kiosk ISO to fileserver - name: Copy kiosk ISO to fileserver
run: | run: |
scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \ scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \
@@ -42,13 +49,3 @@ jobs:
- name: Cleanup kiosk ISO - name: Cleanup kiosk ISO
run: rm -f "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" run: rm -f "/home/user/radiantwave/${KIOSK_ISO_FILENAME}"
- name: Commit updated flake.lock
run: |
git config user.email "ci@radiantwavetech.com"
git config user.name "RadiantWave CI"
git remote set-url origin https://oauth2:${{ secrets.GIT_TOKEN }}@gitea.radiantwavetech.com/RadiantWaveTech/kioskconfig.git
git add flake.lock
git commit -m "chore: update radiantwave-dev to latest" || echo "Nothing to commit"
git push
+43
View File
@@ -0,0 +1,43 @@
on:
workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs:
build-android:
runs-on: build-server
steps:
- name: Checkout
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
- name: Build android kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.android-iso.config.system.build.isoImage
- name: Rename android kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-android-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "ANDROID_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
# - name: Move old android images to archive
# run: |
# ssh nclack@157.245.124.103 'mv /mnt/infrastructure_data/files/images/radiantwave-android-iso* /mnt/infrastructure_data/files/images/archives/'
- name: Copy android kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${ANDROID_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup android kiosk ISO
run: rm -f "/home/user/radiantwave/${ANDROID_ISO_FILENAME}"
@@ -0,0 +1,43 @@
on:
workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs:
build-commercial:
runs-on: build-server
steps:
- name: Checkout
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
- name: Build commercial kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.commercial-iso.config.system.build.isoImage
- name: Rename commercial kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-commercial-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "COMMERCIAL_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
# - name: Move old commercial images to archive
# run: |
# ssh nclack@157.245.124.103 'mv /mnt/infrastructure_data/files/images/radiantwave-commercial-iso* /mnt/infrastructure_data/files/images/archives/'
- name: Copy commercial kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup commercial kiosk ISO
run: rm -f "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}"
+43
View File
@@ -0,0 +1,43 @@
on:
workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs:
build-kiosk:
runs-on: build-server
steps:
- name: Checkout
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
- name: Build kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.kiosk-iso.config.system.build.isoImage
- name: Rename kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-home-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
# - name: Move old kiosk images to archive
# run: |
# ssh nclack@157.245.124.103 'mv /mnt/infrastructure_data/files/images/radiantwave-home* /mnt/infrastructure_data/files/images/archives/'
- name: Copy kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup kiosk ISO
run: rm -f "/home/user/radiantwave/${KIOSK_ISO_FILENAME}"
+42
View File
@@ -0,0 +1,42 @@
on:
workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave https://nixos-raspberrypi.cachix.org
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA= nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI=
jobs:
build-rpi:
runs-on: build-server
steps:
- name: Checkout
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
- name: Build Raspberry Pi image
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.radiantwavekiosk-rpi.config.system.build.sdImage
- name: Rename Raspberry Pi image
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-rpi-${ISO_DATE}.img.zst"
cp -L result/sd-image/*.img.zst "/home/user/radiantwave/${FILENAME}"
echo "RPI_IMAGE_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Move old Raspberry Pi images to archive
run: tools/archive-images.sh nclack@157.245.124.103 /mnt/infrastructure_data/files/images /mnt/infrastructure_data/files/images/archives 'radiantwave-rpi*'
- name: Copy Raspberry Pi image to fileserver
run: |
scp "/home/user/radiantwave/${RPI_IMAGE_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup Raspberry Pi image
run: rm -f "/home/user/radiantwave/${RPI_IMAGE_FILENAME}"
-137
View File
@@ -1,137 +0,0 @@
on:
push:
branches:
- main
workflow_dispatch:
jobs:
update-and-build:
runs-on: build-server
steps:
- 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
nix flake update radiantwave
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
# --- Kiosk ISO ---
- name: Build kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.kiosk-iso.config.system.build.isoImage
- name: Rename kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Copy kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup kiosk ISO
run: rm -f "/home/user/radiantwave/${KIOSK_ISO_FILENAME}"
# --- Android Kiosk ISO ---
- name: Build android kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.android-iso.config.system.build.isoImage
- name: Rename android kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-android-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "ANDROID_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Copy android kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${ANDROID_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup android kiosk ISO
run: rm -f "/home/user/radiantwave/${ANDROID_ISO_FILENAME}"
# --- Commercial Kiosk ISO ---
- name: Build commercial kiosk ISO
run: |
export NIXPKGS_ALLOW_UNFREE=1
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix build -L --impure .#nixosConfigurations.commercial-iso.config.system.build.isoImage
- name: Rename commercial kiosk ISO
run: |
ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="radiantwave-commercial-iso-${ISO_DATE}.iso"
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "COMMERCIAL_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Copy commercial kiosk ISO to fileserver
run: |
scp "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}" \
radiantwave-infra:/mnt/infrastructure_data/files/images/
- name: Cleanup commercial kiosk ISO
run: rm -f "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}"
# --- Raspberry Pi image (disabled for speed, for now) ---
# - name: Build Raspberry Pi image
# run: |
# export NIXPKGS_ALLOW_UNFREE=1
# . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
# nix build -L --impure .#nixosConfigurations.radiantwavekiosk-rpi.config.system.build.sdImage
#
# - name: Rename Raspberry Pi image
# run: |
# ISO_DATE=$(date +%Y-%m-%d_%H-%M-%S)
# FILENAME="radiantwave-rpi-${ISO_DATE}.img.zst"
# cp -L result/sd-image/*.img.zst "/home/user/radiantwave/${FILENAME}"
# echo "RPI_IMAGE_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
#
# - name: Copy Raspberry Pi image to fileserver
# run: |
# scp "/home/user/radiantwave/${RPI_IMAGE_FILENAME}" \
# radiantwave-infra:/mnt/infrastructure_data/files/images/
#
# - name: Cleanup Raspberry Pi image
# run: rm -f "/home/user/radiantwave/${RPI_IMAGE_FILENAME}"
- name: Commit updated flake.lock
run: |
git config user.email "ci@radiantwavetech.com"
git config user.name "RadiantWave CI"
git remote set-url origin https://oauth2:${{ secrets.GIT_TOKEN }}@gitea.radiantwavetech.com/RadiantWaveTech/kioskconfig.git
git add flake.lock
git commit -m "chore: update radiantwave-dev to latest" || echo "Nothing to commit"
git push
# - name: Notify
# if: always()
# uses: https://github.com/dawidd6/action-send-mail@v3
# with:
# server_address: smtp.gmail.com
# server_port: 587
# username: ${{ secrets.MAIL_USERNAME }}
# password: ${{ secrets.MAIL_PASSWORD }}
# subject: "${{ job.status == 'success' && '✅' || '❌' }} KioskConfig main build ${{ job.status }}"
# to: nclack@radiantwavetech.com
# from: ci@radiantwavetech.com
# body: "KioskConfig main build ${{ job.status }} — radiantwave updated and artifacts copied."
+68 -27
View File
@@ -2,10 +2,19 @@
## What this repo is ## What this repo is
NixOS flake that defines kiosk systems running the RadiantWave app. Not application code — this is the OS image and deployment configuration. The actual app lives in the `radiantwave` flake input (from gitea.radiantwavetech.com). NixOS flake that defines kiosk systems running the RadiantWave app. Not application code — this is the OS image and deployment configuration. The actual app lives in the `radiantwave` flake inputs (from gitea.radiantwavetech.com).
Hosted on Gitea: `https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig` Hosted on Gitea: `https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig`
## Prod/dev split
Single branch (`main`) for this repo. The production vs. dev split is at the **flake input + upgrade ref** level:
- Production variants consume the `radiantwave` input (`?ref=main`) and auto-upgrade from `KioskConfig.git#<config>` on `main`.
- `-dev` variants consume the `radiantwave-dev` input (`?ref=dev`) and auto-upgrade from `KioskConfig.git?ref=dev#<config>-dev`.
Both gitea repos are public: all git access is plain HTTPS (`git+https://...`), no SSH keys or access tokens on the kiosks. Don't reintroduce `git+ssh` URLs in flake/upgrade refs.
## Key commands ## Key commands
```bash ```bash
@@ -18,7 +27,7 @@ nix build .#nixosConfigurations.<name>.config.system.build.isoImage
# Deploy to a remote kiosk over SSH # Deploy to a remote kiosk over SSH
nixos-rebuild switch --flake .#<name> --target-host root@<host> nixos-rebuild switch --flake .#<name> --target-host root@<host>
# Push build result to Attic cache # Push build result to Attic cache (not currently wired into any config)
attic push kiosk ./result attic push kiosk ./result
# Evaluate available config names # Evaluate available config names
@@ -27,47 +36,79 @@ nix eval .#nixosConfigurations --apply builtins.attrNames
## Config variants ## Config variants
| Name | Target hardware | Disk device | Notes | | Name | Target hardware | Disk device | App input |
|---|---|---|---| |---|---|---|---|
| `radiantwavekiosk` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | Production, uses `radiantwave` main | | `radiantwavekiosk` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | Dev, uses `radiantwave-dev` ref | | `radiantwavekiosk-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | Production | | `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | `radiantwave` (main) |
| `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | Dev | | `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-android` | Intel NUC 14 | `/dev/nvme0n1` | + rotated display (portrait) | | `radiantwavekiosk-android` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-rpi` | Raspberry Pi 5 | — | Uses `nixos-raspberrypi` | | `radiantwavekiosk-android-dev` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-rpi-dev` | Raspberry Pi 5 | — | Dev, uses `radiantwave-dev` | | `radiantwavekiosk-rpi` | Raspberry Pi 5 (SD image) | — | `radiantwave` (main) |
| `radiantwavekiosk-rpi-dev` | Raspberry Pi 5 (SD image) | — | `radiantwave-dev` (dev) |
ISOs: `usb-iso`, `commercial-usb-iso`, `android-iso`, `dev-iso` — each bakes in the corresponding system closure for zero-touch install. Every variant sets its own `networking.hostName` (same as the config name) and `system.configurationRevision`, so `tools/find_systems.zsh` can identify fleet members.
## Branching model ### USB images (zero-touch installers)
Single branch (`main`). Production vs. dev split is at the **flake input** level (`radiantwave` vs `radiantwave-dev`), not at the branch level. Each ISO installs exactly one closure using that closure's disk layout (`mkIso` in `flake.nix` derives both from the target config name):
## CI (Forgejo) | ISO | Installs | Disk layout |
|---|---|---|
| `kiosk-iso` | `radiantwavekiosk` | NVMe (`disk-config.nix`) |
| `dev-iso` | `radiantwavekiosk-dev` | NVMe |
| `commercial-iso` | `radiantwavekiosk-commercial` | SATA (`commercial-disk-config.nix`) |
| `commercial-dev-iso` | `radiantwavekiosk-commercial-dev` | SATA |
| `android-iso` | `radiantwavekiosk-android` | NVMe |
| `android-dev-iso` | `radiantwavekiosk-android-dev` | NVMe |
`.forgejo/workflows/build-dev.yml` — triggered by `repository_dispatch` (`radiantwave-dev-built`) from the RadiantWave repo. Updates `radiantwave-dev` input, builds dev closure + ISO, commits updated `flake.lock`. Runs on `neils-server-runner`. The installer lives once in `zero-touch-installer.nix` and is parameterized by `targetConfig`. Adding a new variant = add the `nixosConfigurations.*` entry, a matching `packages.x86_64-linux.*` line, and an ISO if needed.
Raspberry Pi systems are built as SD images, not ISOs:
`nix build .#nixosConfigurations.radiantwavekiosk-rpi.config.system.build.sdImage` (see `build-rpi.sh`).
## Hardware facter reports
`facter.json` is a hardware report captured on a **NUC 14**. It is currently applied to **every x86 variant**, including the commercial SATA hardware — acceptable until per-model reports exist.
To generate a report for a hardware model:
1. Boot that hardware from any NixOS live image (the kiosk installers work).
2. With real peripherals attached (display(s), audio), run:
```bash
sudo nix shell nixpkgs#nixos-facter -c nixos-facter -o facter-<model>.json
```
3. Commit `facter-<model>.json` to the repo root.
4. Wire it up at the marked spot in `flake.nix` (`facter.reportPath` inside `mkKioskSystem`) by selecting the right file per variant.
Regenerate when major hardware changes, not on a schedule — reports are snapshots. RPi configs don't use the facter module, so no report is needed there.
## CI (Gitea)
`.gitea/workflows/build-*.yml` — all triggered by `workflow_dispatch` on the `build-server` runner. They only **build and publish** what is committed. `flake.lock` is updated manually: commit an updated lock (e.g. after `nix flake update radiantwave-dev`) and dispatching the workflow is the release trigger.
## Important gotchas ## Important gotchas
- **Disk device differs by variant**: `disk-config.nix` uses `/dev/nvme0n1`, `commercial-disk-config.nix` uses `/dev/sda`. Don't mix them up. - **Disk device differs by variant**: `disk-config.nix` uses `/dev/nvme0n1`, `commercial-disk-config.nix` uses `/dev/sda`. `mkIso` pairs each ISO with the correct layout automatically — keep new ISOs paired correctly.
- **ISO configs reference specific system closures**: `iso-config.nix` hardcodes `radiantwavekiosk`, `dev-iso.nix` hardcodes `radiantwavekiosk-dev`, `commercial-iso-config.nix` hardcodes `radiantwavekiosk-commercial`. Changing a config name in `flake.nix` requires updating the corresponding ISO config. - **Changing a config name** requires updating that config's `upgradeFlakeRef` in `flake.nix` (it embeds the name).
- **Attic cache token**: ISO configs embed a JWT token for Attic in `/etc/nix/netrc`. If builds fail with auth errors, the token may have expired (expiry in the JWT payload). - **`rotated_display.nix` uses `mkForce`** on `loginShellInit` — it replaces the entire kiosk startup script from `configuration.nix`; don't edit both.
- **`rotated_display.nix` uses `mkForce`** on `loginShellInit` — it replaces the entire kiosk startup script from `configuration.nix`, don't edit both. - **Auto-update**: `system.autoUpgrade` runs every 10 min (`*:00/10`) with `--refresh`, operation `switch`, no auto-reboot. A `radiantwave-backup` rsync runs before each attempt. The health-check/rollback service is written but commented out in `configuration.nix`.
- **SOPS**: `.sops.yaml` configures age-based encryption for `secrets.yaml`. You'll need the private key matching `age1t2wpzv...` to decrypt. - **No binary cache**: kiosks fetch from cache.nixos.org only and compile RadiantWave itself from source during upgrades. Attic integration was planned (see `PLAN-update-system.md`) but never wired; the old netrc/JWT setup has been removed.
- **Flake inputs**: `radiantwave` tracks main, `radiantwave-dev` tracks `?ref=dev`. Updating them independently is intentional. - **Secrets**: none in-tree anymore (gitea repos are public). If either repo goes private, re-add auth via `nix.settings.access-tokens` in `configuration.nix`.
- **Flake inputs**: `radiantwave` tracks main, `radiantwave-dev` tracks `?ref=dev`; prod and `-dev` configs consume them respectively. Updating them independently is intentional.
- **SSH keys on machines are inbound-only** (`authorizedKeys` for admin access); outbound git is HTTPS. The root key in `zero-touch-installer.nix` must stay in sync with `myKey` in `configuration.nix`.
## File map ## File map
- `flake.nix` — all system definitions, entry point - `flake.nix` — entry point: inputs, builders (`mkKioskSystem`, `mkRpiKioskSystem`, `mkIso`), all system definitions, facter report wiring
- `configuration.nix` — shared NixOS config (packages, services, kiosk user, auto-upgrade, health check, VM variant) - `configuration.nix` — shared NixOS config (packages, services, kiosk user, auto-upgrade, health check, VM variant)
- `zero-touch-installer.nix` — parameterized USB installer module used by all six ISOs
- `disk-config.nix` — NVMe disk layout (NUC) - `disk-config.nix` — NVMe disk layout (NUC)
- `commercial-disk-config.nix` — SATA disk layout (commercial HW) - `commercial-disk-config.nix` — SATA disk layout (commercial HW)
- `iso-config.nix` — production ISO + zero-touch installer
- `dev-iso.nix` — dev ISO + zero-touch installer
- `commercial-iso-config.nix` — commercial ISO + zero-touch installer
- `rotated_display.nix` — portrait display override for Android variant - `rotated_display.nix` — portrait display override for Android variant
- `facter.json` — hardware facter report (NUC 14) - `facter.json` — hardware facter report (NUC 14)
- `14rvk.json`, `pn54.json` — additional hardware facter reports
- `assets/` — logo and splash image - `assets/` — logo and splash image
- `plymouth-theme/` — boot splash theme - `plymouth-theme/` — boot splash theme
- `commands.md` — quick-reference for build/deploy commands - `tools/find_systems.zsh` — subnet sweep for fleet inventory over SSH
- `build-rpi.sh` — containerized RPi SD-image build helper
- `PLAN-*.md`, `report.md`, `timeline.csv`, `kiosk-url-changes.csv` — planning/history notes, not configuration
+159
View File
@@ -0,0 +1,159 @@
# DRM/KMS Direct Mode — Deferred to Post-Launch
**Status:** Deferred (too much risk before launch)
**Created:** 2026-08-17
---
## Goal
Remove Cage (Wayland compositor) from -dev kiosk variants and run RadiantWave
directly on DRM/KMS via SDL3's built-in `SDL_VIDEODRIVER=drm` backend. This
simplifies the stack, removes compositor overhead, and is better suited for
embedded/hardware kiosks.
**Decision:** Deferring until after the current launch. Cage works, and the
transition touches every variant's boot pipeline.
---
## What Cage Currently Provides
| Feature | How Cage Does It | DRM/KMS Replacement |
|---------|------------------|---------------------|
| Display mode setting | Opens `/dev/dri/card*` via libseat, selects connector/CRTC/mode | SDL3 DRM backend opens DRM devices directly |
| Fullscreen surface | Creates Wayland surface, manages lifecycle | SDL3 creates DRM framebuffer surface |
| Page flipping / VSync | Handles `drmHandlePageFlip()` | SDL3 DRM backend handles page flip |
| Input devices | Opens `/dev/input/*` via libseat, generates Wayland events | SDL3 DRM backend reads evdev directly |
| Keyboard mapping | XKB keymap loading, key repeat | SDL3 handles keymap translation |
| Seat management | Connects to seatd via libseat | Not needed — group permissions (`video`, `input`) suffice |
---
## What Stays Safe Without Cage
| Concern | Why It's Safe |
|---------|---------------|
| **Audio** | PipeWire/ALSA works independently of the compositor. App uses SDL3_mixer -> ALSA. Audio init service still runs before launch. |
| **WiFi** | NetworkManager uses system bus (`sd_bus_open_system()` in `network_manager.cpp`). No session bus needed. `networkmanager` group handles D-Bus access. |
| **Keyboard/input** | SDL3's DRM backend reads `/dev/input/*` evdev directly. `input` group grants access. |
| **DRM/display** | SDL3's DRM backend opens `/dev/dri/card*` directly. `video` group grants access. |
| **Plymouth** | `sudo -n plymouth quit --wait` still works — Plymouth runs as root on DRM/KMS. |
| **Auto-login** | getty autologin still works on tty1. |
| **Health check** | `pgrep -f '.radiantwave-unwrapped'` still works — no wrapper changes. |
| **Backup service** | Runs as kiosk user, rsyncs `~/.local/radiantwave`. No compositor dependency. |
---
## Implementation Plan — 4 Phases
All changes are in **kioskconfig only**. The radiantwave app needs no code
changes — SDL3 handles DRM/KMS internally when `SDL_VIDEODRIVER=drm` is set.
The NixOS system already provides Mesa/EGL/GBM via `hardware.graphics.enable = true`.
Only **-dev** variants are modified. Production configs stay on Cage.
### New module: `kiosk-drm.nix`
A NixOS module that overrides the Wayland/cage setup:
- `environment.systemPackages = mkForce [...]` — same list as `configuration.nix`
but **without `pkgs.cage`**
- `environment.loginShellInit = mkForce ''...` — same script but:
- Sets `SDL_VIDEODRIVER=drm` instead of `wayland`
- Removes `WLR_RENDERER`, `WLR_NO_HARDWARE_CURSORS`, `QT_QPA_PLATFORM`,
`XDG_SESSION_TYPE`, `GODEBUG`
- Launches `exec /run/current-system/sw/bin/radiantwave` directly
(no `dbus-run-session cage --`)
- Keeps: network wait, audio init, Plymouth quit
- `services.seatd.enable = mkForce false` — nothing uses libseat anymore
---
### Phase 1: `radiantwavekiosk-dev` (Intel NUC)
**Files:**
- Create `kiosk-drm.nix`
- Modify `flake.nix`: add `./kiosk-drm.nix` to `extraModules` for
`radiantwavekiosk-dev`
- `dev-iso.nix` already targets `radiantwavekiosk-dev` — no change needed
**Verify:** `nix build .#nixosConfigurations.radiantwavekiosk-dev.config.system.build.toplevel`
---
### Phase 2: `radiantwavekiosk-commercial-dev` (commercial HW)
**Files:**
- Modify `flake.nix`: add `./kiosk-drm.nix` to `extraModules` for
`radiantwavekiosk-commercial-dev`
- Create `commercial-dev-iso.nix` (same pattern as `dev-iso.nix`, targeting
`radiantwavekiosk-commercial-dev`)
- Add `commercial-dev-iso` config to `flake.nix`
**Verify:** `nix build .#nixosConfigurations.radiantwavekiosk-commercial-dev.config.system.build.toplevel`
---
### Phase 3: `radiantwavekiosk-android-dev` (rotated display)
**Files:**
- Create `radiantwavekiosk-android-dev` in `flake.nix` (currently only
production `radiantwavekiosk-android` exists)
- Create `android-kiosk-drm.nix` — DRM/KMS mode + display rotation
**Challenge:** `rotated_display.nix` uses `wlr-randr` (Wayland tool) for
90-degree rotation. Without Cage/Wayland, this won't work. Alternatives:
- Option A: Use `modetest` from `libdrm` to set DRM rotation property
- Option B: Handle rotation in the app (query display orientation, render rotated)
- Option C: Kernel DRM rotation via modprobe params or udev rule
This is the hardest phase — needs investigation.
**Verify:** `nix build .#nixosConfigurations.radiantwavekiosk-android-dev.config.system.build.toplevel`
---
### Phase 4: `radiantwavekiosk-rpi-dev` (RPi 5)
**Files:**
- Modify `flake.nix`: add `./kiosk-drm.nix` to `extraModules` for
`radiantwavekiosk-rpi-dev`
- Modify `build-rpi.sh`: update to build `radiantwavekiosk-rpi-dev` instead of
`radiantwavekiosk-rpi`
RPi 5 uses VC4/V3D GPU driver — `hardware.graphics.enable = true` +
`nixos-raspberrypi.nixosModules.raspberry-pi-5.display-vc4` already handles this.
**Verify:** `./build-rpi.sh` (builds SD card image)
---
## Risks and Unknowns
1. **SDL3 DRM backend maturity** — Less commonly used than the Wayland backend.
Needs testing on NUC (Intel i915) and RPi 5 (VC4/V3D) hardware.
2. **Android rotation** — `wlr-randr` won't work without Wayland. Needs an
alternative rotation strategy.
3. **Input device permissions** — SDL3's DRM backend reads `/dev/input/*`
directly. Need to verify `input` group is sufficient and udev rules don't
block access.
4. **Multi-GPU/multi-output** — DRM/KMS needs to select the right connector.
SDL3 handles this, but edge cases exist (e.g., multiple monitors).
5. **Plymouth -> app handoff** — Plymouth runs on DRM/KMS too. The handoff
should work, but timing might differ without a Wayland compositor in between.
---
## radiantwave Repo — No Changes Needed
The app doesn't directly use DRM/KMS APIs. SDL3 handles the DRM backend
internally when `SDL_VIDEODRIVER=drm` is set. The Nix package doesn't need
changes — SDL3 dynamically loads DRM libraries at runtime.
The only change is the environment variable in the kiosk startup script
(`SDL_VIDEODRIVER=drm` vs `wayland`), which lives in kioskconfig.
+632
View File
@@ -0,0 +1,632 @@
# RadiantWave Kiosk Update System Plan
**Goal**: Bulletproof automatic update system for RadiantWave kiosk
**Deadline**: Production in 2 days
**Architecture**: Manifest-based app updates + Flake lock system updates + systemd service supervision
**Timezone**: UTC (all kiosks run in UTC)
**Variants**: All variants (production + dev) auto-update
**Notifications**: Logs only (no email/Slack)
---
## Executive Summary
This plan implements a three-part update system:
1. **Kiosk App Supervision**: Convert the kiosk app from exec'd login shell to a supervised systemd user service with automatic restart
2. **RadiantWave App Updates**: Hourly manifest checks trigger updates via Attic binary cache
3. **System Updates**: NixOS updates on boot and nightly at 8PM UTC
All updates show Plymouth splash during transition and auto-rollback on failure.
---
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────────┐
│ BOOT SEQUENCE │
├─────────────────────────────────────────────────────────────────┤
│ 1. Plymouth splash (held indefinitely) │
│ 2. getty autologin as kiosk on tty1 │
│ 3. loginShellInit runs: │
│ a. Set environment variables │
│ b. Wait for network (up to 10s) │
│ c. Start radiantwave-audio-init user service │
│ d. Start kiosk-app.service (systemd user service) │
│ e. Quit Plymouth │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ KIOSK APP SERVICE │
├─────────────────────────────────────────────────────────────────┤
│ kiosk-app.service (systemd user service) │
│ ├─ Runs: dbus-run-session cage -- radiantwave -d -s │
│ ├─ Restart=always, RestartSec=5 │
│ ├─ Logs to /tmp/kiosk.log │
│ └─ On failure: auto-restart (3 attempts) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ UPDATE CHECKERS │
├─────────────────────────────────────────────────────────────────┤
│ radiantwave-update-checker.service (hourly) │
│ ├─ Checks: https://attic.radiantwavetech.com/manifest.json │
│ ├─ If new version: trigger radiantwave-upgrade.service │
│ └─ Runs as: root (system service) │
│ │
│ system-update-checker.service (on boot + 8PM UTC) │
│ ├─ Triggers: nixos-upgrade.service │
│ └─ Runs as: root (system service) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ UPGRADE PROCESS │
├─────────────────────────────────────────────────────────────────┤
│ radiantwave-upgrade.service (triggered by update checker) │
│ ├─ 1. Show Plymouth splash │
│ ├─ 2. Stop kiosk-app.service │
│ ├─ 3. Update flake.lock (git pull) │
│ ├─ 4. Run nixos-rebuild switch │
│ ├─ 5. Restart kiosk-app.service │
│ ├─ 6. Quit Plymouth │
│ └─ 7. Health check (if fails: auto-rollback) │
└─────────────────────────────────────────────────────────────────┘
```
---
## Component Details
### 1. Kiosk App Systemd Service
**File**: `kiosk-app.nix` (new module)
**Purpose**: Supervise the cage/radiantwave process with automatic restart
**Key Configuration**:
```nix
{ config, lib, pkgs, ... }:
{
# System service (runs as root, starts user service)
systemd.services.kiosk-app = {
description = "RadiantWave Kiosk Application";
after = [ "graphical.target" ];
wantedBy = [ "graphical.target" ];
# Start the user service
serviceConfig = {
ExecStart = "${pkgs.systemd}/bin/systemctl --user start kiosk-app-session.service";
ExecStop = "${pkgs.systemd}/bin/systemctl --user stop kiosk-app-session.service";
Type = "oneshot";
RemainAfterExit = true;
};
};
# User service (actual cage/radiantwave process)
systemd.user.services.kiosk-app-session = {
description = "RadiantWave Kiosk Session";
after = [ "graphical-session.target" ];
serviceConfig = {
ExecStart = "${pkgs.dbus}/bin/dbus-run-session ${pkgs.cage}/bin/cage -- ${config.radiantApp}/bin/radiantwave -d -s";
Restart = "always";
RestartSec = 5;
# Logging
StandardOutput = "journal";
StandardError = "journal";
# Environment
Environment = [
"GODEBUG=cgocheck=0"
"WAYLAND_DISPLAY=wayland-0"
"XDG_RUNTIME_DIR=/run/user/1000"
];
};
# Restart policy
unitConfig = {
StartLimitIntervalSec = 60;
StartLimitBurst = 3;
};
};
}
```
**Changes to `configuration.nix`**:
- Remove the `exec` line from `environment.loginShellInit`
- Add `systemctl --user start kiosk-app-session.service` instead
- Keep Plymouth quit after service start
**Updated `loginShellInit`**:
```nix
environment.loginShellInit = ''
# ... existing env setup and network wait ...
# Start audio init
systemctl --user start radiantwave-audio-init.service
# Start kiosk app service
systemctl --user start kiosk-app-session.service
# Wait a moment for cage to start
sleep 2
# Quit Plymouth
sudo -n plymouth quit --wait
# Keep shell alive (don't exec)
# The systemd service manages the kiosk app
'';
```
---
### 2. Attic Cache Configuration
**File**: `attic-cache.nix` (new module)
**Purpose**: Configure Nix to use Attic as a binary cache
**Key Configuration**:
```nix
{ config, lib, pkgs, ... }:
{
# Add Attic to trusted caches
nix.settings = {
trusted-caches = [
"https://attic.radiantwavetech.com/radiantwave"
];
# Extra substituters (for pulling)
extra-substituters = [
"https://attic.radiantwavetech.com/radiantwave"
];
# Public keys (Attic uses Ed25519)
trusted-public-keys = [
"radiantwave:PLACEHOLDER_PUBLIC_KEY"
];
};
# Ensure nix can use the cache without authentication
# (Attic is configured as public/open)
}
```
**Note**: Replace `PLACEHOLDER_PUBLIC_KEY` with the actual Attic public key after server setup.
---
### 3. RadiantWave Update Checker
**File**: `radiantwave-update-checker.nix` (new module)
**Purpose**: Check Attic manifest hourly for new RadiantWave versions
**Key Configuration**:
```nix
{ config, lib, pkgs, ... }:
{
systemd.services.radiantwave-update-checker = {
description = "Check for RadiantWave updates";
# Run hourly
startAt = "hourly";
serviceConfig = {
Type = "oneshot";
# Check manifest and trigger upgrade if needed
ExecStart = pkgs.writeScript "check-radiantwave-update" ''
#!/bin/bash
set -euo pipefail
MANIFEST_URL="https://attic.radiantwavetech.com/manifest.json"
CURRENT_VERSION_FILE="/etc/radiantwave-version"
# Fetch manifest
MANIFEST=$(curl -sf "$MANIFEST_URL" || exit 0)
# Extract version
NEW_VERSION=$(echo "$MANIFEST" | ${pkgs.jq}/bin/jq -r '.version')
# Get current version
if [ -f "$CURRENT_VERSION_FILE" ]; then
CURRENT_VERSION=$(cat "$CURRENT_VERSION_FILE")
else
CURRENT_VERSION="0.0.0"
fi
# Compare versions
if [ "$NEW_VERSION" != "$CURRENT_VERSION" ]; then
echo "Update available: $CURRENT_VERSION -> $NEW_VERSION"
# Trigger upgrade
systemctl start radiantwave-upgrade.service
else
echo "Already up to date: $CURRENT_VERSION"
fi
'';
};
};
# Upgrade service (triggered by checker)
systemd.services.radiantwave-upgrade = {
description = "Upgrade RadiantWave";
serviceConfig = {
Type = "oneshot";
# Show Plymouth during upgrade
ExecStartPre = "${pkgs.plymouth}/bin/plymouth show-splash || true";
# Stop kiosk
ExecStart = "${pkgs.systemd}/bin/systemctl stop kiosk-app.service";
# Update flake.lock and rebuild
ExecStart = pkgs.writeScript "upgrade-radiantwave" ''
#!/bin/bash
set -euo pipefail
# Update flake.lock
cd ${config.system.build.toplevel} # or git repo path
git pull origin main
# Update radiantwave input
nix flake update radiantwave
# Rebuild and switch
nixos-rebuild switch --flake .#${config.networking.hostName}
# Update version file
NEW_VERSION=$(curl -sf https://attic.radiantwavetech.com/manifest.json | ${pkgs.jq}/bin/jq -r '.version')
echo "$NEW_VERSION" > /etc/radiantwave-version
'';
# Restart kiosk
ExecStart = "${pkgs.systemd}/bin/systemctl start kiosk-app.service";
# Quit Plymouth
ExecStartPost = "${pkgs.plymouth}/bin/plymouth quit --wait || true";
# Rollback on failure
FailureAction = "none"; # Handled by healthcheck
# Timeout
TimeoutStartSec = 300; # 5 minutes for rebuild
};
# Run after update checker
after = [ "radiantwave-update-checker.service" ];
};
}
```
---
### 4. System Update Configuration
**File**: `system-updates.nix` (modify existing)
**Purpose**: Configure NixOS system updates on boot and nightly at 8PM UTC
**Changes to `configuration.nix`**:
```nix
# Replace existing system.autoUpgrade
system.autoUpgrade = {
enable = true;
flake = upgradeFlakeRef; # e.g., "git+https://gitea...KioskConfig.git#radiantwavekiosk"
# Run on boot and nightly at 8PM UTC (kiosks are in UTC)
dates = "20:00"; # 8PM UTC daily
randomizedDelaySec = "10min"; # Avoid thundering herd
flags = [ "--refresh" "-L" ];
operation = "switch";
};
```
**Note**: The existing health check service (`radiantwave-healthcheck`) already runs after `nixos-upgrade.service` and handles rollback. Keep this as-is.
---
### 5. Update Rollback Mechanism
**File**: `update-rollback.nix` (modify existing health check)
**Purpose**: Auto-rollback on failed updates
**Existing mechanism** (already in `configuration.nix`):
```nix
systemd.services.radiantwave-healthcheck = {
description = "Health check after upgrade";
after = [ "nixos-upgrade.service" ];
wantedBy = [ "nixos-upgrade.service" ];
serviceConfig = {
Type = "oneshot";
ExecStartPre = "sleep 90"; # Wait for cage to start
ExecStart = pkgs.writeScript "healthcheck" ''
#!/bin/bash
if ! pgrep -f ".radiantwave-unwrapped"; then
echo "Health check failed, rolling back..."
nixos-rebuild switch --rollback
fi
'';
};
};
```
**Enhancement**: Add version file tracking and logging:
```nix
ExecStart = pkgs.writeScript "healthcheck" ''
#!/bin/bash
set -euo pipefail
LOG_FILE="/var/log/radiantwave-healthcheck.log"
echo "$(date): Starting health check" >> "$LOG_FILE"
# Wait for cage to start
sleep 10
# Check if radiantwave is running
if pgrep -f ".radiantwave-unwrapped" > /dev/null; then
echo "$(date): Health check passed" >> "$LOG_FILE"
# Update version file on success
if [ -f "/tmp/pending-version" ]; then
cp /tmp/pending-version /etc/radiantwave-version
fi
else
echo "$(date): Health check FAILED, rolling back..." >> "$LOG_FILE"
nixos-rebuild switch --rollback 2>> "$LOG_FILE"
echo "$(date): Rollback complete" >> "$LOG_FILE"
fi
'';
```
---
### 6. CI Changes to Push to Attic
**File**: `.gitea/workflows/build-prod.yml` (modify)
**Purpose**: Push built closures to Attic cache
**Add to workflow**:
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
# ... existing build steps ...
# Push to Attic
- name: Push to Attic cache
run: |
# Install attic-client
nix profile install github:zedant/attic#attic-client
# Login to Attic (token from secrets)
attic login production https://attic.radiantwavetech.com production "${{ secrets.ATTIC_TOKEN }}"
# Push closures
attic push production ./result-kiosk
attic push production ./result-android
attic push production ./result-commercial
# Update manifest
- name: Update manifest
run: |
VERSION=$(date +%Y.%m.%d-%H%M)
STORE_PATH=$(readlink -f ./result-kiosk)
# Create manifest
cat > manifest.json << EOF
{
"version": "$VERSION",
"storePath": "$STORE_PATH",
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"commit": "${{ github.sha }}"
}
EOF
# Upload manifest to Attic or fileserver
# (Attic doesn't support arbitrary file uploads, so use a fileserver or git)
```
**Note**: Attic doesn't support arbitrary file uploads. Options for manifest:
1. Host on a simple fileserver (nginx, S3, etc.)
2. Commit to a git repo and serve via GitHub/Gitea Pages
3. Use Attic's labels feature (if available)
---
## Implementation Steps
### Phase 1: Attic Server Setup (User's Responsibility)
- [ ] Set up Attic server at `attic.radiantwavetech.com`
- [ ] Configure public/open access (no authentication)
- [ ] Create cache named `radiantwave`
- [ ] Note the public key for Nix configuration
- [ ] Test pushing a closure: `attic push radiantwave /nix/store/...`
### Phase 2: Manifest Hosting (User's Responsibility)
- [ ] Choose manifest hosting location (fileserver, git, S3)
- [ ] Create initial manifest with current version
- [ ] Ensure manifest is accessible via HTTPS
### Phase 3: Kiosk Configuration Changes
- [ ] Create `kiosk-app.nix` module with systemd service
- [ ] Create `attic-cache.nix` module for Attic configuration
- [ ] Create `radiantwave-update-checker.nix` module
- [ ] Modify `configuration.nix`:
- Remove `exec` from `loginShellInit`
- Add `systemctl --user start kiosk-app-session.service`
- Update `system.autoUpgrade` schedule
- [ ] Modify `rotated_display.nix` to match changes
- [ ] Test locally with `nixos-rebuild build`
### Phase 4: CI Changes
- [ ] Add Attic push step to `build-prod.yml`
- [ ] Add manifest update step
- [ ] Test CI pipeline with manual trigger
### Phase 5: Testing
- [ ] Build ISO with changes
- [ ] Test on VM or physical hardware
- [ ] Verify kiosk starts automatically
- [ ] Test manual update trigger
- [ ] Test automatic update detection
- [ ] Test rollback on failure
- [ ] Test Plymouth splash during updates
---
## Testing Checklist
### Kiosk App Service
- [ ] Kiosk starts automatically on boot
- [ ] Kiosk restarts if crashed (kill -9 radiantwave)
- [ ] Logs appear in `/tmp/kiosk.log` and `journalctl`
- [ ] Audio init completes before kiosk starts
### Update Detection
- [ ] Manifest check runs hourly
- [ ] System update check runs on boot
- [ ] System update check runs at 8PM UTC
- [ ] Checker logs show current vs available version
### Update Process
- [ ] Plymouth splash shows during update
- [ ] Kiosk stops before rebuild
- [ ] Rebuild completes successfully
- [ ] Kiosk restarts after rebuild
- [ ] Plymouth quits after kiosk starts
- [ ] Version file updates on success
### Rollback
- [ ] Health check runs after upgrade
- [ ] Rollback triggers if radiantwave not running
- [ ] Rollback completes successfully
- [ ] Logs show rollback reason
### Network Failure Handling
- [ ] Update checker continues if manifest unreachable
- [ ] Rebuild continues if Attic unreachable (uses local cache)
- [ ] Kiosk restarts even if update fails
---
## File Map (New/Modified)
### New Files
- `kiosk-app.nix` - Systemd service for kiosk app
- `attic-cache.nix` - Attic binary cache configuration
- `radiantwave-update-checker.nix` - Hourly update checker
- `system-updates.nix` - System update schedule (or modify configuration.nix)
### Modified Files
- `configuration.nix` - Remove exec, add service start, update autoUpgrade schedule
- `rotated_display.nix` - Match loginShellInit changes
- `.gitea/workflows/build-prod.yml` - Add Attic push step
- `.gitea/workflows/build-dev.yml` - Add Attic push step (optional)
---
## Rollback Strategy
If the update system itself fails:
1. **Manual rollback**: SSH into kiosk, run `nixos-rebuild switch --rollback`
2. **Boot previous generation**: Select previous generation in systemd-boot (if timeout enabled)
3. **Reinstall from ISO**: Last resort, use zero-touch installer ISO
---
## Monitoring and Debugging
### Logs to Check
- `/tmp/kiosk.log` - Kiosk app output
- `journalctl -u kiosk-app.service` - Systemd service logs
- `journalctl -u radiantwave-update-checker.service` - Update checker logs
- `journalctl -u radiantwave-upgrade.service` - Upgrade process logs
- `/var/log/radiantwave-healthcheck.log` - Health check results
### Manual Commands
```bash
# Check current version
cat /etc/radiantwave-version
# Check manifest manually
curl -sf https://attic.radiantwavetech.com/manifest.json | jq
# Trigger manual update
systemctl start radiantwave-upgrade.service
# Check kiosk service status
systemctl --user status kiosk-app-session.service
# View kiosk logs
journalctl -u kiosk-app.service -f
# Manual rollback
nixos-rebuild switch --rollback
```
---
## Risk Assessment
| Risk | Impact | Mitigation |
|------|--------|------------|
| Attic server unavailable | Updates fail, kiosk continues running | Update checker continues hourly, kiosk unaffected |
| Manifest corrupted | False update trigger | Version comparison logic, checksums |
| Rebuild fails | Kiosk stays on old version | Automatic rollback via health check |
| Kiosk crashes during update | Plymouth stays on screen | Timeout mechanisms, manual intervention |
| Network partition | No updates possible | Kiosk continues on current version |
---
## Success Criteria
- [ ] Kiosk starts automatically on boot (no manual intervention)
- [ ] Kiosk restarts automatically if crashed
- [ ] RadiantWave updates check every hour
- [ ] System updates check on boot and 8PM UTC
- [ ] Updates show Plymouth splash during transition
- [ ] Failed updates auto-rollback within 2 minutes
- [ ] All operations logged for debugging
- [ ] Zero manual intervention required for routine updates
---
## Timeline
**Day 1 (Today)**:
- [ ] Set up Attic server
- [ ] Create manifest hosting
- [ ] Implement kiosk-app.nix
- [ ] Implement attic-cache.nix
- [ ] Test kiosk service locally
**Day 2 (Tomorrow)**:
- [ ] Implement update checker modules
- [ ] Update CI workflows
- [ ] Build test ISO
- [ ] Test on hardware
- [ ] Deploy to production
---
## Questions for Clarification
1. ~~Where will the manifest file be hosted?~~ → **Fileserver (nginx/Caddy)**
2. ~~What timezone is the kiosk in?~~ → **UTC (all kiosks)**
3. ~~Should dev variants also auto-update?~~ → **Yes, all variants**
4. Do you want a manual "check for updates" button in the kiosk UI?
5. ~~Should we notify admins of failed updates?~~ → **Logs only**
-128
View File
@@ -1,128 +0,0 @@
{
pkgs,
inputs,
self,
...
}:
let
# TODO: Parameterize this to combine with iso-config.nix
# Currently hardcoded to radiantwavekiosk-commercial; should accept target config as param
targetSystem =
self.nixosConfigurations.radiantwavekiosk-commercial.config.system.build.toplevel;
diskoScript =
self.nixosConfigurations.radiantwavekiosk-commercial.config.system.build.diskoScript;
in
{
nix.settings = {
experimental-features = [
"nix-command"
"flakes"
];
substituters = [
"https://cache.nixos.org"
];
flake-registry = "";
};
nix.registry.nixpkgs = pkgs.lib.mkForce {
to = {
type = "path";
path = "${inputs.nixpkgs}";
};
};
environment.variables.KIOSK_FLAKE = "${self}";
virtualisation.vmVariant = {
virtualisation.memorySize = 8096;
virtualisation.diskSize = 100000;
virtualisation.cores = 4;
virtualisation.qemu.options = [
# "-nic none"
];
virtualisation.forwardPorts = [
{ from = "host"; host.port = 2222; guest.port = 22; }
];
};
environment.etc."nix/netrc" = {
text = ''
password eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjIwODgzODk2ODEsIm5iZiI6MTc3MjgxMzY4MSwic3ViIjoia2lvc2siLCJodHRwczovL2p3dC5hdHRpYy5ycy92MSI6eyJjYWNoZXMiOnsia2lvc2siOnsiciI6MX19fX0.N6Ktrmmu1LSy2PP8uNF25VHRP1dxPZJ4M0MR1kUpVi0
'';
mode = "0400";
};
nix.extraOptions = ''
netrc-file = /etc/nix/netrc
'';
networking.networkmanager.enable = true;
systemd.services.NetworkManager-wait-online.enable = false;
nix.settings.connect-timeout = 0;
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB4vXx7sOOVAyxdS/N1LEI+L8wYICf+gbzs6Kz7K8Je5 cnclack@pm.me:Thinkpad"
];
systemd.services.zero-touch-install = {
description = "Zero-Touch Kiosk Installation";
wantedBy = [ "multi-user.target" ];
wants = [ ];
after = [ "systemd-udev-settle.service" ];
path = with pkgs; [
nix
git
util-linux
nixos-install-tools
curl
networkmanager
mount
umount
disko
];
environment = {
NIX_PATH = "nixpkgs=${inputs.nixpkgs}";
KIOSK_FLAKE = "${self}";
DISKO_SCRIPT = "${diskoScript}";
};
script = ''
set -euo pipefail
echo "Running disko script..."
echo "Script: $DISKO_SCRIPT"
${diskoScript}
echo "Installing RadiantWave"
echo "Closure Path: ${targetSystem}"
nixos-install \
--system "${targetSystem}" \
--no-root-passwd \
--no-channel-copy
# Redirect to console and show completion message
exec > /dev/tty1 2>&1
echo ""
echo "============================================="
echo " Installation complete!"
echo ""
echo " Please remove the USB drive and reboot."
echo "============================================="
# Wait indefinitely for user action
sleep infinity
''; };
}
+59 -33
View File
@@ -55,14 +55,28 @@ in
} }
]; ];
# Let the kiosk app apply pending updates by restarting its own TTY
# session (re-autologin -> fresh cage + RadiantWave). Scoped to exactly
# one unit and verb; everything else keeps stock (denied) policy.
security.polkit.enable = true;
environment.etc."polkit-1/rules.d/10-kiosk-getty.rules".text = ''
polkit.addRule(function(action, subject) {
if (subject.user !== "kiosk") return null;
if (action.id !== "org.freedesktop.systemd1.manage-units") return null;
var unit = action.lookup("unit");
var verb = action.lookup("verb");
if ((unit === "getty@tty1.service" || unit === "getty@tty1") && verb === "restart") {
return polkit.Result.YES;
}
});
'';
hardware.graphics.enable = true; hardware.graphics.enable = true;
time.timeZone = "America/Chicago"; time.timeZone = "America/Chicago";
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
nix.settings.access-tokens = "gitea.radiantwavetech.com=ff524968d31acc5c4da350d0884a87264d0e8881";
system.autoUpgrade = { system.autoUpgrade = {
enable = true; enable = true;
flake = upgradeFlakeRef; flake = upgradeFlakeRef;
@@ -71,10 +85,6 @@ in
operation = "switch"; operation = "switch";
}; };
system.activationScripts.cleanRadiantFiles = ''
rm -rf /home/kiosk/.local/share/radiantwave/audio
'';
# Virtual machine declaration # Virtual machine declaration
virtualisation.vmVariant = { virtualisation.vmVariant = {
boot.loader.systemd-boot.enable = pkgs.lib.mkForce false; boot.loader.systemd-boot.enable = pkgs.lib.mkForce false;
@@ -98,6 +108,14 @@ in
# NixOS settings. # NixOS settings.
nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.settings.experimental-features = [ "nix-command" "flakes" ];
nix.settings.accept-flake-config = true; nix.settings.accept-flake-config = true;
nix.settings.extra-substituters = [
"https://attic.radiantwavetech.com/radiantwave"
"https://attic.radiantwavetech.com/radiantwave-dev"
];
nix.settings.extra-trusted-public-keys = [
"radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA="
"radiantwave-dev:B8FhLu3MQ9JfeEIHIKNrKxnP+3akzzkqMbTZR4hRfj0="
];
system.stateVersion = "24.05"; system.stateVersion = "24.05";
############################################################ ############################################################
@@ -108,9 +126,8 @@ in
users.users.kiosk = { users.users.kiosk = {
isNormalUser = true; isNormalUser = true;
uid = 1000; uid = 1000;
extraGroups = ["audio" "video" "input" "networkmanager" "wheel"]; extraGroups = ["audio" "video" "input" "networkmanager" "wheel" "seat"];
openssh.authorizedKeys.keys = myKey; openssh.authorizedKeys.keys = myKey;
password = "Fuckp@ssw0rds";
}; };
services.getty.autologinUser = "kiosk"; services.getty.autologinUser = "kiosk";
@@ -173,11 +190,13 @@ in
Type = "oneshot"; Type = "oneshot";
}; };
script = '' 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="" sinks=""
for i in {1..30}; do for i in {1..30}; do
sinks=$(${pkgs.wireplumber}/bin/wpctl list audio sinks 2>/dev/null \ 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 if [ -n "$sinks" ]; then
break break
fi fi
@@ -193,6 +212,10 @@ in
# Fallback in case the sink list came up empty # 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-volume @DEFAULT_AUDIO_SINK@ 1.0 2>/dev/null || true
${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ 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 +230,7 @@ in
# --- Set ownership of Radiantwave files --- # --- Set ownership of Radiantwave files ---
systemd.tmpfiles.rules = [ 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 --- # --- Backup service: runs before nixos-upgrade ---
@@ -220,8 +243,8 @@ in
User = "kiosk"; User = "kiosk";
}; };
script = '' script = ''
BACKUP_DIR="/home/kiosk/.local/share/radiantwave-backup" BACKUP_DIR="/home/kiosk/.local/radiantwave-backup"
SOURCE_DIR="/home/kiosk/.local/share/radiantwave" SOURCE_DIR="/home/kiosk/.local/radiantwave"
mkdir -p "$BACKUP_DIR" mkdir -p "$BACKUP_DIR"
@@ -234,27 +257,30 @@ in
}; };
# --- Health check service: runs after nixos-upgrade --- # --- Health check service: runs after nixos-upgrade ---
systemd.services.radiantwave-healthcheck = { # systemd.services.radiantwave-healthcheck = {
description = "Verify RadiantWave is running after upgrade, rollback if not"; # description = "Verify RadiantWave is running after upgrade, rollback if not";
after = [ "nixos-upgrade.service" ]; # after = [ "nixos-upgrade.service" ];
wantedBy = [ "nixos-upgrade.service" ]; # wantedBy = [ "nixos-upgrade.service" ];
serviceConfig = { # serviceConfig = {
Type = "oneshot"; # Type = "oneshot";
# Give cage time to start radiantwave after the switch # # Give cage time to start radiantwave after the switch
ExecStartPre = "${pkgs.coreutils}/bin/sleep 90"; # ExecStartPre = "${pkgs.coreutils}/bin/sleep 90";
}; # };
script = '' # script = ''
if ${pkgs.procps}/bin/pgrep -x radiantwave > /dev/null; then # # The installed `radiantwave` is a makeWrapper script that execs the real
echo "RadiantWave is running, upgrade successful" # # binary (`.radiantwave-unwrapped`), so the process comm is not exactly
exit 0 # # `radiantwave`; match the exec'd binary's command line instead.
fi # if ${pkgs.procps}/bin/pgrep -f '\.radiantwave-unwrapped' > /dev/null; then
# echo "RadiantWave is running, upgrade successful"
# exit 0
# fi
echo "RadiantWave not found after upgrade, rolling back..." # echo "RadiantWave not found after upgrade, rolling back..."
# Roll back to previous NixOS generation # # Roll back to previous NixOS generation
/run/current-system/sw/bin/nixos-rebuild switch --rollback # /run/current-system/sw/bin/nixos-rebuild switch --rollback
echo "Rollback completed at $(date)" # echo "Rollback completed at $(date)"
''; # '';
}; # };
} }
-133
View File
@@ -1,133 +0,0 @@
{
pkgs,
inputs,
self,
...
}:
let
targetSystem =
self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.toplevel;
diskoScript =
self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.diskoScript;
in
{
############################################################
# System configuration
############################################################
nix.settings = {
experimental-features = [
"nix-command"
"flakes"
];
substituters = [
"https://cache.nixos.org"
];
flake-registry = "";
connect-timeout = 0;
};
nix.registry.nixpkgs = pkgs.lib.mkForce {
to = {
type = "path";
path = "${inputs.nixpkgs}";
};
};
nix.extraOptions = ''
netrc-file = /etc/nix/netrc
'';
environment.variables.KIOSK_FLAKE = "${self}";
environment.etc."nix/netrc" = {
text = ''
password eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjIwODgzODk2ODEsIm5iZiI6MTc3MjgxMzY4MSwic3ViIjoia2lvc2siLCJodHRwczovL2p3dC5hdHRpYy5ycy92MSI6eyJjYWNoZXMiOnsia2lvc2siOnsiciI6MX19fX0.N6Ktrmmu1LSy2PP8uNF25VHRP1dxPZJ4M0MR1kUpVi0
'';
mode = "0400";
};
networking.networkmanager.enable = true;
############################################################
# User configuration
############################################################
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook"
];
############################################################
# Service configuration
############################################################
services.openssh.enable = true;
systemd.services.NetworkManager-wait-online.enable = false;
systemd.services.zero-touch-install = {
description = "Zero-Touch Kiosk Installation";
wantedBy = [ "multi-user.target" ];
# Make sure we own tty1 exclusively - getty@tty1 will otherwise
# try to spawn a login prompt on the same console.
conflicts = [ "getty@tty1.service" ];
after = [ "systemd-udev-settle.service" "getty@tty1.service" ];
path = with pkgs; [
nix
git
util-linux
nixos-install-tools
curl
networkmanager
mount
umount
disko
];
environment = {
NIX_PATH = "nixpkgs=${inputs.nixpkgs}";
KIOSK_FLAKE = "${self}";
DISKO_SCRIPT = "${diskoScript}";
};
serviceConfig = {
StandardInput = "tty";
StandardOutput = "tty";
StandardError = "tty";
TTYPath = "/dev/tty1";
TTYReset = true;
TTYVHangup = true;
TTYVTDisallocate = true;
};
script = ''
set -euo pipefail
echo "Running disko script..."
echo "Script: $DISKO_SCRIPT"
${diskoScript}
echo "Installing RadiantWave"
echo "Closure Path: ${targetSystem}"
nixos-install \
--system "${targetSystem}" \
--no-root-passwd \
--no-channel-copy
echo "============================================"
echo " Installation complete!"
echo " Please shut down and remove the flash drive before restarting"
echo "============================================"
sleep 10000000
'';
};
}
Generated
+13 -13
View File
@@ -184,11 +184,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1776877367, "lastModified": 1785967620,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=", "narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57", "rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -220,11 +220,11 @@
"nixpkgs": "nixpkgs_3" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1785742851, "lastModified": 1787522765,
"narHash": "sha256-WX8hpYpgoEwKRKRkszjCjx+dgZYXE8DSN15+0Sest9g=", "narHash": "sha256-D3KOrGcAH07lvKYgyiwejOQpDW91js7zI6l87WdabLk=",
"ref": "main", "ref": "main",
"rev": "b54dbca2d5e7d6d35b6e596565a0d963a6922c4d", "rev": "63265cc22f3055a782a0114e92c57a36bef723b2",
"revCount": 244, "revCount": 40,
"type": "git", "type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}, },
@@ -240,18 +240,18 @@
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1786139696, "lastModified": 1787522765,
"narHash": "sha256-fLcmVYU2BNpl0P2M9WgoJohL3t0n1EIJQz1TAe/NwrE=", "narHash": "sha256-D3KOrGcAH07lvKYgyiwejOQpDW91js7zI6l87WdabLk=",
"ref": "dev", "ref": "dev",
"rev": "cad834f2321f925e46f36797a11282e9c73fdf47", "rev": "63265cc22f3055a782a0114e92c57a36bef723b2",
"revCount": 6, "revCount": 40,
"type": "git", "type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}, },
"original": { "original": {
"ref": "dev", "ref": "dev",
"type": "git", "type": "git",
"url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave-cpp.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
} }
}, },
"root": { "root": {
+118 -108
View File
@@ -5,7 +5,7 @@
disko.inputs.nixpkgs.follows = "nixpkgs"; disko.inputs.nixpkgs.follows = "nixpkgs";
nixos-facter-modules.url = "github:numtide/nixos-facter-modules"; nixos-facter-modules.url = "github:numtide/nixos-facter-modules";
radiantwave.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=main"; 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";
nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main"; nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
}; };
@@ -35,14 +35,15 @@
nativeBuildInputs = [ pkgs.librsvg ]; nativeBuildInputs = [ pkgs.librsvg ];
src = ./assets/RWT-Circular-Color-ForOnDark.svg; src = ./assets/RWT-Circular-Color-ForOnDark.svg;
dontUnpack = true;
buildPhase = '' buildPhase = ''
mkdir -p $out/share/plymouth/themes/radiantwave mkdir -p $out/share/plymouth/themes/radiantwave
rsvg-convert \ rsvg-convert \
--keep-aspect-ratio \ --keep-aspect-ratio \
--background-color=#111318 \ --background-color=#111318 \
--width=3840 \ --width=1280 \
--height=2160 \ --height=720 \
--output=$out/share/plymouth/themes/radiantwave/splash.png \ --output=$out/share/plymouth/themes/radiantwave/splash.png \
$src $src
sed 's,/usr/,'"$out"'/,g' ${./plymouth-theme/radiantwave.plymouth} \ sed 's,/usr/,'"$out"'/,g' ${./plymouth-theme/radiantwave.plymouth} \
@@ -52,7 +53,16 @@
''; '';
}; };
mkKioskSystem = { system, radiantwave, upgradeFlakeRef, extraModules ? [], diskModule, enableAutoUpgrade ? true, extraSpecialArgs ? {}}: revision = self.rev or self.dirtyRev or null;
mkKioskSystem = {
system,
radiantwave,
upgradeFlakeRef,
hostName,
diskModule,
extraModules ? [],
}:
nixpkgs.lib.nixosSystem { nixpkgs.lib.nixosSystem {
inherit system; inherit system;
@@ -60,20 +70,35 @@
inherit radiantwave; inherit radiantwave;
inherit upgradeFlakeRef; inherit upgradeFlakeRef;
inherit radiantwavePlymouth; inherit radiantwavePlymouth;
} // extraSpecialArgs; };
modules = [ modules = [
{ nixpkgs.config.allowUnfree = true; } { nixpkgs.config.allowUnfree = true; }
{
networking.hostName = hostName;
system.configurationRevision = revision;
}
./configuration.nix ./configuration.nix
disko.nixosModules.disko disko.nixosModules.disko
diskModule diskModule
nixos-facter-modules.nixosModules.facter nixos-facter-modules.nixosModules.facter
# Hardware facter report. This is a NUC 14 report currently
# applied to every x86 variant (including commercial SATA
# hardware). To use per-model reports: generate them on each
# hardware target (procedure in AGENTS.md), commit them as
# facter-<model>.json, and select per variant here, e.g.:
# { facter.reportPath = ./facter-commercial.json; }
{ facter.reportPath = ./facter.json; } { facter.reportPath = ./facter.json; }
radiantwave.nixosModules.default radiantwave.nixosModules.default
] ++ extraModules; ] ++ extraModules;
}; };
mkRpiKioskSystem = { radiantwave, upgradeFlakeRef, extraModules ? [], enableAutoUpgrade ? true }: mkRpiKioskSystem = {
radiantwave,
upgradeFlakeRef,
hostName,
extraModules ? [],
}:
nixos-raspberrypi.lib.nixosSystem { nixos-raspberrypi.lib.nixosSystem {
specialArgs = { specialArgs = {
inherit radiantwave upgradeFlakeRef; inherit radiantwave upgradeFlakeRef;
@@ -93,6 +118,9 @@
./configuration.nix ./configuration.nix
radiantwave.nixosModules.default radiantwave.nixosModules.default
{ {
networking.hostName = hostName;
system.configurationRevision = revision;
boot.loader.systemd-boot.enable = nixpkgs.lib.mkForce false; boot.loader.systemd-boot.enable = nixpkgs.lib.mkForce false;
boot.loader.efi.canTouchEfiVariables = nixpkgs.lib.mkForce false; boot.loader.efi.canTouchEfiVariables = nixpkgs.lib.mkForce false;
boot.loader.raspberry-pi.bootloader = "kernel"; boot.loader.raspberry-pi.bootloader = "kernel";
@@ -106,155 +134,137 @@
} }
] ++ extraModules; ] ++ extraModules;
}; };
# Zero-touch USB installer image. `targetConfig` names the kiosk system
# to install: the closure comes from the packages output below and the
# partitioning script from the paired disk module, so the ISO always
# installs the matching system for its hardware.
mkIso = { targetConfig, diskModule }:
nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {
inherit inputs;
inherit self;
};
modules = [
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
disko.nixosModules.disko
(import ./zero-touch-installer.nix { inherit targetConfig; })
diskModule
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.${targetConfig}
];
environment.etc."disko-config.nix".source = diskModule;
})
];
};
in in
{ {
packages.x86_64-linux.radiantwavekiosk = self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel; packages.x86_64-linux.radiantwavekiosk = self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-dev = self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.toplevel; packages.x86_64-linux.radiantwavekiosk-dev = self.nixosConfigurations.radiantwavekiosk-dev.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-commercial = self.nixosConfigurations.radiantwavekiosk-commercial.config.system.build.toplevel; packages.x86_64-linux.radiantwavekiosk-commercial = self.nixosConfigurations.radiantwavekiosk-commercial.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-commercial-dev = self.nixosConfigurations.radiantwavekiosk-commercial-dev.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-android = self.nixosConfigurations.radiantwavekiosk-android.config.system.build.toplevel; packages.x86_64-linux.radiantwavekiosk-android = self.nixosConfigurations.radiantwavekiosk-android.config.system.build.toplevel;
# Kiosk packages.x86_64-linux.radiantwavekiosk-android-dev = self.nixosConfigurations.radiantwavekiosk-android-dev.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-rpi = self.nixosConfigurations.radiantwavekiosk-rpi.config.system.build.toplevel;
packages.x86_64-linux.radiantwavekiosk-rpi-dev = self.nixosConfigurations.radiantwavekiosk-rpi-dev.config.system.build.toplevel;
# Kiosk systems.
#
# Production variants consume the `radiantwave` input (?ref=main);
# `-dev` variants consume `radiantwave-dev` (?ref=dev) and track the
# dev branch of this repo via their autoUpgrade flake refs.
nixosConfigurations = { nixosConfigurations = {
radiantwavekiosk = mkKioskSystem { radiantwavekiosk = mkKioskSystem {
system = "x86_64-linux"; system = "x86_64-linux";
radiantwave = radiantwave; radiantwave = radiantwave;
hostName = "radiantwavekiosk";
diskModule = ./disk-config.nix; diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk";
extraModules = [];
}; };
# Kiosk-dev
radiantwavekiosk-dev = mkKioskSystem { radiantwavekiosk-dev = mkKioskSystem {
system = "x86_64-linux"; system = "x86_64-linux";
radiantwave = radiantwave-dev; radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-dev";
diskModule = ./disk-config.nix; diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-dev"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-dev";
extraModules = [];
}; };
# Commercial
radiantwavekiosk-commercial = mkKioskSystem { radiantwavekiosk-commercial = mkKioskSystem {
system = "x86_64-linux"; system = "x86_64-linux";
radiantwave = radiantwave; radiantwave = radiantwave;
hostName = "radiantwavekiosk-commercial";
diskModule = ./commercial-disk-config.nix; diskModule = ./commercial-disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-commercial"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-commercial";
extraModules = [];
}; };
# Commercial-dev
radiantwavekiosk-commercial-dev = mkKioskSystem { radiantwavekiosk-commercial-dev = mkKioskSystem {
system = "x86_64-linux"; system = "x86_64-linux";
radiantwave = radiantwave; radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-commercial-dev";
diskModule = ./commercial-disk-config.nix; diskModule = ./commercial-disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-commercial"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-commercial-dev";
extraModules = [];
}; };
# Kiosk - rotated screen for android displays # Rotated screen for android-style displays.
radiantwavekiosk-android = mkKioskSystem { radiantwavekiosk-android = mkKioskSystem {
system = "x86_64-linux"; system = "x86_64-linux";
radiantwave = radiantwave; radiantwave = radiantwave;
hostName = "radiantwavekiosk-android";
diskModule = ./disk-config.nix; diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-android"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-android";
extraModules = [./rotated_display.nix ]; extraModules = [./rotated_display.nix];
}; };
# Raspberry pi 5 radiantwavekiosk-android-dev = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-android-dev";
diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-android-dev";
extraModules = [./rotated_display.nix];
};
# Raspberry Pi 5.
radiantwavekiosk-rpi = mkRpiKioskSystem { radiantwavekiosk-rpi = mkRpiKioskSystem {
radiantwave = radiantwave; radiantwave = radiantwave;
hostName = "radiantwavekiosk-rpi";
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-rpi"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-rpi";
}; };
# Raspberry pi 5 dev
radiantwavekiosk-rpi-dev = mkRpiKioskSystem { radiantwavekiosk-rpi-dev = mkRpiKioskSystem {
radiantwave = radiantwave-dev; radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-rpi-dev";
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-rpi-dev"; upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-rpi-dev";
}; };
# === USB Images === # === USB Images ===
# Kiosk ISO # Each ISO installs exactly the named system closure using that
kiosk-iso = nixpkgs.lib.nixosSystem { # system's disk layout. NVMe layouts pair with ./disk-config.nix,
system = "x86_64-linux"; # SATA with ./commercial-disk-config.nix — don't cross them.
specialArgs = { kiosk-iso = mkIso {
inherit inputs; targetConfig = "radiantwavekiosk";
inherit self; diskModule = ./disk-config.nix;
};
modules = [
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
disko.nixosModules.disko
./iso-config.nix
./disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk
];
environment.etc."disko-config.nix".source = ./disk-config.nix;
})
];
}; };
# Commercial iso commercial-iso = mkIso {
commercial-iso = nixpkgs.lib.nixosSystem { targetConfig = "radiantwavekiosk-commercial";
system = "x86_64-linux"; diskModule = ./commercial-disk-config.nix;
specialArgs = {
inherit inputs;
inherit self;
};
modules = [
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
disko.nixosModules.disko
./commercial-iso-config.nix
./commercial-disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk-commercial
];
environment.etc."disko-config.nix".source = ./commercial-disk-config.nix;
})
];
}; };
# kiosk rotated screen ISO android-iso = mkIso {
android-iso = nixpkgs.lib.nixosSystem { targetConfig = "radiantwavekiosk-android";
system = "x86_64-linux"; diskModule = ./disk-config.nix;
specialArgs = {
inherit inputs;
inherit self;
};
modules = [
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
disko.nixosModules.disko
./iso-config.nix
./disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk-android
];
environment.etc."disko-config.nix".source = ./disk-config.nix;
})
];
}; };
# Kiosk iso development branch dev-iso = mkIso {
dev-iso = nixpkgs.lib.nixosSystem { targetConfig = "radiantwavekiosk-dev";
system = "x86_64-linux"; diskModule = ./disk-config.nix;
specialArgs = { };
inherit inputs; commercial-dev-iso = mkIso {
inherit self; targetConfig = "radiantwavekiosk-commercial-dev";
}; diskModule = ./commercial-disk-config.nix;
modules = [ };
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" android-dev-iso = mkIso {
disko.nixosModules.disko targetConfig = "radiantwavekiosk-android-dev";
./dev-iso.nix diskModule = ./disk-config.nix;
./disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk-dev
];
environment.etc."disko-config.nix".source = ./disk-config.nix;
})
];
}; };
}; };
}; };
-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;
}
+15
View File
@@ -0,0 +1,15 @@
KioskConfig Commit,Date (CDT),URL Change,Pinned App Revision,App Revision Date,App Version on Home Screen
c06a3f7,2026-07-27 14:13,"codeberg.org/RhemaWave-Technologies/RhemaWave.git",9f8212cf550b,2026-06-27,2.3.5.8
5a6031a,2026-07-27 14:23,Codeberg → gitea.radiantwavetech.com/.../RhemaWave.git,9f8212cf550b,2026-06-27,2.3.5.8
7f2f19f,2026-07-27 14:24,RhemaWave.git → radiantwave.git,9f8212cf550b,2026-06-27,2.3.5.8
4af16d9,2026-07-28 10:43,Add ?ref=main,6ad6516a7461,2026-07-02,Coming Soon
cbb3e05,2026-08-07 17:13,Dev → radiantwave-cpp.git?ref=dev,b54dbca2d5e7,2026-08-03,07292026_1618
37d18d3,2026-08-07 17:18,Fix: dropped git+ prefix on dev URL,b54dbca2d5e7,2026-08-03,07292026_1618
50a1f3e,2026-08-07 17:19,Fix: restored git+ prefix on dev URL,b54dbca2d5e7,2026-08-03,07292026_1618
e3120f2,2026-08-08 00:02,Dev back to radiantwave.git?ref=dev,b54dbca2d5e7,2026-08-03,07292026_1618
50176d8,2026-08-17 10:51,New radiantwave-legacy input added,312f5e2a90e0,2026-08-08,08082026_0120
0cb1337,2026-08-17 10:57,Auth token added to legacy URL,312f5e2a90e0,2026-08-08,08082026_0120
fb2f861,2026-08-17 12:48,Prod pointed to radiantwave-legacy.git,312f5e2a90e0,2026-08-08,08082026_0120
027d1a6,2026-08-17 12:50,Token rotated (fb62d6c → 794ef1d),312f5e2a90e0,2026-08-08,08082026_0120
14463ad,2026-08-17 12:52,Token removed (repo made public),312f5e2a90e0,2026-08-08,08082026_0120
e09758a,2026-08-17 12:54,HTTPS → SSH (:2222),312f5e2a90e0,2026-08-08,08082026_0120
1 KioskConfig Commit Date (CDT) URL Change Pinned App Revision App Revision Date App Version on Home Screen
2 c06a3f7 2026-07-27 14:13 codeberg.org/RhemaWave-Technologies/RhemaWave.git 9f8212cf550b 2026-06-27 2.3.5.8
3 5a6031a 2026-07-27 14:23 Codeberg → gitea.radiantwavetech.com/.../RhemaWave.git 9f8212cf550b 2026-06-27 2.3.5.8
4 7f2f19f 2026-07-27 14:24 RhemaWave.git → radiantwave.git 9f8212cf550b 2026-06-27 2.3.5.8
5 4af16d9 2026-07-28 10:43 Add ?ref=main 6ad6516a7461 2026-07-02 Coming Soon
6 cbb3e05 2026-08-07 17:13 Dev → radiantwave-cpp.git?ref=dev b54dbca2d5e7 2026-08-03 07292026_1618
7 37d18d3 2026-08-07 17:18 Fix: dropped git+ prefix on dev URL b54dbca2d5e7 2026-08-03 07292026_1618
8 50a1f3e 2026-08-07 17:19 Fix: restored git+ prefix on dev URL b54dbca2d5e7 2026-08-03 07292026_1618
9 e3120f2 2026-08-08 00:02 Dev back to radiantwave.git?ref=dev b54dbca2d5e7 2026-08-03 07292026_1618
10 50176d8 2026-08-17 10:51 New radiantwave-legacy input added 312f5e2a90e0 2026-08-08 08082026_0120
11 0cb1337 2026-08-17 10:57 Auth token added to legacy URL 312f5e2a90e0 2026-08-08 08082026_0120
12 fb2f861 2026-08-17 12:48 Prod pointed to radiantwave-legacy.git 312f5e2a90e0 2026-08-08 08082026_0120
13 027d1a6 2026-08-17 12:50 Token rotated (fb62d6c → 794ef1d) 312f5e2a90e0 2026-08-08 08082026_0120
14 14463ad 2026-08-17 12:52 Token removed (repo made public) 312f5e2a90e0 2026-08-08 08082026_0120
15 e09758a 2026-08-17 12:54 HTTPS → SSH (:2222) 312f5e2a90e0 2026-08-08 08082026_0120
+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).
+10 -1
View File
@@ -2,8 +2,17 @@
let let
radiantApp = radiantwave.packages.${pkgs.system}.default; radiantApp = radiantwave.packages.${pkgs.system}.default;
kioskscript = pkgs.writeShellScript "kiosk-start" '' kioskscript = pkgs.writeShellScript "kiosk-start" ''
# Wait for the Wayland display to be ready
for i in {1..10}; do
if ${pkgs.wlr-randr}/bin/wlr-randr &>/dev/null; then
break
fi
sleep 1
done
OUTPUT=$(${pkgs.wlr-randr}/bin/wlr-randr | grep -m1 '^\S' | awk '{print $1}') OUTPUT=$(${pkgs.wlr-randr}/bin/wlr-randr | grep -m1 '^\S' | awk '{print $1}')
${pkgs.wlr-randr}/bin/wlr-randr --output "$OUTPUT" --transform 90 echo "Rotating output: $OUTPUT" >> /tmp/kiosk.log
${pkgs.wlr-randr}/bin/wlr-randr --output "$OUTPUT" --transform 90 >> /tmp/kiosk.log 2>&1 || echo "wlr-randr failed" >> /tmp/kiosk.log
exec ${radiantApp}/bin/radiantwave -d -s exec ${radiantApp}/bin/radiantwave -d -s
''; '';
in in
+130
View File
@@ -0,0 +1,130 @@
Date (CDT),KioskConfig Hash,RadiantWave Hash,App Version,Summary
2026-03-12 08:05:10 -0500,,403ec4db89b5,dev,Initial release: RadiantWave v1.0
2026-03-13 19:57:06 -0500,,ee2b3383a8da,dev,Fix WiFi password entry
2026-03-13 20:14:01 -0500,,c68757a63439,dev,Update version
2026-03-13 20:28:41 -0500,,91e5c04a3800,dev,Update version
2026-03-13 20:58:28 -0500,,5fef01107b03,dev,Attempt to fix wifi connectivity
2026-03-13 20:59:02 -0500,,a116e01146e9,dev,update version
2026-03-13 21:13:21 -0500,,5f254e94cd55,dev,Fix WiFi page update
2026-03-13 21:16:54 -0500,,f8fbfb721d3d,dev,Update version
2026-03-23 15:02:07 -0500,,17c088cc2fc2,dev,Update Database
2026-03-23 17:35:52 -0500,,8d2384139116,dev,Pull Proclamations & Categories from API and store them in the database
2026-03-24 11:19:50 -0500,,9b6bae9511ab,dev,List proclamations inside of categories
2026-03-25 11:27:16 -0500,,678d679b536d,dev,Fix bug loading 0 proclamations
2026-03-25 18:09:02 -0500,,465928915c2c,dev,Update version
2026-03-25 19:56:41 -0500,,c1c077dc698d,dev,Update asset locations and permissions
2026-03-25 20:33:58 -0500,,4aeaaf10b7d2,dev,Simplify asset handling
2026-03-29 23:41:16 -0500,,6e28b90ee860,dev,"Add wifi, license and email checks"
2026-03-30 00:08:52 -0500,,aea646f78868,dev,Set default volume to MAX
2026-03-30 00:10:21 -0500,,331a8255fd5d,v1.0.0,Set version to 1.0.0 statically
2026-03-30 00:43:01 -0500,,120772175d42,v1.0.0,Update Proclamation selection
2026-04-13 14:00:02 -0500,,105d8900d58d,v1.0.0,Replace audio devices with audio toggle
2026-04-13 14:09:26 -0500,,76fd6057778b,v1.0.0,Update changelog
2026-04-15 11:01:28 -0500,,b6bf0f1873b7,v1.0.0,Sync proclamations when entering proclamation list
2026-04-15 11:58:44 -0500,,10ba5df13261,v1.0.0,Force re-initialization of audio device when Play() is called
2026-04-15 13:56:53 -0500,,b94279be691a,v1.0.0,Update changelog
2026-04-17 11:43:59 -0500,,504095caa826,v1.0.0,Sync instead of download.
2026-04-23 16:44:09 -0500,,dd069e934508,1.0,WIP: Stagger proclamations
2026-04-24 11:06:50 -0500,,7f344ae5c806,1.0,Optimize proclamation loading
2026-05-06 10:16:19 -0500,,3cf3e4cf23f3,1.0,Fix database syncronization
2026-05-10 21:19:07 -0500,,87d484353fb0,1.0,Fixed WiFi password bug. Ready for testing and merge
2026-05-11 12:55:16 -0500,,1f9da7ee780a,1.0,Attempt to fix proclamation sync
2026-05-14 09:57:13 -0500,,3ea32e0eaa36,1.0,Add volume changing logic
2026-05-14 10:21:11 -0500,,5188c90350d8,1.0,Add working volume bar in audioDevices page
2026-05-26 14:12:27 -0500,,f7ef42c84ab5,1.0,Rename application to Radiant Wave
2026-05-31 12:08:19 -0500,,0ebc3adf4ae5,1.0,Proclamations change colors!
2026-05-31 12:15:10 -0500,,8268022d5128,1.0,Organize proclamations alphabetically
2026-06-03 11:21:28 -0500,,ddab8e446c6b,1.0.0-beta,Update version for visual preference during beta phase
2026-06-11 19:44:20 -0500,,4b7d2c13d5ce,1.0.0-beta,Rename audio devices to audio options
2026-06-18 08:02:21 -0500,,6b4867953756,1.0.0-beta,Add database logic
2026-06-18 11:29:45 -0500,,fe5543d50dea,1.0.0-beta,Audio downloads when necessary
2026-06-18 15:39:30 -0500,,a5f9780f410b,1.0.0-beta,Add download package
2026-06-18 15:49:05 -0500,,1a67b9780400,1.0.0-beta,un-mask wifi password
2026-06-18 15:49:29 -0500,,b11afe22f09e,1.0.0-beta,remove file downloads
2026-06-18 21:28:16 -0500,,7ecb90b63b61,1.0,Downloads are working and the goroutine is reporting updates appropriately.
2026-06-18 21:52:29 -0500,,2af1aae88580,1.0,Audio files download on application start. Home screen shows status message
2026-06-18 22:43:47 -0500,,ac86864c7286,1.0,Add downloading message to home screen.
2026-06-18 22:51:17 -0500,,1c814f4abb6b,1.0,Reset default volume to MAX
2026-06-19 00:13:25 -0500,,4cd24375cdac,1.0,Add audio features
2026-06-23 11:22:21 -0500,,30dd5ffdcb94,1.0,Create objects for tracking audio devices
2026-06-24 14:17:06 -0500,,0a9a33b87b90,1.0,Fix download URL mismatch
2026-06-24 14:50:13 -0500,,970b8ebf09af,1.0,Add verbose logging to download.DownloadAudioFiles
2026-06-24 14:57:42 -0500,,cc2887d2a06d,b018a79,Update version text and add more download logs
2026-06-24 18:29:59 -0500,,953d0d8bc93d,b018a79,Rewrite entire network package and update wifi page
2026-06-24 22:41:48 -0500,,a4eff17b77a1,b018a79,"fix(network): fix wifi page never scanning, never exiting, and UI freezes on connect"
2026-06-24 23:18:32 -0500,,57500308b00d,b018a79,Handle locked database cases
2026-06-24 23:20:57 -0500,,f8e75194e845,cd79a6f,Update version hash for visual verification
2026-06-26 18:07:12 -0500,,4dd78b5ade8a,9beeeb1,Update version number for visual validation
2026-06-27 00:37:07 -0500,,2fac3ab6a8aa,9beeeb1,Replace textInputSupported flag
2026-06-27 01:47:06 -0500,,ca18000c8ef4,2.3.5.8,Update version string for validation
2026-06-27 12:57:29 -0500,,18c57c9101bf,2.3.5.8,Remove calls to RefreshConfig
2026-06-27 13:59:22 -0500,,f00cb9efb6a0,2.3.5.8,Fix download progress and prevent re-downloading existing audio.
2026-06-27 14:25:25 -0500,,2c88b7ffc515,2.3.5.8,Add creation of audio directory and remove unused function in download package
2026-06-27 14:25:51 -0500,,0b43a982985b,2.3.5.8,Remove unused function in download package
2026-06-27 14:50:50 -0500,,8ec1cbbc480b,2.3.5.8,Log the app config in Debug
2026-06-27 15:09:51 -0500,,ba39ed85a943,2.3.5.8,Remove wal and shm deletion
2026-06-27 16:01:33 -0500,,7e598f191f72,2.3.5.8,Update Network package
2026-06-27 16:51:18 -0500,,b0947bd59447,2.3.5.8,Fix bugs in WiFi page
2026-06-28 01:56:35 -0500,,193ebbcb2714,2.3.5.8,Fix network connection timeouts and security detection
2026-06-28 15:11:35 -0500,,6ad8a19f2ad9,2.3.5.8,Increase startup volume to 1.0
2026-06-28 15:18:27 -0500,,c232d417ba31,Coming Soon,Update version string
2026-07-10 13:56:06 -0500,,2bcb36669fd2,Coming Soon,fix: restore SDL volume to MAX after device switch
2026-07-10 13:56:12 -0500,,9bc0fd6820bb,Coming Soon,fix: restore SDL volume to MAX after device switch
2026-07-10 14:00:48 -0500,,68b3680e32bc,Coming Soon,fix: make wayland/X11 buildInputs Linux-only for macOS dev shell
2026-07-10 14:18:47 -0500,,779bc77c5b45,Coming Soon,fix: use recursiveUpdate instead of // to preserve packages.default
2026-07-10 16:02:02 -0500,,313db8ccd18a,Coming Soon,fix: rewrite cmd_diagnose to use script upload instead of nested SSH quoting
2026-07-10 17:12:48 -0500,,fca635482901,Coming Soon,Create Docker build pipeline for MacOS
2026-07-11 09:01:05 -0500,,141613f571ed,Audio-Bug-Fix 0.1,Update version string to indicate audio-bug-fixes
2026-07-11 09:45:12 -0500,,9dc1ce77aefc,Audio-Bug-Fix 0.1,WIP on dev: 141613f Update version string to indicate audio-bug-fixes
2026-07-11 09:45:12 -0500,,bdbc525b6fb7,Audio-Bug-Fix 0.1,index on dev: 141613f Update version string to indicate audio-bug-fixes
2026-07-11 10:16:15 -0500,,72910e700605,Audio-Bug-Fix 0.1,fix: prevent Play() deadlock when device is not open
2026-07-11 11:39:58 -0500,,bb132ceeaf86,Audio-Bug-Fix 0.5,fix: resolve 4 critical audio mixer bugs (v0.5)
2026-07-11 13:43:05 -0500,,3f8144a708bb,Audio-Bug-Fix 0.6,Gate READY on download completion; move audio to ~/.radiantwave/audio
2026-07-11 15:27:01 -0500,,336f407499f4,Audio-Bug-Fix 0.6,Allow F2/F3 during DOWNLOADING_ASSETS state
2026-07-11 16:36:15 -0500,,a93e47589984,Audio-Bug-Fix 0.6,Fix double-close panic on DownloadDone channel
2026-07-11 16:43:16 -0500,,2ef826fe635b,Audio-Bug-Fix 0.6,Fix double-close panic on DownloadDone: skip re-navigation between HOME-mapped states
2026-07-11 17:10:59 -0500,,f29d1d1af51e,07112026-1710,Bump version to 07112026-1710; move completed items to release section
2026-07-12 18:15:41 -0500,,c98b84a3a8f3,07112026-1710,fix: active device highlight incorrect when using default device
2026-07-12 18:16:18 -0500,,e090870b4dfd,07112026-1710,fix: SwitchDevice no longer passes 'system default' to SDL
2026-07-12 18:17:22 -0500,,5854c57f6f01,07112026-1710,"changelog: update fixed issues list, remove known issues"
2026-07-27 13:14:37 -0500,,b1a5a670ab0b,07112026-1710,Add audio list
2026-07-27 14:13:58 -0500,c06a3f7f92de,,07112026-1710,init new repo
2026-07-27 14:23:31 -0500,5a6031a3fe5a,,07112026-1710,refactor: migrate from Codeberg to Gitea and rename rhemawave to radiantwave
2026-07-27 14:24:25 -0500,7f2f19fe41d9,,07112026-1710,fix: use correct lowercase repo name radiantwave.git
2026-07-27 14:29:03 -0500,26aca21e963d,,07112026-1710,Update flake.lock
2026-07-28 14:10:44 +0000,16545a77fd7e,,07112026-1710,chore: update radiantwave-dev to latest dev
2026-07-28 10:43:06 -0500,4af16d9df7c4,,07112026-1710,Specify main branch
2026-07-29 14:46:11 -0500,,6dda46288473,07292026_1445,Add audio selection
2026-07-29 14:57:32 -0500,,7a3b6a66b72f,07292026_1445,"Remove wpctl parsing tests (TestParseSinkLine, TestParseSinks)"
2026-07-29 14:58:15 -0500,,3480e7594a3b,07292026_1445,Replace wpctl volume control with SDL_mixer VolumeMusic
2026-07-29 16:19:15 -0500,,91711eef9328,07292026_1618,"Replace AudioFile with AudioTrack, fix download+orphan+MD5 sync, always play original audio fallback"
2026-07-29 19:40:04 -0500,09bc293af31e,,07292026_1618,Chore: Update RadiantWave
2026-08-02 00:56:34 -0500,ab6488028120,,07292026_1618,Organize flakes and cleanup things.
2026-08-03 01:54:27 -0500,,11b25227d789,07292026_1618,"Rename app to radiantwave: embed and provision assets, drop proclamations"
2026-08-03 01:54:52 -0500,ce6856b37a09,,07292026_1618,"Fix kiosk startup: radiantwave binary, drop stale rsync, fix GODEBUG typo"
2026-08-03 07:26:16 +0000,8ef25f756076,,07292026_1618,chore: update radiantwave-dev to latest
2026-08-03 02:40:51 -0500,,b54dbca2d5e7,07292026_1618,Fix asset provisioning to strip embedded share/radiantwave root
2026-08-06 10:13:40 -0500,0f5aa7670cf9,,07292026_1618,Chore: Update Radiantwave
2026-08-06 21:55:40 -0500,c3f65f78976f,,07292026_1618,Fix audio: pin system volume to 100% before RadiantWave launches
2026-08-07 00:38:25 -0500,2d4aca230d04,,07292026_1618,Update configuration and dev-iso
2026-08-07 17:13:59 -0500,cbb3e0585970,,07292026_1618,"Update to radiantave-cpp, enable plymouth boot image"
2026-08-07 17:18:32 -0500,37d18d3f474b,,07292026_1618,Update repository location
2026-08-07 17:19:04 -0500,50a1f3e99dfc,,07292026_1618,Update repository location
2026-08-07 17:39:26 -0500,06f02d49b910,,07292026_1618,update radiantwave to radiatnwave-dev
2026-08-07 17:47:04 -0500,2e3d88b57dce,,07292026_1618,Update Plymount dontUnpack = true;
2026-08-07 22:17:52 -0500,4580319f19f5,,07292026_1618,Update radiantwave-dev
2026-08-07 23:58:25 -0500,8abb028c8260,,07292026_1618,fix wpctl volume pinning
2026-08-08 00:02:09 -0500,e3120f27c20b,,07292026_1618,Pull back from radiantwave-cpp-dev to radiantwave-dev
2026-08-08 00:12:57 -0500,,2212cc9b7805,07292026_1618,Add audio device switching UI
2026-08-08 01:20:11 -0500,,312f5e2a90e0,08082026_0120,Rename rhemawave to radiantwave throughout
2026-08-08 06:25:05 +0000,1f3e194aa558,,08082026_0120,Chore: Update Radiantwave-dev
2026-08-08 01:44:03 -0500,240be2540f3f,,08082026_0120,Update Radiantwave
2026-08-17 10:44:36 -0500,06c2a7cd0a1e,,08082026_0120,Add plan to migrate to DRM
2026-08-17 10:51:05 -0500,50176d8fd5e4,,08082026_0120,"repoint production to radiantwave-legacy, dev to radiantwave (ref=main)"
2026-08-17 10:57:16 -0500,0cb1337f18fd,,08082026_0120,"add radiantwave-legacy input with auth token, update flake.lock"
2026-08-17 11:02:19 -0500,2abdfa2b9b28,,08082026_0120,revert upgradeFlakeRef URLs to KioskConfig to match renamed repo
2026-08-17 12:43:57 -0500,974a61051883,,08082026_0120,Update dev images to new radiantwave
2026-08-17 12:48:22 -0500,fb2f86125804,,08082026_0120,Revert back to Legacy Radiant Wave
2026-08-17 12:50:20 -0500,027d1a628feb,,08082026_0120,Update token
2026-08-17 12:52:11 -0500,14463ad99b08,,08082026_0120,Just make RadiantWave-Legacy public
2026-08-17 12:54:06 -0500,e09758a70ece,,08082026_0120,fix: switch radiantwave inputs to SSH for legacy Go repo
1 Date (CDT) KioskConfig Hash RadiantWave Hash App Version Summary
2 2026-03-12 08:05:10 -0500 403ec4db89b5 dev Initial release: RadiantWave v1.0
3 2026-03-13 19:57:06 -0500 ee2b3383a8da dev Fix WiFi password entry
4 2026-03-13 20:14:01 -0500 c68757a63439 dev Update version
5 2026-03-13 20:28:41 -0500 91e5c04a3800 dev Update version
6 2026-03-13 20:58:28 -0500 5fef01107b03 dev Attempt to fix wifi connectivity
7 2026-03-13 20:59:02 -0500 a116e01146e9 dev update version
8 2026-03-13 21:13:21 -0500 5f254e94cd55 dev Fix WiFi page update
9 2026-03-13 21:16:54 -0500 f8fbfb721d3d dev Update version
10 2026-03-23 15:02:07 -0500 17c088cc2fc2 dev Update Database
11 2026-03-23 17:35:52 -0500 8d2384139116 dev Pull Proclamations & Categories from API and store them in the database
12 2026-03-24 11:19:50 -0500 9b6bae9511ab dev List proclamations inside of categories
13 2026-03-25 11:27:16 -0500 678d679b536d dev Fix bug loading 0 proclamations
14 2026-03-25 18:09:02 -0500 465928915c2c dev Update version
15 2026-03-25 19:56:41 -0500 c1c077dc698d dev Update asset locations and permissions
16 2026-03-25 20:33:58 -0500 4aeaaf10b7d2 dev Simplify asset handling
17 2026-03-29 23:41:16 -0500 6e28b90ee860 dev Add wifi, license and email checks
18 2026-03-30 00:08:52 -0500 aea646f78868 dev Set default volume to MAX
19 2026-03-30 00:10:21 -0500 331a8255fd5d v1.0.0 Set version to 1.0.0 statically
20 2026-03-30 00:43:01 -0500 120772175d42 v1.0.0 Update Proclamation selection
21 2026-04-13 14:00:02 -0500 105d8900d58d v1.0.0 Replace audio devices with audio toggle
22 2026-04-13 14:09:26 -0500 76fd6057778b v1.0.0 Update changelog
23 2026-04-15 11:01:28 -0500 b6bf0f1873b7 v1.0.0 Sync proclamations when entering proclamation list
24 2026-04-15 11:58:44 -0500 10ba5df13261 v1.0.0 Force re-initialization of audio device when Play() is called
25 2026-04-15 13:56:53 -0500 b94279be691a v1.0.0 Update changelog
26 2026-04-17 11:43:59 -0500 504095caa826 v1.0.0 Sync instead of download.
27 2026-04-23 16:44:09 -0500 dd069e934508 1.0 WIP: Stagger proclamations
28 2026-04-24 11:06:50 -0500 7f344ae5c806 1.0 Optimize proclamation loading
29 2026-05-06 10:16:19 -0500 3cf3e4cf23f3 1.0 Fix database syncronization
30 2026-05-10 21:19:07 -0500 87d484353fb0 1.0 Fixed WiFi password bug. Ready for testing and merge
31 2026-05-11 12:55:16 -0500 1f9da7ee780a 1.0 Attempt to fix proclamation sync
32 2026-05-14 09:57:13 -0500 3ea32e0eaa36 1.0 Add volume changing logic
33 2026-05-14 10:21:11 -0500 5188c90350d8 1.0 Add working volume bar in audioDevices page
34 2026-05-26 14:12:27 -0500 f7ef42c84ab5 1.0 Rename application to Radiant Wave
35 2026-05-31 12:08:19 -0500 0ebc3adf4ae5 1.0 Proclamations change colors!
36 2026-05-31 12:15:10 -0500 8268022d5128 1.0 Organize proclamations alphabetically
37 2026-06-03 11:21:28 -0500 ddab8e446c6b 1.0.0-beta Update version for visual preference during beta phase
38 2026-06-11 19:44:20 -0500 4b7d2c13d5ce 1.0.0-beta Rename audio devices to audio options
39 2026-06-18 08:02:21 -0500 6b4867953756 1.0.0-beta Add database logic
40 2026-06-18 11:29:45 -0500 fe5543d50dea 1.0.0-beta Audio downloads when necessary
41 2026-06-18 15:39:30 -0500 a5f9780f410b 1.0.0-beta Add download package
42 2026-06-18 15:49:05 -0500 1a67b9780400 1.0.0-beta un-mask wifi password
43 2026-06-18 15:49:29 -0500 b11afe22f09e 1.0.0-beta remove file downloads
44 2026-06-18 21:28:16 -0500 7ecb90b63b61 1.0 Downloads are working and the goroutine is reporting updates appropriately.
45 2026-06-18 21:52:29 -0500 2af1aae88580 1.0 Audio files download on application start. Home screen shows status message
46 2026-06-18 22:43:47 -0500 ac86864c7286 1.0 Add downloading message to home screen.
47 2026-06-18 22:51:17 -0500 1c814f4abb6b 1.0 Reset default volume to MAX
48 2026-06-19 00:13:25 -0500 4cd24375cdac 1.0 Add audio features
49 2026-06-23 11:22:21 -0500 30dd5ffdcb94 1.0 Create objects for tracking audio devices
50 2026-06-24 14:17:06 -0500 0a9a33b87b90 1.0 Fix download URL mismatch
51 2026-06-24 14:50:13 -0500 970b8ebf09af 1.0 Add verbose logging to download.DownloadAudioFiles
52 2026-06-24 14:57:42 -0500 cc2887d2a06d b018a79 Update version text and add more download logs
53 2026-06-24 18:29:59 -0500 953d0d8bc93d b018a79 Rewrite entire network package and update wifi page
54 2026-06-24 22:41:48 -0500 a4eff17b77a1 b018a79 fix(network): fix wifi page never scanning, never exiting, and UI freezes on connect
55 2026-06-24 23:18:32 -0500 57500308b00d b018a79 Handle locked database cases
56 2026-06-24 23:20:57 -0500 f8e75194e845 cd79a6f Update version hash for visual verification
57 2026-06-26 18:07:12 -0500 4dd78b5ade8a 9beeeb1 Update version number for visual validation
58 2026-06-27 00:37:07 -0500 2fac3ab6a8aa 9beeeb1 Replace textInputSupported flag
59 2026-06-27 01:47:06 -0500 ca18000c8ef4 2.3.5.8 Update version string for validation
60 2026-06-27 12:57:29 -0500 18c57c9101bf 2.3.5.8 Remove calls to RefreshConfig
61 2026-06-27 13:59:22 -0500 f00cb9efb6a0 2.3.5.8 Fix download progress and prevent re-downloading existing audio.
62 2026-06-27 14:25:25 -0500 2c88b7ffc515 2.3.5.8 Add creation of audio directory and remove unused function in download package
63 2026-06-27 14:25:51 -0500 0b43a982985b 2.3.5.8 Remove unused function in download package
64 2026-06-27 14:50:50 -0500 8ec1cbbc480b 2.3.5.8 Log the app config in Debug
65 2026-06-27 15:09:51 -0500 ba39ed85a943 2.3.5.8 Remove wal and shm deletion
66 2026-06-27 16:01:33 -0500 7e598f191f72 2.3.5.8 Update Network package
67 2026-06-27 16:51:18 -0500 b0947bd59447 2.3.5.8 Fix bugs in WiFi page
68 2026-06-28 01:56:35 -0500 193ebbcb2714 2.3.5.8 Fix network connection timeouts and security detection
69 2026-06-28 15:11:35 -0500 6ad8a19f2ad9 2.3.5.8 Increase startup volume to 1.0
70 2026-06-28 15:18:27 -0500 c232d417ba31 Coming Soon Update version string
71 2026-07-10 13:56:06 -0500 2bcb36669fd2 Coming Soon fix: restore SDL volume to MAX after device switch
72 2026-07-10 13:56:12 -0500 9bc0fd6820bb Coming Soon fix: restore SDL volume to MAX after device switch
73 2026-07-10 14:00:48 -0500 68b3680e32bc Coming Soon fix: make wayland/X11 buildInputs Linux-only for macOS dev shell
74 2026-07-10 14:18:47 -0500 779bc77c5b45 Coming Soon fix: use recursiveUpdate instead of // to preserve packages.default
75 2026-07-10 16:02:02 -0500 313db8ccd18a Coming Soon fix: rewrite cmd_diagnose to use script upload instead of nested SSH quoting
76 2026-07-10 17:12:48 -0500 fca635482901 Coming Soon Create Docker build pipeline for MacOS
77 2026-07-11 09:01:05 -0500 141613f571ed Audio-Bug-Fix 0.1 Update version string to indicate audio-bug-fixes
78 2026-07-11 09:45:12 -0500 9dc1ce77aefc Audio-Bug-Fix 0.1 WIP on dev: 141613f Update version string to indicate audio-bug-fixes
79 2026-07-11 09:45:12 -0500 bdbc525b6fb7 Audio-Bug-Fix 0.1 index on dev: 141613f Update version string to indicate audio-bug-fixes
80 2026-07-11 10:16:15 -0500 72910e700605 Audio-Bug-Fix 0.1 fix: prevent Play() deadlock when device is not open
81 2026-07-11 11:39:58 -0500 bb132ceeaf86 Audio-Bug-Fix 0.5 fix: resolve 4 critical audio mixer bugs (v0.5)
82 2026-07-11 13:43:05 -0500 3f8144a708bb Audio-Bug-Fix 0.6 Gate READY on download completion; move audio to ~/.radiantwave/audio
83 2026-07-11 15:27:01 -0500 336f407499f4 Audio-Bug-Fix 0.6 Allow F2/F3 during DOWNLOADING_ASSETS state
84 2026-07-11 16:36:15 -0500 a93e47589984 Audio-Bug-Fix 0.6 Fix double-close panic on DownloadDone channel
85 2026-07-11 16:43:16 -0500 2ef826fe635b Audio-Bug-Fix 0.6 Fix double-close panic on DownloadDone: skip re-navigation between HOME-mapped states
86 2026-07-11 17:10:59 -0500 f29d1d1af51e 07112026-1710 Bump version to 07112026-1710; move completed items to release section
87 2026-07-12 18:15:41 -0500 c98b84a3a8f3 07112026-1710 fix: active device highlight incorrect when using default device
88 2026-07-12 18:16:18 -0500 e090870b4dfd 07112026-1710 fix: SwitchDevice no longer passes 'system default' to SDL
89 2026-07-12 18:17:22 -0500 5854c57f6f01 07112026-1710 changelog: update fixed issues list, remove known issues
90 2026-07-27 13:14:37 -0500 b1a5a670ab0b 07112026-1710 Add audio list
91 2026-07-27 14:13:58 -0500 c06a3f7f92de 07112026-1710 init new repo
92 2026-07-27 14:23:31 -0500 5a6031a3fe5a 07112026-1710 refactor: migrate from Codeberg to Gitea and rename rhemawave to radiantwave
93 2026-07-27 14:24:25 -0500 7f2f19fe41d9 07112026-1710 fix: use correct lowercase repo name radiantwave.git
94 2026-07-27 14:29:03 -0500 26aca21e963d 07112026-1710 Update flake.lock
95 2026-07-28 14:10:44 +0000 16545a77fd7e 07112026-1710 chore: update radiantwave-dev to latest dev
96 2026-07-28 10:43:06 -0500 4af16d9df7c4 07112026-1710 Specify main branch
97 2026-07-29 14:46:11 -0500 6dda46288473 07292026_1445 Add audio selection
98 2026-07-29 14:57:32 -0500 7a3b6a66b72f 07292026_1445 Remove wpctl parsing tests (TestParseSinkLine, TestParseSinks)
99 2026-07-29 14:58:15 -0500 3480e7594a3b 07292026_1445 Replace wpctl volume control with SDL_mixer VolumeMusic
100 2026-07-29 16:19:15 -0500 91711eef9328 07292026_1618 Replace AudioFile with AudioTrack, fix download+orphan+MD5 sync, always play original audio fallback
101 2026-07-29 19:40:04 -0500 09bc293af31e 07292026_1618 Chore: Update RadiantWave
102 2026-08-02 00:56:34 -0500 ab6488028120 07292026_1618 Organize flakes and cleanup things.
103 2026-08-03 01:54:27 -0500 11b25227d789 07292026_1618 Rename app to radiantwave: embed and provision assets, drop proclamations
104 2026-08-03 01:54:52 -0500 ce6856b37a09 07292026_1618 Fix kiosk startup: radiantwave binary, drop stale rsync, fix GODEBUG typo
105 2026-08-03 07:26:16 +0000 8ef25f756076 07292026_1618 chore: update radiantwave-dev to latest
106 2026-08-03 02:40:51 -0500 b54dbca2d5e7 07292026_1618 Fix asset provisioning to strip embedded share/radiantwave root
107 2026-08-06 10:13:40 -0500 0f5aa7670cf9 07292026_1618 Chore: Update Radiantwave
108 2026-08-06 21:55:40 -0500 c3f65f78976f 07292026_1618 Fix audio: pin system volume to 100% before RadiantWave launches
109 2026-08-07 00:38:25 -0500 2d4aca230d04 07292026_1618 Update configuration and dev-iso
110 2026-08-07 17:13:59 -0500 cbb3e0585970 07292026_1618 Update to radiantave-cpp, enable plymouth boot image
111 2026-08-07 17:18:32 -0500 37d18d3f474b 07292026_1618 Update repository location
112 2026-08-07 17:19:04 -0500 50a1f3e99dfc 07292026_1618 Update repository location
113 2026-08-07 17:39:26 -0500 06f02d49b910 07292026_1618 update radiantwave to radiatnwave-dev
114 2026-08-07 17:47:04 -0500 2e3d88b57dce 07292026_1618 Update Plymount dontUnpack = true;
115 2026-08-07 22:17:52 -0500 4580319f19f5 07292026_1618 Update radiantwave-dev
116 2026-08-07 23:58:25 -0500 8abb028c8260 07292026_1618 fix wpctl volume pinning
117 2026-08-08 00:02:09 -0500 e3120f27c20b 07292026_1618 Pull back from radiantwave-cpp-dev to radiantwave-dev
118 2026-08-08 00:12:57 -0500 2212cc9b7805 07292026_1618 Add audio device switching UI
119 2026-08-08 01:20:11 -0500 312f5e2a90e0 08082026_0120 Rename rhemawave to radiantwave throughout
120 2026-08-08 06:25:05 +0000 1f3e194aa558 08082026_0120 Chore: Update Radiantwave-dev
121 2026-08-08 01:44:03 -0500 240be2540f3f 08082026_0120 Update Radiantwave
122 2026-08-17 10:44:36 -0500 06c2a7cd0a1e 08082026_0120 Add plan to migrate to DRM
123 2026-08-17 10:51:05 -0500 50176d8fd5e4 08082026_0120 repoint production to radiantwave-legacy, dev to radiantwave (ref=main)
124 2026-08-17 10:57:16 -0500 0cb1337f18fd 08082026_0120 add radiantwave-legacy input with auth token, update flake.lock
125 2026-08-17 11:02:19 -0500 2abdfa2b9b28 08082026_0120 revert upgradeFlakeRef URLs to KioskConfig to match renamed repo
126 2026-08-17 12:43:57 -0500 974a61051883 08082026_0120 Update dev images to new radiantwave
127 2026-08-17 12:48:22 -0500 fb2f86125804 08082026_0120 Revert back to Legacy Radiant Wave
128 2026-08-17 12:50:20 -0500 027d1a628feb 08082026_0120 Update token
129 2026-08-17 12:52:11 -0500 14463ad99b08 08082026_0120 Just make RadiantWave-Legacy public
130 2026-08-17 12:54:06 -0500 e09758a70ece 08082026_0120 fix: switch radiantwave inputs to SSH for legacy Go repo
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Archive old build images on the fileserver before publishing new ones.
#
# Usage: tools/archive-images.sh <ssh-target> <images-dir> <archive-dir> <pattern>...
#
# Zero matching files is fine (nothing to archive yet); a missing directory
# or a failed move aborts non-zero so CI stops before publishing.
# The remote half is piped to `bash -s` over stdin so there is no nested
# shell quoting to get wrong.
set -euo pipefail
die() { echo "error: $*" >&2; exit 1; }
(( $# >= 4 )) || die "usage: $0 <ssh-target> <images-dir> <archive-dir> <pattern>..."
target=$1 images_dir=$2 archive_dir=$3
shift 3
patterns=("$@")
for v in "$images_dir" "$archive_dir" "${patterns[@]}"; do
case $v in
*[[:space:]\'\"]*) die "unsafe argument (whitespace/quotes): $v" ;;
esac
done
echo "Archiving previous images on $target:"
printf ' pattern: %s\n' "${patterns[@]}"
# Assignments prefixed to `bash -s` are parsed by the remote shell as
# environment variables for the script below; the quoted heredoc marker
# keeps every byte of the payload literal until bash executes it.
ssh "$target" "IMAGES_DIR=$images_dir ARCHIVE_DIR=$archive_dir bash -s" <<'REMOTE'
set -euo pipefail
shopt -s nullglob
if [ ! -d "$IMAGES_DIR" ]; then
echo "error: images dir not found: $IMAGES_DIR" >&2
exit 1
fi
if [ ! -d "$ARCHIVE_DIR" ]; then
echo "error: archive dir not found: $ARCHIVE_DIR" >&2
exit 1
fi
moved=0
for pat in "${PATTERNS[@]}"; do
for f in "$IMAGES_DIR"/$pat; do
echo " archiving $(basename "$f")"
mv "$f" "$ARCHIVE_DIR/"
moved=$((moved + 1))
done
done
echo "Archived $moved file(s)."
REMOTE
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env zsh
#
# find_systems.zsh
# Sweeps a subnet for hosts with SSH open, then queries each as `kiosk`
# for hostname + NixOS configuration revision.
#
# Usage: ./find_systems.zsh [subnet]
# subnet defaults to 192.168.4.0/24
set -uo pipefail # no -e: we want to keep going past unreachable hosts
SUBNET="${1:-192.168.4.0/24}"
SSH_USER="kiosk"
SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new)
echo "Scanning $SUBNET for open SSH (22)..."
ips=("${(@f)$(nmap -p 22 --open -Pn "$SUBNET" -oG - | awk '/22\/open/ {print $2}')}")
if [[ ${#ips[@]} -eq 0 ]]; then
echo "No hosts with open SSH found on $SUBNET."
exit 0
fi
echo "Found ${#ips[@]} host(s). Querying..."
echo
fail_count=0
for ip in "${ips[@]}"; do
echo "== $ip =="
if ssh "${SSH_OPTS[@]}" "${SSH_USER}@${ip}" \
'echo "host: $(hostname)"; echo "rev: $(nixos-version --configuration-revision)"'; then
:
else
echo " (unreachable or auth failed)"
((fail_count++))
fi
echo
done
echo "Done. ${fail_count} of ${#ips[@]} host(s) failed to respond."
-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"
];
};
};
};
};
};
};
}
+19 -32
View File
@@ -1,3 +1,13 @@
# Parameterized zero-touch installer for kiosk USB images.
#
# Usage in flake.nix:
# (import ./zero-touch-installer.nix { targetConfig = "radiantwavekiosk"; })
#
# `targetConfig` must name an entry in self.nixosConfigurations. The target
# closure and its disko partitioning script are derived from that config, so
# an image can never install a mismatched system or format the wrong disk
# layout as long as flake.nix pairs each ISO with its disk-config.nix.
{ targetConfig }:
{ {
pkgs, pkgs,
inputs, inputs,
@@ -5,17 +15,15 @@
... ...
}: }:
let let
targetSystem = cfg = self.nixosConfigurations.${targetConfig};
self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel; targetSystem = cfg.config.system.build.toplevel;
diskoScript = cfg.config.system.build.diskoScript;
diskoScript = # Keep in sync with myKey in configuration.nix.
self.nixosConfigurations.radiantwavekiosk.config.system.build.diskoScript; adminKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook";
in in
{ {
############################################################
# System configuration
############################################################
nix.settings = { nix.settings = {
experimental-features = [ experimental-features = [
"nix-command" "nix-command"
@@ -38,32 +46,11 @@ in
}; };
}; };
nix.extraOptions = ''
netrc-file = /etc/nix/netrc
'';
environment.variables.KIOSK_FLAKE = "${self}"; environment.variables.KIOSK_FLAKE = "${self}";
environment.etc."nix/netrc" = {
text = ''
password eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjIwODgzODk2ODEsIm5iZiI6MTc3MjgxMzY4MSwic3ViIjoia2lvc2siLCJodHRwczovL2p3dC5hdHRpYy5ycy92MSI6eyJjYWNoZXMiOnsia2lvc2siOnsiciI6MX19fX0.N6Ktrmmu1LSy2PP8uNF25VHRP1dxPZJ4M0MR1kUpVi0
'';
mode = "0400";
};
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
############################################################ users.users.root.openssh.authorizedKeys.keys = [ adminKey ];
# User configuration
############################################################
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook"
];
############################################################
# Service configuration
############################################################
services.openssh.enable = true; services.openssh.enable = true;
@@ -115,7 +102,7 @@ in
${diskoScript} ${diskoScript}
echo "Installing RadiantWave" echo "Installing RadiantWave (${targetConfig})"
echo "Closure Path: ${targetSystem}" echo "Closure Path: ${targetSystem}"
nixos-install \ nixos-install \
@@ -127,7 +114,7 @@ in
echo " Installation complete!" echo " Installation complete!"
echo " Please shut down and remove the flash drive before restarting" echo " Please shut down and remove the flash drive before restarting"
echo "============================================" echo "============================================"
sleep 10000000 sleep infinity
''; '';
}; };
} }