27 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
15 changed files with 392 additions and 668 deletions
+14 -9
View File
@@ -2,19 +2,25 @@ name: Build Dev ISO
on: on:
workflow_dispatch: workflow_dispatch:
push:
branches:
- dev
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
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git . 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
@@ -34,8 +40,7 @@ jobs:
echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV" echo "KIOSK_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV"
- name: Move old dev images to archive - name: Move old dev images to archive
run: | run: tools/archive-images.sh nclack@157.245.124.103 /mnt/infrastructure_data/files/images /mnt/infrastructure_data/files/images/archives 'radiantwave-kiosk-dev*'
ssh nclack@157.245.124.103 'mv /mnt/infrastructure_data/files/images/radiantwave-kiosk-dev* /mnt/infrastructure_data/files/images/archives/'
- name: Copy kiosk ISO to fileserver - name: Copy kiosk ISO to fileserver
run: | run: |
+9
View File
@@ -1,6 +1,11 @@
on: on:
workflow_dispatch: workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs: jobs:
build-android: build-android:
runs-on: build-server runs-on: build-server
@@ -25,6 +30,10 @@ jobs:
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}" cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "ANDROID_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV" 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 - name: Copy android kiosk ISO to fileserver
run: | run: |
scp "/home/user/radiantwave/${ANDROID_ISO_FILENAME}" \ scp "/home/user/radiantwave/${ANDROID_ISO_FILENAME}" \
@@ -1,6 +1,11 @@
on: on:
workflow_dispatch: workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs: jobs:
build-commercial: build-commercial:
runs-on: build-server runs-on: build-server
@@ -25,6 +30,10 @@ jobs:
cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}" cp -L result/iso/*.iso "/home/user/radiantwave/${FILENAME}"
echo "COMMERCIAL_ISO_FILENAME=${FILENAME}" >> "$GITHUB_ENV" 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 - name: Copy commercial kiosk ISO to fileserver
run: | run: |
scp "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}" \ scp "/home/user/radiantwave/${COMMERCIAL_ISO_FILENAME}" \
+10 -1
View File
@@ -1,6 +1,11 @@
on: on:
workflow_dispatch: workflow_dispatch:
env:
NIX_CONFIG: |
extra-substituters = https://attic.radiantwavetech.com/radiantwave
extra-trusted-public-keys = radiantwave:QADrjpBWJssTZ3KmiZtcWEf4uAm66oOlHmtQI3jkrgA=
jobs: jobs:
build-kiosk: build-kiosk:
runs-on: build-server runs-on: build-server
@@ -21,10 +26,14 @@ 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-iso-${ISO_DATE}.iso" FILENAME="radiantwave-home-${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 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 - name: Copy kiosk ISO to fileserver
run: | run: |
scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \ scp "/home/user/radiantwave/${KIOSK_ISO_FILENAME}" \
+8
View File
@@ -1,6 +1,11 @@
on: on:
workflow_dispatch: 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: jobs:
build-rpi: build-rpi:
runs-on: build-server runs-on: build-server
@@ -25,6 +30,9 @@ jobs:
cp -L result/sd-image/*.img.zst "/home/user/radiantwave/${FILENAME}" cp -L result/sd-image/*.img.zst "/home/user/radiantwave/${FILENAME}"
echo "RPI_IMAGE_FILENAME=${FILENAME}" >> "$GITHUB_ENV" 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 - name: Copy Raspberry Pi image to fileserver
run: | run: |
scp "/home/user/radiantwave/${RPI_IMAGE_FILENAME}" \ scp "/home/user/radiantwave/${RPI_IMAGE_FILENAME}" \
+67 -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,48 +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-legacy` | | `radiantwavekiosk` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | Dev, uses `radiantwave` `?ref=dev` | | `radiantwavekiosk-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | Production, uses `radiantwave-legacy` | | `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | `radiantwave` (main) |
| `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | Dev, uses `radiantwave` `?ref=dev` | | `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-android` | Intel NUC 14 | `/dev/nvme0n1` | + rotated display (portrait), uses `radiantwave-legacy` | | `radiantwavekiosk-android` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-rpi` | Raspberry Pi 5 | — | Uses `nixos-raspberrypi`, uses `radiantwave-legacy` | | `radiantwavekiosk-android-dev` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-rpi-dev` | Raspberry Pi 5 | — | Dev, uses `radiantwave` `?ref=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-legacy` vs `radiantwave` `?ref=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):
| 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 |
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) ## CI (Gitea)
`.gitea/workflows/build-dev.yml` — triggered by `workflow_dispatch`. Updates `radiantwave` input (dev branch), builds dev closure + ISO, commits updated `flake.lock`. Runs on `build-server`. `.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`, `android-iso.nix` hardcodes `radiantwavekiosk-android`. 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
- `android-iso.nix` — android 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
-133
View File
@@ -1,133 +0,0 @@
{
pkgs,
inputs,
self,
...
}:
let
targetSystem =
self.nixosConfigurations.radiantwavekiosk-android.config.system.build.toplevel;
diskoScript =
self.nixosConfigurations.radiantwavekiosk-android.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
'';
};
}
-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
''; };
}
+24 -6
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/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";
############################################################ ############################################################
-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 -83
View File
@@ -87,24 +87,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixos-facter-modules": { "nixos-facter-modules": {
"locked": { "locked": {
"lastModified": 1773858690, "lastModified": 1773858690,
@@ -232,40 +214,24 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_5": {
"locked": {
"lastModified": 1776877367,
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"radiantwave": { "radiantwave": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs_3" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1786986028, "lastModified": 1787522765,
"narHash": "sha256-DW8q8higedCMLlfcAwhEQyP57ZRTok7cG1N8g5P+1ms=", "narHash": "sha256-D3KOrGcAH07lvKYgyiwejOQpDW91js7zI6l87WdabLk=",
"ref": "main", "ref": "main",
"rev": "359ae905d7086322bf8e394c9731a738f7fc79f3", "rev": "63265cc22f3055a782a0114e92c57a36bef723b2",
"revCount": 29, "revCount": 40,
"type": "git", "type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}, },
"original": { "original": {
"ref": "main", "ref": "main",
"type": "git", "type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
} }
}, },
"radiantwave-dev": { "radiantwave-dev": {
@@ -274,38 +240,18 @@
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1786826629, "lastModified": 1787522765,
"narHash": "sha256-DW8q8higedCMLlfcAwhEQyP57ZRTok7cG1N8g5P+1ms=", "narHash": "sha256-D3KOrGcAH07lvKYgyiwejOQpDW91js7zI6l87WdabLk=",
"ref": "dev", "ref": "dev",
"rev": "e401bd4ec59d1ef4f2e8b117b5933293615a19f6", "rev": "63265cc22f3055a782a0114e92c57a36bef723b2",
"revCount": 27, "revCount": 40,
"type": "git", "type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}, },
"original": { "original": {
"ref": "dev", "ref": "dev",
"type": "git", "type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git" "url": "https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git"
}
},
"radiantwave-legacy": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_5"
},
"locked": {
"lastModified": 1786170011,
"narHash": "sha256-Vx/3kwIQFRYDZQtVdcdGgJPnNa2Y44HRYZyJAeug6OI=",
"ref": "main",
"rev": "312f5e2a90e03f32ce61d6db54f46b9adac60933",
"revCount": 250,
"type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave-legacy.git"
},
"original": {
"ref": "main",
"type": "git",
"url": "ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave-legacy.git"
} }
}, },
"root": { "root": {
@@ -315,8 +261,7 @@
"nixos-raspberrypi": "nixos-raspberrypi", "nixos-raspberrypi": "nixos-raspberrypi",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"radiantwave": "radiantwave", "radiantwave": "radiantwave",
"radiantwave-dev": "radiantwave-dev", "radiantwave-dev": "radiantwave-dev"
"radiantwave-legacy": "radiantwave-legacy"
} }
}, },
"systems": { "systems": {
@@ -348,21 +293,6 @@
"repo": "default", "repo": "default",
"type": "github" "type": "github"
} }
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",
+121 -115
View File
@@ -4,10 +4,8 @@
disko.url = "github:nix-community/disko"; disko.url = "github:nix-community/disko";
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"; # This is the NEW RadiantWave radiantwave.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=main";
radiantwave.url = "git+ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git?ref=main"; radiantwave-dev.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=dev";
radiantwave-dev.url = "git+ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave.git?ref=dev";
radiantwave-legacy.url = "git+ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/radiantwave-legacy.git?ref=main";
nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main"; nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
}; };
@@ -19,7 +17,6 @@
nixos-facter-modules, nixos-facter-modules,
radiantwave, radiantwave,
radiantwave-dev, radiantwave-dev,
radiantwave-legacy,
nixos-raspberrypi, nixos-raspberrypi,
... ...
}@inputs: }@inputs:
@@ -45,8 +42,8 @@
rsvg-convert \ rsvg-convert \
--keep-aspect-ratio \ --keep-aspect-ratio \
--background-color=#111318 \ --background-color=#111318 \
--width=1920 \ --width=1280 \
--height=1080 \ --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} \
@@ -56,7 +53,16 @@
''; '';
}; };
mkKioskSystem = { system, radiantwave, upgradeFlakeRef, extraModules ? [], diskModule, 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;
@@ -64,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 ? [] }: mkRpiKioskSystem = {
radiantwave,
upgradeFlakeRef,
hostName,
extraModules ? [],
}:
nixos-raspberrypi.lib.nixosSystem { nixos-raspberrypi.lib.nixosSystem {
specialArgs = { specialArgs = {
inherit radiantwave upgradeFlakeRef; inherit radiantwave upgradeFlakeRef;
@@ -97,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";
@@ -110,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-legacy; 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-legacy; 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-dev; 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-dev"; 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-legacy; 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-legacy; 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
./android-iso.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;
})
];
}; };
}; };
}; };
+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."
+20 -33
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
''; '';
}; };
} }