test+docs(#4449): backward-compat state-dir tests + upgrade migration note (Opus gate)
Opus flagged a real upgrade gap on the #4449 state-dir contract folded into #4454: a deployment that relocated HERMES_HOME to a non-default base WITHOUT setting HERMES_WEBUI_STATE_DIR sees WebUI state move to $HERMES_HOME/webui on upgrade (empty app at the new address). Add (1) README note documenting the move + how to keep the old location, and (2) two backward-compat regression tests pinning the invariants: HERMES_HOME-unset stays at the platform default (normal installs don't relocate), and HERMES_WEBUI_STATE_DIR takes precedence.
This commit is contained in:
1 parent
8b598ac133
commit
4d4b11b43c
2 files changed
+57
-1
No files matched your search
@@ -337,7 +337,7 @@ Full list of environment variables:
|
||||
| `HERMES_WEBUI_PYTHON` | auto-discovered | Python executable |
|
||||
| `HERMES_WEBUI_HOST` | `127.0.0.1` | Bind address (`0.0.0.0` for all IPv4, `::` for all IPv6, `::1` for IPv6 loopback) |
|
||||
| `HERMES_WEBUI_PORT` | `8787` | Port |
|
||||
| `HERMES_WEBUI_STATE_DIR` | `$HERMES_HOME/webui` (Windows default `%LOCALAPPDATA%\hermes\webui`, POSIX default `~/.hermes/webui`) | Where sessions and state are stored |
|
||||
| `HERMES_WEBUI_STATE_DIR` | `$HERMES_HOME/webui` (Windows default `%LOCALAPPDATA%\hermes\webui`, POSIX default `~/.hermes/webui`) | Where sessions and state are stored. **Note (upgrade):** the default now follows `HERMES_HOME` — if you previously relocated `HERMES_HOME` to a non-default base **without** setting `HERMES_WEBUI_STATE_DIR`, your WebUI state now resolves to `$HERMES_HOME/webui` instead of the old platform-default `~/.hermes/webui`. To keep using the old location, set `HERMES_WEBUI_STATE_DIR` to it (or move the directory). Installs with `HERMES_HOME` unset or at the default base are unaffected. |
|
||||
| `HERMES_WEBUI_DEFAULT_WORKSPACE` | `~/workspace` | Default workspace |
|
||||
| `HERMES_WEBUI_DEFAULT_MODEL` | *(provider default)* | Optional model override; leave unset to use the active Hermes provider default |
|
||||
| `HERMES_WEBUI_PASSWORD` | *(unset)* | Set to enable password authentication |
|
||||
|
||||
@@ -31,3 +31,59 @@ def test_config_state_dir_defaults_to_hermes_home_webui(tmp_path):
|
||||
else:
|
||||
os.environ["HERMES_WEBUI_STATE_DIR"] = old_state_dir
|
||||
importlib.reload(config)
|
||||
|
||||
|
||||
def test_config_state_dir_unchanged_for_normal_install_hermes_home_unset(tmp_path):
|
||||
"""Backward-compat: with HERMES_HOME unset, STATE_DIR stays at the platform
|
||||
default `<~/.hermes>/webui` — a normal install's state must NOT relocate
|
||||
(the #4449/#4454 state-dir move only affects an explicitly-set HERMES_HOME)."""
|
||||
old_home = os.environ.get("HERMES_HOME")
|
||||
old_state_dir = os.environ.get("HERMES_WEBUI_STATE_DIR")
|
||||
try:
|
||||
os.environ.pop("HERMES_HOME", None)
|
||||
os.environ.pop("HERMES_WEBUI_STATE_DIR", None)
|
||||
|
||||
reloaded = importlib.reload(config)
|
||||
|
||||
# _platform_default_hermes_home() drives the default; STATE_DIR must be
|
||||
# that base + /webui, exactly as on master before the #4449 change.
|
||||
expected = (reloaded._platform_default_hermes_home() / "webui").resolve()
|
||||
assert reloaded.STATE_DIR == expected
|
||||
finally:
|
||||
if old_home is None:
|
||||
os.environ.pop("HERMES_HOME", None)
|
||||
else:
|
||||
os.environ["HERMES_HOME"] = old_home
|
||||
if old_state_dir is None:
|
||||
os.environ.pop("HERMES_WEBUI_STATE_DIR", None)
|
||||
else:
|
||||
os.environ["HERMES_WEBUI_STATE_DIR"] = old_state_dir
|
||||
importlib.reload(config)
|
||||
|
||||
|
||||
def test_config_state_dir_explicit_override_takes_precedence(tmp_path):
|
||||
"""HERMES_WEBUI_STATE_DIR always wins over the HERMES_HOME-derived default,
|
||||
so an operator who pinned a state dir keeps it even in isolated mode."""
|
||||
hermes_home = tmp_path / ".hermes" / "profiles" / "isolated"
|
||||
hermes_home.mkdir(parents=True)
|
||||
explicit = tmp_path / "custom-state"
|
||||
|
||||
old_home = os.environ.get("HERMES_HOME")
|
||||
old_state_dir = os.environ.get("HERMES_WEBUI_STATE_DIR")
|
||||
try:
|
||||
os.environ["HERMES_HOME"] = str(hermes_home)
|
||||
os.environ["HERMES_WEBUI_STATE_DIR"] = str(explicit)
|
||||
|
||||
reloaded = importlib.reload(config)
|
||||
|
||||
assert reloaded.STATE_DIR == explicit.resolve()
|
||||
finally:
|
||||
if old_home is None:
|
||||
os.environ.pop("HERMES_HOME", None)
|
||||
else:
|
||||
os.environ["HERMES_HOME"] = old_home
|
||||
if old_state_dir is None:
|
||||
os.environ.pop("HERMES_WEBUI_STATE_DIR", None)
|
||||
else:
|
||||
os.environ["HERMES_WEBUI_STATE_DIR"] = old_state_dir
|
||||
importlib.reload(config)
|
||||
Reference in new issue
Block a user