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
This commit is contained in:
NeilClack
2026-08-23 09:58:46 -05:00
parent 64b2a9cfc4
commit 65a6b256f9
8 changed files with 200 additions and 617 deletions
+3 -5
View File
@@ -4,17 +4,15 @@ on:
workflow_dispatch:
jobs:
update-and-build:
build-dev-iso:
runs-on: build-server
steps:
- name: Checkout
run: git clone --depth 1 ssh://git@gitea.radiantwavetech.com:2222/RadiantWaveTech/KioskConfig.git .
- name: Update radiantwave-dev
run: |
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
nix flake update radiantwave-dev
# flake.lock is updated manually (committing an updated lock is the
# release trigger); CI only builds what is checked in.
- name: Prepare output directory
run: mkdir -p /home/user/radiantwave
+67 -27
View File
@@ -2,10 +2,19 @@
## 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`
## 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
```bash
@@ -18,7 +27,7 @@ nix build .#nixosConfigurations.<name>.config.system.build.isoImage
# Deploy to a remote kiosk over SSH
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
# Evaluate available config names
@@ -27,48 +36,79 @@ nix eval .#nixosConfigurations --apply builtins.attrNames
## 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-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | Dev, uses `radiantwave` `?ref=dev` |
| `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | Production, uses `radiantwave-legacy` |
| `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | Dev, uses `radiantwave` `?ref=dev` |
| `radiantwavekiosk-android` | Intel NUC 14 | `/dev/nvme0n1` | + rotated display (portrait), uses `radiantwave-legacy` |
| `radiantwavekiosk-rpi` | Raspberry Pi 5 | — | Uses `nixos-raspberrypi`, uses `radiantwave-legacy` |
| `radiantwavekiosk-rpi-dev` | Raspberry Pi 5 | — | Dev, uses `radiantwave` `?ref=dev` |
| `radiantwavekiosk` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-dev` | Intel NUC 14 (NVMe) | `/dev/nvme0n1` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-commercial` | Commercial HW (SATA) | `/dev/sda` | `radiantwave` (main) |
| `radiantwavekiosk-commercial-dev` | Commercial HW (SATA) | `/dev/sda` | `radiantwave-dev` (dev) |
| `radiantwavekiosk-android` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave` (main) |
| `radiantwavekiosk-android-dev` | Intel NUC 14, rotated display | `/dev/nvme0n1` | `radiantwave-dev` (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)
`.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
- **Disk device differs by variant**: `disk-config.nix` uses `/dev/nvme0n1`, `commercial-disk-config.nix` uses `/dev/sda`. Don't mix them up.
- **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.
- **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.
- **SOPS**: `.sops.yaml` configures age-based encryption for `secrets.yaml`. You'll need the private key matching `age1t2wpzv...` to decrypt.
- **Flake inputs**: `radiantwave` tracks main, `radiantwave-dev` tracks `?ref=dev`. Updating them independently is intentional.
- **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.
- **Changing a config name** requires updating that config's `upgradeFlakeRef` in `flake.nix` (it embeds the name).
- **`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`.
- **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.
- **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
- `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)
- `zero-touch-installer.nix` — parameterized USB installer module used by all six ISOs
- `disk-config.nix` — NVMe disk layout (NUC)
- `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
- `facter.json` — hardware facter report (NUC 14)
- `14rvk.json`, `pn54.json` — additional hardware facter reports
- `assets/` — logo and splash image
- `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
''; };
}
-2
View File
@@ -61,8 +61,6 @@ in
networking.networkmanager.enable = true;
nix.settings.access-tokens = "gitea.radiantwavetech.com=ff524968d31acc5c4da350d0884a87264d0e8881";
system.autoUpgrade = {
enable = true;
flake = upgradeFlakeRef;
-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
'';
};
}
+110 -156
View File
@@ -53,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 {
inherit system;
@@ -61,20 +70,35 @@
inherit radiantwave;
inherit upgradeFlakeRef;
inherit radiantwavePlymouth;
} // extraSpecialArgs;
};
modules = [
{ nixpkgs.config.allowUnfree = true; }
{
networking.hostName = hostName;
system.configurationRevision = revision;
}
./configuration.nix
disko.nixosModules.disko
diskModule
diskModule
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; }
radiantwave.nixosModules.default
] ++ extraModules;
};
mkRpiKioskSystem = { radiantwave, upgradeFlakeRef, extraModules ? [] }:
mkRpiKioskSystem = {
radiantwave,
upgradeFlakeRef,
hostName,
extraModules ? [],
}:
nixos-raspberrypi.lib.nixosSystem {
specialArgs = {
inherit radiantwave upgradeFlakeRef;
@@ -94,6 +118,9 @@
./configuration.nix
radiantwave.nixosModules.default
{
networking.hostName = hostName;
system.configurationRevision = revision;
boot.loader.systemd-boot.enable = nixpkgs.lib.mkForce false;
boot.loader.efi.canTouchEfiVariables = nixpkgs.lib.mkForce false;
boot.loader.raspberry-pi.bootloader = "kernel";
@@ -107,211 +134,138 @@
}
] ++ 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
{
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-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;
# 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 = {
radiantwavekiosk = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
hostName = "radiantwavekiosk";
diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk";
extraModules = [];
};
# Kiosk-dev
radiantwavekiosk-dev = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-dev";
diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-dev";
extraModules = [];
};
# Commercial
radiantwavekiosk-commercial = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
hostName = "radiantwavekiosk-commercial";
diskModule = ./commercial-disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-commercial";
extraModules = [];
};
# Commercial-dev
radiantwavekiosk-commercial-dev = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-commercial-dev";
diskModule = ./commercial-disk-config.nix;
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 {
system = "x86_64-linux";
radiantwave = radiantwave;
hostName = "radiantwavekiosk-android";
diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-android";
extraModules = [./rotated_display.nix ];
extraModules = [./rotated_display.nix];
};
# Kiosk-dev - rotated screen for android displays
radiantwavekiosk-android-dev = mkKioskSystem {
system = "x86_64-linux";
radiantwave = radiantwave;
radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-android-dev";
diskModule = ./disk-config.nix;
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-android";
extraModules = [./rotated_display.nix ];
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-android-dev";
extraModules = [./rotated_display.nix];
};
# Raspberry pi 5
# Raspberry Pi 5.
radiantwavekiosk-rpi = mkRpiKioskSystem {
radiantwave = radiantwave;
hostName = "radiantwavekiosk-rpi";
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git#radiantwavekiosk-rpi";
};
# Raspberry pi 5 dev
radiantwavekiosk-rpi-dev = mkRpiKioskSystem {
radiantwave = radiantwave;
radiantwave = radiantwave-dev;
hostName = "radiantwavekiosk-rpi-dev";
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git?ref=dev#radiantwavekiosk-rpi-dev";
};
# === USB Images ===
# Kiosk ISO
kiosk-iso = 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
./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;
})
];
# Each ISO installs exactly the named system closure using that
# system's disk layout. NVMe layouts pair with ./disk-config.nix,
# SATA with ./commercial-disk-config.nix — don't cross them.
kiosk-iso = mkIso {
targetConfig = "radiantwavekiosk";
diskModule = ./disk-config.nix;
};
# Commercial iso
commercial-iso = 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
./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;
})
];
commercial-iso = mkIso {
targetConfig = "radiantwavekiosk-commercial";
diskModule = ./commercial-disk-config.nix;
};
# kiosk rotated screen ISO
android-iso = 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
./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;
})
];
android-iso = mkIso {
targetConfig = "radiantwavekiosk-android";
diskModule = ./disk-config.nix;
};
# Kiosk iso development branch
dev-iso = 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
./dev-iso.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;
})
];
dev-iso = mkIso {
targetConfig = "radiantwavekiosk-dev";
diskModule = ./disk-config.nix;
};
# Kiosk iso development branch
commercial-dev-iso = 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
./dev-iso.nix
./disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk-commercial-dev
];
environment.etc."disko-config.nix".source = ./commercial-disk-config.nix;
})
];
commercial-dev-iso = mkIso {
targetConfig = "radiantwavekiosk-commercial-dev";
diskModule = ./commercial-disk-config.nix;
};
# Kiosk-dev rotated display iso
android-dev-iso = 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
./dev-iso.nix
./disk-config.nix
({ pkgs, ... }: {
environment.systemPackages = [
disko.packages.${system}.default
];
isoImage.storeContents = [
self.packages.x86_64-linux.radiantwavekiosk-android-dev
];
environment.etc."disko-config.nix".source = ./disk-config.nix;
})
];
android-dev-iso = mkIso {
targetConfig = "radiantwavekiosk-android-dev";
diskModule = ./disk-config.nix;
};
};
};
}
+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,
inputs,
@@ -5,17 +15,15 @@
...
}:
let
targetSystem =
self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel;
cfg = self.nixosConfigurations.${targetConfig};
targetSystem = cfg.config.system.build.toplevel;
diskoScript = cfg.config.system.build.diskoScript;
diskoScript =
self.nixosConfigurations.radiantwavekiosk.config.system.build.diskoScript;
# Keep in sync with myKey in configuration.nix.
adminKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL4qWNZnYU5JaqR9c2qh6oFZktzVNBOx42PfDaGofCL6 cnclack@pm.me macbook";
in
{
############################################################
# System configuration
############################################################
nix.settings = {
experimental-features = [
"nix-command"
@@ -38,32 +46,11 @@ in
};
};
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
############################################################
users.users.root.openssh.authorizedKeys.keys = [ adminKey ];
services.openssh.enable = true;
@@ -115,7 +102,7 @@ in
${diskoScript}
echo "Installing RadiantWave"
echo "Installing RadiantWave (${targetConfig})"
echo "Closure Path: ${targetSystem}"
nixos-install \
@@ -127,7 +114,7 @@ in
echo " Installation complete!"
echo " Please shut down and remove the flash drive before restarting"
echo "============================================"
sleep 10000000
sleep infinity
'';
};
}
}