diff --git a/.agents/skills/nix-config-desktop/SKILL.md b/.agents/skills/nix-config-desktop/SKILL.md index fcdfaf60..b23f9727 100644 --- a/.agents/skills/nix-config-desktop/SKILL.md +++ b/.agents/skills/nix-config-desktop/SKILL.md @@ -36,20 +36,20 @@ back with git, and needs no rebuild. Only the store layer needs one. ## 1. Pick the layer -| Change | Where it lives | Applies | -| --------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------ | -| Niri compositor (binds, layout, window rules) | `home/linux/gui/niri/conf/*.kdl` | live | -| Niri per-host outputs | `hosts//niri-hardware.kdl` | live | -| Noctalia shared baseline | `home/linux/gui/base/noctalia/config/config.toml` | live | -| Noctalia per-host override | `home/hosts/linux//noctalia.toml` (`host-.toml`) | store: needs `just niri` | -| Noctalia value saved by the Settings UI | `~/.local/state/noctalia/settings.toml` (not in the repo) | live, wins over the rest | -| Mozc dictionary | `home/linux/gui/base/fcitx5/mozc-config1.db` | live | -| fcitx5 profile and addons | `home/linux/gui/base/fcitx5/` | store: needs `just niri` | -| vinput (voice input) | `home/linux/gui/base/vinput/` (tag-pinned: the `fcitx5-vinput` row in WORKAROUNDS.md §Pins) | store: needs `just niri` | -| Interface a net-speed widget reads | `home/hosts/linux//noctalia.toml` (`[widget.net_rx]`/`[widget.net_tx]` `interface`) | store: needs `just niri` | -| `$HOME` state that must survive | `hosts//preservation.nix` (tmpfs root) | store: needs `just niri` | -| Theme (catppuccin), fonts | `home/base/core/theme.nix`, `modules/nixos/desktop/fonts.nix` | store: needs `just niri` | -| Session, portal, and systemd wiring | `modules/nixos/desktop/**`, `home/linux/gui/base/xdg/` | store: needs `just niri` | +| Change | Where it lives | Applies | +| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------ | +| Niri compositor (binds, layout, window rules) | `home/linux/gui/niri/conf/*.kdl` | live | +| Niri per-host outputs | `hosts//niri-hardware.kdl` | live | +| Noctalia shared baseline | `home/linux/gui/base/noctalia/config/config.toml` | live | +| Noctalia per-host override | `home/hosts/linux//noctalia.toml` (`host-.toml`) | store: needs `just niri` | +| Noctalia value saved by the Settings UI | `~/.local/state/noctalia/settings.toml` (not in the repo) | live, wins over the rest | +| Mozc dictionary | `home/linux/gui/base/fcitx5/mozc-config1.db` | live | +| fcitx5 profile and addons | `home/linux/gui/base/fcitx5/` | store: needs `just niri` | +| vinput (voice input) | `home/linux/gui/base/vinput/` (tag-pinned: the `fcitx5-vinput` row in WORKAROUNDS.md §Pins) | store: needs `just niri` | +| Interface a net-speed widget reads | `home/hosts/linux//noctalia.toml` (`[widget.net_rx]`/`[widget.net_tx]` `interface`) | store: needs `just niri` | +| `$HOME` state that must survive | `hosts//preservation.nix` (tmpfs root; `12kingdoms-shoukei` imports `hosts/idols-ai/preservation.nix`) | store: needs `just niri` | +| Theme (catppuccin), fonts | `home/base/core/theme.nix`, `modules/nixos/desktop/fonts.nix` | store: needs `just niri` | +| Session, portal, and systemd wiring | `modules/nixos/desktop/**`, `home/linux/gui/base/xdg/` | store: needs `just niri` | Noctalia's merge order and `[include]` are in [home/linux/gui/base/README.md](../../../home/linux/gui/base/README.md). A per-host difference goes diff --git a/SECURITY.md b/SECURITY.md index f43956d5..f3c10fa3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -200,8 +200,8 @@ checks remain necessary after deployment. `root_squash` is deferred: the existing PVC subdirectories are root-owned (observed `drwxr-xr-x root root` and `drwxrwsr-x root 107`), so enabling it needs a one-time ownership migration and a maintenance window. See WORKAROUNDS.md. -- **Remote consoles:** the libvirt VNC consoles listen on `127.0.0.1` only, and the shared firewall - drops 5900-5910 on every host. Reach a console through an SSH tunnel. +- **Remote consoles:** the libvirt VNC consoles listen on `127.0.0.1` only, and the k3s firewall + drops 5900-5903 from pod sources. Reach a console through an SSH tunnel. - **Pod-to-host firewall:** two independent layers deny pod access to the credential-bearing host ports (SSH, NFS, Postgres, restic, VNC, Immich, exporter/monitoring). The `deny-pod-to-node-admin-ports` `CiliumClusterwideNetworkPolicy` in diff --git a/WORKAROUNDS.md b/WORKAROUNDS.md index 1096893f..f57160b6 100644 --- a/WORKAROUNDS.md +++ b/WORKAROUNDS.md @@ -44,6 +44,7 @@ A setting that works around a bug or a hardware quirk. | WA-019 | programs.steam.extraCompatPackages = [ pkgs.dwproton-bin pkgs.proton-ge-bin ] — modules/nixos/desktop/gaming.nix | ACE games fail on GE/mainline Proton, work with DW-Proton | Drop once mainline or GE-Proton runs these games (GE-Proton#433) | 2026-10-07 | on Proton/GE bump | active | | WA-024 | Wi-Fi power saving disabled (`networking.networkmanager.wifi.powersave = false`) — `hosts/12kingdoms-shoukei/apple-silicon.nix` | On this BCM4378/brcmfmac laptop, powersave is a common source of intermittent ASSOC-REJECT / authentication-timeout failures; NetworkManager then mistakes the failure for a bad key, re-prompts, and the client (Noctalia, nmtui, nmcli) saves the answer as a duplicate ` 1` profile | Drop once the kernel carries the brcmfmac `port_authorized` fix (WA-025) and no association failures remain | 2026-10-07 | watch `journalctl -u wpa_supplicant` for ASSOC-REJECT / authentication timeout | active | | WA-026 | guest deploys run `installOnHost` then `systemctl restart microvm@` on the physical host — `Justfile`, `lib/genMicrovmGuestModule.nix` | the sshSwitch step runs `nix-store --load-db` against the guest's read-only virtiofs `/nix/store` and dies on `cannot remount "/nix/store" writable` (nix 2.35) | Drop the manual path once microvm.nix or nix handles a read-only store switch. A host activation re-links `/var/lib/microvms//current` to the runner baked into the host's system, so switch the host after installing a guest from a newer tree | 2026-10-09 | on microvm.nix or nix bump | active | +| WA-028 | GitHub SSH pinned to IPv4 (`AddressFamily = "inet"`) — `home/base/tui/ssh.nix` | a v6 fake AAAA for `ssh.github.com` from the `2001:2::/64` pool (WA-029) is not proven on the 443 SSH tunnel yet | Drop once the v6 fake-ip pool is proven for GitHub SSH | 2026-10-10 | on a mihomo bump or a v6 pool change | active | | WA-029 | mihomo `fake-ip-range6` is `2001:2::/64`, not the shipped ULA default — `modules/nixos/desktop/networking/mihomo/generate.nu` | the default `fdfe:dcba:9876::/64` sits in `fc00::/7`, which Local Network Access calls local, so a public page loaded over the v4 fake pool and pulling a dual-stack subresource prompts for local-network access (Chrome 154, Firefox). The same range also stalled ssh: a session to a fake AAAA authenticated and then never closed, on both `gvisor` and `mips`. `2001:2::/48` is RFC 5180 benchmarking -- the v6 twin of the `198.18.0.0/15` v4 default, absent from that table -- and both symptoms went with the move | Go back to the upstream default once mihomo ships a pool outside the LNA non-public table; the ULA default brings the ssh stall back | 2026-10-09 | on a browser or mihomo bump -- that table already grew to cover `2001:db8::/32` and `198.18.0.0/15` | active | If WA-008 freezes recur, the fallback is to restore @@ -72,7 +73,7 @@ An unfinished feature or gap. | ID | What & where | Why | Removal condition | Added | Revisit | Status | | ------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------- | ----------------------- | ------ | | WA-013 | NixOS tests — `outputs/README.md` | full-host tests still rebuild custom packages (no private cache) and need the host ssh key to decrypt agenix; the shared-firewall security-exporters VM test now runs in CI (KVM) | Resolve when a private cache exists and tests can run per-service | 2024-03-13 | quarterly | active | -| WA-020 | NFS golden store `no_root_squash` — `hosts/12kingdoms-youko/nfs-golden.nix` | the existing PVC subdirectories are root-owned, so enabling `root_squash` would break running workloads until they are migrated; the CSI node plugin is hostNetwork and sources from the allowlisted node IPs | Drop when the PVC subdirectories are migrated and `root_squash` is enabled | 2026-10-07 | next maintenance window | active | +| WA-027 | NFS golden store `no_root_squash` — `hosts/12kingdoms-youko/nfs-golden.nix` | the existing PVC subdirectories are root-owned, so enabling `root_squash` would break running workloads until they are migrated; the CSI node plugin is hostNetwork and sources from the allowlisted node IPs | Drop when the PVC subdirectories are migrated and `root_squash` is enabled | 2026-10-07 | next maintenance window | active | ## Related diff --git a/docs/nixos-modernization-options.md b/docs/nixos-modernization-options.md index ce9fdf44..85a99eb5 100644 --- a/docs/nixos-modernization-options.md +++ b/docs/nixos-modernization-options.md @@ -1,8 +1,8 @@ # NixOS Modernization — Options and Decision Record > **Purpose:** let the maintainer decide, per candidate, whether it is worth adopting — by comparing -> it against what this repository does **today**. The plan documents under `docs/plans/` are -> downstream of this file: a plan item is only approved work once its card here says **adopt**. +> it against what this repository does **today**. A plan derived from this file is only approved +> work once its card here says **adopt**. > > Researched against nixpkgs `nixos-unstable` on 2026-10-07. Option names and upstream wording are > quoted from the module sources cited in each card. diff --git a/home/linux/gui/i3/README.md b/home/linux/gui/i3/README.md index 4a377e78..be27b9dd 100644 --- a/home/linux/gui/i3/README.md +++ b/home/linux/gui/i3/README.md @@ -41,7 +41,7 @@ tree the agent reads, so it stays. services: `xvfb` → `i3` → (`x11vnc`, `autocutsel-primary` / `autocutsel-clipboard`, `cua-driver serve`). - `modules/nixos/desktop/computer-use.nix` provides the system side (`linger`, AT-SPI, fonts, Mesa, - Clash Verge proxy, proxy-region timezone). + and a `proxyRegion` option that pins the timezone to the proxy's exit region). - the generated `computer-use-init` script (exec'd by i3) publishes `DISPLAY`/`XDG_SESSION_TYPE` to the systemd user manager, clears any stale `WAYLAND_DISPLAY`, and enables the AT-SPI bridge via a gsettings key. diff --git a/hosts/idols-ruby/README.md b/hosts/idols-ruby/README.md index 89449ccd..5e7666ac 100644 --- a/hosts/idols-ruby/README.md +++ b/hosts/idols-ruby/README.md @@ -2,7 +2,7 @@ NixOS VM running under libvirt on `shoryu`, used to run AI agents. It owns the shared agent and computer-use modules (`packages.nix`, `computer-use.nix`, `oci-containers/`) that -[`idols-kana`](../idols-kana/) imports, and is the only host with a `*-nixos-tests` output. +[`idols-kana`](../idols-kana/) imports. - Deploy from the VM with `just local`. - Host inventory and role context: [`../README.md`](../README.md). diff --git a/modules/nixos/desktop/networking/mihomo/README.md b/modules/nixos/desktop/networking/mihomo/README.md index 61b19689..89094431 100644 --- a/modules/nixos/desktop/networking/mihomo/README.md +++ b/modules/nixos/desktop/networking/mihomo/README.md @@ -12,9 +12,11 @@ just mihomo-gen # -> ~/.config/mihomo/config.yam sudo systemctl restart mihomo.service # dashboard: http://127.0.0.1:9090/ui ``` -`~/.config/mihomo` holds only `sources.yaml` and the generated `config.yaml` (plus geodata and the -cache); the generator, `policy.yaml` and `gateway-config.nu` are run from here and never copied -over. `just mihomo-gen` renders the config and validates it with the core the service runs. +`~/.config/mihomo` holds `sources.yaml` and the generated `config.yaml`, which the service loads +through systemd `LoadCredential`; the core's own state — geodata and cache — is in +`/var/lib/private/mihomo` (`StateDirectory`, `DynamicUser`). The generator, `policy.yaml` and +`gateway-config.nu` are run from here and never copied over. `just mihomo-gen` renders the config +and validates it with the core the service runs. `sources.yaml` holds everything private (subscription URLs, secret, private domains) and stays out of the repo and the Nix store; the module loads `config.yaml` via `LoadCredential`. Generate the diff --git a/outputs/README.md b/outputs/README.md index bbb828fa..5a399154 100644 --- a/outputs/README.md +++ b/outputs/README.md @@ -46,10 +46,10 @@ suite passes when every `expr` equals its `expected`. Some tests iterate over every configuration, so a new host is covered automatically and must satisfy them. Others name specific hosts and only cover a new host if you add it. -| Kind | Tests | -| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Every configuration | `hostname`, `kernel`, `nix-system-features`, `security-apparmor`, `security-container-groups`, `security-exporters`, `security-firewall`, `security-k3s-kubeconfig`, `security-kernel`, `security-ssh-x11` | -| Named hosts only | `btrbk`, `home-manager`, `home-manager-xdg`, `computer-use-headless`, `k3s-api-endpoint`, `k3s-master-home-manager`, `idols-ai-gpu`, `youko-metrics`, `ups-metrics`, `shoukei-logind` | +| Kind | Tests | +| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Every configuration | `hostname`, `kernel`, `nix-system-features`, `security-apparmor`, `security-container-groups`, `security-exporters`, `security-firewall`, `security-k3s-kubeconfig`, `security-k3s-pod-firewall`, `security-kernel`, `security-ssh-x11` | +| Named hosts only | `btrbk`, `home-manager`, `home-manager-xdg`, `computer-use-headless`, `k3s-api-endpoint`, `k3s-master-home-manager`, `idols-ai-gpu`, `idols-ai-voice-input`, `security-postgres-auth`, `youko-metrics`, `ups-metrics`, `shoukei-logind` | `hostname` expects each configuration's `networking.hostName` to equal its name. Niri desktop configurations are the exception (`ai-niri` → `ai`, `shoukei-niri` → `shoukei`) and are listed in @@ -71,15 +71,8 @@ Problems: agenix secrets. - [ ] Maybe it's better to test every service separately, not the whole host? -How to run a host's NixOS tests: - -```bash -# Format: nix build .#-nixos-tests - -nix build .#ruby-nixos-tests -``` - -Only `ruby` currently defines a `*-nixos-tests` output. +No host defines a NixOS integration test yet: full-host tests are tracked as WA-013 in +[WORKAROUNDS.md](../WORKAROUNDS.md). What runs today is the eval set above, with `just test`. ## Overview