From b7f523c3a1c7c04a906d2ed53e1a864a392b6075 Mon Sep 17 00:00:00 2001 From: Rod Boev Date: Sat, 4 Jul 2026 16:41:44 -0400 Subject: [PATCH] fix(#2422): tighten Nix module polish --- README.md | 2 +- flake.nix | 3 ++- nix/nixosModules.nix | 3 --- nix/packages.nix | 3 ++- tests/test_nix_flake_module_source.py | 11 +++++++++++ 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cd092d34..ddfb33d9 100644 --- a/README.md +++ b/README.md @@ -429,7 +429,7 @@ services.hermes-webui = { The module defaults to `127.0.0.1`. Set `host = "0.0.0.0"` and `openFirewall = true` only when you want direct network access, and pair that with auth, for example `HERMES_WEBUI_PASSWORD` via `environmentFiles`. -You can also set `agent.package` instead of `agent.dir` when you are using a compatible Hermes Agent package layout. When the package exposes `passthru.hermesAgentDir`, the module derives `HERMES_WEBUI_AGENT_DIR` from that path. When it exposes `passthru.hermesVenv`, the module derives `HERMES_WEBUI_PYTHON` from the venv interpreter so bootstrap can use agent dependencies without creating a local `.venv`. If the package does not expose either metadata path, set `agent.dir` and `agent.python` explicitly. +You can also set `agent.package` instead of `agent.dir` when you are using a compatible Hermes Agent package layout. This path depends on package metadata that the current published Hermes Agent flake may not expose yet, so explicit `agent.dir` and `agent.python` are the reliable integration options for existing agent packages. When the package exposes `passthru.hermesAgentDir`, the module derives `HERMES_WEBUI_AGENT_DIR` from that path. When it exposes `passthru.hermesVenv`, the module derives `HERMES_WEBUI_PYTHON` from the venv interpreter so bootstrap can use agent dependencies without creating a local `.venv`. When WebUI reads shared Hermes Agent state, run the service as a user that can already read that state. For a co-located Hermes Agent service, set `user` and `group` to the agent service account; the module only creates the default `hermes-webui` account and never changes ownership of an existing `hermesHome`. diff --git a/flake.nix b/flake.nix index 1a60a20a..475fda1a 100644 --- a/flake.nix +++ b/flake.nix @@ -16,11 +16,12 @@ linuxSystems = [ "x86_64-linux" "aarch64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs supportedSystems; hermesModule = import ./nix/nixosModules.nix { inherit self; }; + packageVersion = self.shortRev or (self.dirtyShortRev or "unstable"); perSystem = forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; package = import ./nix/packages.nix { inherit pkgs; - version = "0.51.0"; + version = packageVersion; }; moduleChecks = if builtins.elem system linuxSystems then let diff --git a/nix/nixosModules.nix b/nix/nixosModules.nix index f6443b87..c49def76 100644 --- a/nix/nixosModules.nix +++ b/nix/nixosModules.nix @@ -85,7 +85,6 @@ let cfg.extraEnvironment)); needsWritableStateDir = cfg.stateDir != defaultStateDir; - writableServiceDirs = lib.optionals needsWritableStateDir [ cfg.stateDir ]; tmpfilesRules = lib.optionals needsWritableStateDir [ "d ${cfg.stateDir} 0700 ${cfg.user} ${cfg.group} - -" ]; @@ -194,7 +193,6 @@ in Restart = "on-failure"; Environment = mappedEnvironment; EnvironmentFile = map builtins.toString cfg.environmentFiles; - ReadWritePaths = map builtins.toString writableServiceDirs; StateDirectoryMode = "0700"; UMask = "0077"; } @@ -213,7 +211,6 @@ in ${cfg.user} = { isSystemUser = true; group = cfg.group; - createHome = true; home = cfg.stateDir; }; }; diff --git a/nix/packages.nix b/nix/packages.nix index ee7e5619..ecfe2fa7 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -1,4 +1,4 @@ -{ pkgs, version ? "0.51.0" }: +{ pkgs, version ? "unstable" }: let pythonEnv = pkgs.python3.withPackages ( @@ -29,6 +29,7 @@ pkgs.stdenv.mkDerivation { cp "${./../requirements.txt}" "$out/${runtimeDir}/requirements.txt" cp -r "${./../api}" "$out/${runtimeDir}/api" cp -r "${./../static}" "$out/${runtimeDir}/static" + printf "__version__ = '%s'\n" "$version" > "$out/${runtimeDir}/api/_version.py" makeWrapper ${pythonEnv}/bin/python3 "$out/bin/hermes-webui" \ --set HERMES_WEBUI_DISABLE_LOCAL_VENV 1 \ diff --git a/tests/test_nix_flake_module_source.py b/tests/test_nix_flake_module_source.py index 28410082..e9f12bb6 100644 --- a/tests/test_nix_flake_module_source.py +++ b/tests/test_nix_flake_module_source.py @@ -25,6 +25,15 @@ def test_nix_package_disables_store_local_venv_fallback(): assert "--set HERMES_WEBUI_DISABLE_LOCAL_VENV 1" in PACKAGES_NIX +def test_nix_package_version_comes_from_flake_source_revision(): + assert 'version ? "unstable"' in PACKAGES_NIX + assert 'packageVersion = self.shortRev or (self.dirtyShortRev or "unstable");' in FLAKE_NIX + assert "version = packageVersion;" in FLAKE_NIX + assert "0.51.0" not in FLAKE_NIX + assert "0.51.0" not in PACKAGES_NIX + assert 'api/_version.py' in PACKAGES_NIX + + def test_nixos_module_decouples_agent_dir_from_python_inference(): assert "agent.python" in MODULE_NIX assert "configuredAgentPython" in MODULE_NIX @@ -50,6 +59,7 @@ def test_nixos_module_keeps_webui_state_private_by_default_and_custom_path(): assert 'StateDirectoryMode = "0700";' in MODULE_NIX assert 'UMask = "0077";' in MODULE_NIX assert '"d ${cfg.stateDir} 0700 ${cfg.user} ${cfg.group} - -"' in MODULE_NIX + assert "ReadWritePaths" not in MODULE_NIX assert "2770" not in MODULE_NIX @@ -58,6 +68,7 @@ def test_nixos_module_only_creates_default_service_identity(): assert "cfg.user == defaultUser" in MODULE_NIX assert "users.groups.${cfg.group}" not in MODULE_NIX assert "users.users.${cfg.user}" not in MODULE_NIX + assert "createHome = true;" not in MODULE_NIX def test_nixos_module_defaults_to_loopback_with_explicit_firewall_opt_in():