- Replace environment.etc raw script with pkgs.writeShellApplication
- Declare runtimeInputs: pkgs.coreutils, pkgs.gawk, pkgs.gnugrep
- Use awk -v for safe marker variable passing (no shell interpolation)
- Point systemd ExecStart and activation script at lib.getExe hostsUpdateScript
- Keep /etc/sovran-hosts-update.sh as a source symlink for operator discoverability
- Remove environment.systemPackages reliance
- Emit warning (not silently swallow) on activation failure
- Add structural regression tests (19 new tests, all passing)
- Use set -eu (not set -euf) in sovran-hosts-update.sh
- Add sync note for domain validation regex between shell and Python
- Rename `seen` to `unique_addresses` in _resolve_all_addresses
- Improve loopback override UI message with external DNS check guidance
- Add docstring note about first-address display in _resolve_all_addresses"
- Add modules/core/local-domain-loopback.nix: systemd service and
activation script that write configured service domains to a
Sovran-managed block in /etc/hosts (127.0.0.1 / ::1) so requests
originating on this computer reach Caddy without NAT loopback.
- Import local-domain-loopback.nix in modules/modules.nix.
- server.py: add _validate_domain_value, _is_loopback_address,
_resolve_all_addresses, _trigger_hosts_update helpers.
- server.py: update _check_domain_reachable to use --resolve so
reachability is checked locally via Caddy, not via NAT loopback.
- server.py: update _evaluate_domain_checklist, api_services inline DNS
check, and api_domains_check to recognise loopback resolution as an
intentional local override rather than a DNS mismatch.
- server.py: call _trigger_hosts_update from api_domains_set after
saving a service domain so the /etc/hosts entry is applied immediately.
- Add app/tests/test_loopback_diagnostics.py with 47 tests covering
domain validation, loopback detection, diagnostic checklist logic,
composite health, and api_domains_check."
GRD 50.x invokes pkexec internally for every grdctl --system call, even
when the caller is root. An isolated systemd script PATH does not include
/run/wrappers/bin automatically, causing exit 70 at boot.
Changes:
- Prepend /run/wrappers/bin to PATH at script start so every subsequent
grdctl --system resolves the NixOS setuid pkexec wrapper.
- Add an explicit preflight check (test -x /run/wrappers/bin/pkexec) with
a clear error message before the first grdctl_system call.
- pkgs.polkit remains absent from the service path.
- Update test_setup_runs_grdctl_directly_as_root to reflect that pkexec
now appears in the preflight check (not as a direct invocation).
- Add test_run_wrappers_bin_prepended_to_path and test_pkexec_preflight_check.
Root cause: gnome-remote-desktop-setup.service ran as root but dropped
privileges via `runuser -u gnome-remote-desktop`. Non-root grdctl --system
attempts authorisation through pkexec. The Nix-store pkexec binary is not
setuid, so every system-mode credential call silently failed while the script
still printed "configured successfully". GNOME Remote Desktop then started
without applied credentials, causing Remmina to loop at the login dialog.
Fix:
- Remove `runuser -u gnome-remote-desktop --` from grdctl_system helper;
the root-run oneshot service can call grdctl --system directly.
- Remove pkgs.polkit and pkgs.util-linux from the setup service path as
neither polkit nor runuser is needed any more.
- Update tests: rename test_setup_runs_grdctl_as_gnome_remote_desktop_user
to test_setup_runs_grdctl_directly_as_root and assert that runuser,
pkexec, and sudo are absent; add
test_privilege_escalation_packages_absent_from_setup_path.
All 21 app/tests pass.
1. Add nix-bitcoin.generateSecrets = lib.mkDefault true global compat
default in role-logic.nix so Desktop Only systems can evaluate while
nix-bitcoin is still globally imported by the flake.
2. Harden Desktop Only role: change all server/node service and feature
disables from lib.mkDefault false to lib.mkForce false so they cannot
be overridden by custom.nix or option defaults.
- sovran_systemsOS.services: synapse, bitcoin, vaultwarden, wordpress, nextcloud
- sovran_systemsOS.features: haven, mempool, element-calling, bitcoin-core
- sovran_systemsOS.web.btcpayserver
3. Make Caddy conditional in caddy.nix:
enable = needsHttpsPorts || extraVhosts != ""
so Caddy does not run on Desktop Only installs with no web services.