- nixos/vm.nix: enable PasswordAuthentication for kiosk user (SSH test access) - scripts/test-vm.sh: one-command build → start → diagnose workflow - macOS: builds and runs on remote Linux server, SSH through server - Linux: builds and runs locally - Commands: --build, --start, --stop, --diagnose, --shell - Diagnostics: NetworkManager, PipeWire, wpctl, ALSA, pactl, processes, logs - AGENTS.md: compact agent guide for the repo
142 lines
5.8 KiB
Nix
142 lines
5.8 KiB
Nix
# NixOS test VM for RadiantWave — mirrors production kiosk setup.
|
|
#
|
|
# Build & run:
|
|
# nixos-rebuild build-vm --flake .#test-vm
|
|
# ./result/bin/run-test-vm-vm
|
|
#
|
|
# This replicates the production kiosk config from KioskConfig:
|
|
# - cage as Wayland compositor (fullscreen kiosk)
|
|
# - PipeWire audio (with a virtual sink for device-switch testing)
|
|
# - NetworkManager
|
|
# - Auto-login as kiosk user
|
|
# - RadiantWave started via loginShellInit (same as production)
|
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
rhemaApp = config.services.rhemawave.package;
|
|
in
|
|
{
|
|
# ── Hostname ──────────────────────────────────────────────────────────────
|
|
networking.hostName = "radiantwave-test";
|
|
|
|
# ── RadiantWave module ────────────────────────────────────────────────────
|
|
services.rhemawave.enable = true;
|
|
|
|
# ── Boot ──────────────────────────────────────────────────────────────────
|
|
boot.loader.systemd-boot.enable = lib.mkForce false;
|
|
boot.loader.efi.canTouchEfiVariables = lib.mkForce false;
|
|
|
|
# ── Packages (matches production) ─────────────────────────────────────────
|
|
environment.systemPackages = [
|
|
pkgs.cage pkgs.rsync pkgs.dbus pkgs.mesa pkgs.git pkgs.tailscale pkgs.sqlite
|
|
];
|
|
|
|
# ── Audio (PipeWire + virtual sink for device-switch testing) ─────────────
|
|
services.pipewire = {
|
|
enable = true;
|
|
alsa.enable = true;
|
|
pulse.enable = true;
|
|
extraConfig.pipewire."30-virtual-sink" = {
|
|
"context.modules" = [
|
|
{
|
|
name = "libpipewire-module-loopback";
|
|
args = {
|
|
"node.name" = "virtual-speaker";
|
|
"node.description" = "Virtual Speaker";
|
|
"audio.position" = [ "FL" "FR" ];
|
|
};
|
|
}
|
|
];
|
|
};
|
|
};
|
|
|
|
# ── Seat (matches production) ─────────────────────────────────────────────
|
|
services.seatd.enable = true;
|
|
hardware.graphics.enable = true;
|
|
|
|
# ── Networking ────────────────────────────────────────────────────────────
|
|
services.resolved.enable = false;
|
|
networking.networkmanager.enable = true;
|
|
systemd.services.NetworkManager-wait-online.enable = false;
|
|
systemd.network.wait-online.enable = false;
|
|
|
|
# ── SSH ───────────────────────────────────────────────────────────────────
|
|
services.openssh = {
|
|
enable = true;
|
|
settings = {
|
|
PermitRootLogin = "prohibit-password";
|
|
PasswordAuthentication = true;
|
|
};
|
|
};
|
|
|
|
# ── User (matches production) ─────────────────────────────────────────────
|
|
users.users.kiosk = {
|
|
isNormalUser = true;
|
|
uid = 1000;
|
|
extraGroups = [ "audio" "video" "input" "networkmanager" "wheel" ];
|
|
password = "kiosk";
|
|
};
|
|
services.getty.autologinUser = "kiosk";
|
|
|
|
# ── Data directory ────────────────────────────────────────────────────────
|
|
systemd.tmpfiles.rules = [
|
|
"d /home/kiosk/.local/share/rhemawave 0770 kiosk kiosk -"
|
|
];
|
|
|
|
# ── RadiantWave service (via loginShellInit, same as production) ──────────
|
|
environment.loginShellInit = ''
|
|
if [ "$(tty)" = "/dev/tty1" ]; then
|
|
export GODEBUG=netdns=cgo
|
|
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
|
|
|
# Smart Network Wait
|
|
for i in {1..10}; do
|
|
if ${pkgs.iputils}/bin/ping -c 1 8.8.8.8 &> /dev/null; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# Graphics fixes (matches production)
|
|
export SDL_VIDEODRIVER=wayland
|
|
export QT_QPA_PLATFORM=wayland
|
|
export XDG_SESSION_TYPE=wayland
|
|
export WLR_RENDERER=pixman
|
|
export WLR_NO_HARDWARE_CURSORS=1
|
|
|
|
# Asset sync + start app (same as production)
|
|
mkdir -p /home/kiosk/.local/share/rhemawave
|
|
${pkgs.rsync}/bin/rsync -ru ${rhemaApp}/share/rhemawave/ /home/kiosk/.local/share/rhemawave/
|
|
|
|
cage -- ${rhemaApp}/bin/rhemawave -d -s > /tmp/kiosk.log 2>&1
|
|
fi
|
|
'';
|
|
|
|
# ── VM settings ───────────────────────────────────────────────────────────
|
|
virtualisation = {
|
|
memorySize = 4096;
|
|
cores = 4;
|
|
graphics = true;
|
|
forwardPorts = [
|
|
{ from = "host"; host.port = 2222; guest.port = 22; }
|
|
];
|
|
qemu.options = [
|
|
"-device intel-hda"
|
|
"-device hda-duplex"
|
|
"-vga virtio"
|
|
];
|
|
};
|
|
|
|
services.logrotate.enable = false;
|
|
|
|
# ── Nix settings ──────────────────────────────────────────────────────────
|
|
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
|
nix.settings.accept-flake-config = true;
|
|
|
|
# ── Firewall (open for local dev) ─────────────────────────────────────────
|
|
networking.firewall.enable = false;
|
|
|
|
system.stateVersion = "24.11";
|
|
}
|