fix: preserve webui launcher environment

(cherry picked from commit 2297ab4db854b52b20cdd34731cd82e8cc5bdb72)
This commit is contained in:
Charanis
2026-05-24 16:52:59 +02:00
parent 5977567035
commit f0b0854773
4 changed files with 32 additions and 3 deletions

View File

@@ -28,8 +28,8 @@ def _load_repo_dotenv() -> None:
``python3 bootstrap.py`` directly behaves identically to ``./start.sh``.
Variables are set unconditionally (matching shell source semantics), so a
value in .env overrides one already present in the shell environment.
To keep a CLI-supplied value, unset it from .env or launch via start.sh
and override there.
``ctl.sh`` sets HERMES_WEBUI_PRESERVE_ENV=1 when it has already resolved
launcher-specific values such as HERMES_HOME or HERMES_WEBUI_STATE_DIR.
Only loads the webui repo .env — not ~/.hermes/.env, which the server
loads independently at startup for provider credentials.
@@ -41,6 +41,12 @@ def _load_repo_dotenv() -> None:
if not env_path.exists():
return
try:
preserve_existing = os.getenv("HERMES_WEBUI_PRESERVE_ENV", "").strip().lower() in {
"1",
"true",
"yes",
"on",
}
for raw_line in env_path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
@@ -52,6 +58,8 @@ def _load_repo_dotenv() -> None:
k = k[7:].strip()
v = v.strip().strip('"').strip("'")
if k:
if preserve_existing and k in os.environ:
continue
os.environ[k] = v
except Exception as exc:
import sys as _sys

4
ctl.sh
View File

@@ -219,7 +219,9 @@ start_cmd() {
: >> "${LOG_FILE}"
(
cd "${REPO_ROOT}"
exec "${python_exe}" "${REPO_ROOT}/bootstrap.py" --no-browser --foreground --host "${CTL_HOST}" "${CTL_PORT}" ${CTL_BOOTSTRAP_ARGS[@]+"${CTL_BOOTSTRAP_ARGS[@]}"}
trap '' HUP
export HERMES_WEBUI_PRESERVE_ENV=1
exec nohup "${python_exe}" "${REPO_ROOT}/bootstrap.py" --no-browser --foreground --host "${CTL_HOST}" "${CTL_PORT}" ${CTL_BOOTSTRAP_ARGS[@]+"${CTL_BOOTSTRAP_ARGS[@]}"}
) >> "${LOG_FILE}" 2>&1 &
pid=$!

View File

@@ -112,6 +112,18 @@ class TestLoadRepoDotenv:
self._run(tmp_path, "HERMES_WEBUI_HOST=0.0.0.0\n")
assert os.environ.get("HERMES_WEBUI_HOST") == "0.0.0.0"
def test_preserve_existing_env_keeps_ctl_overrides(self, tmp_path):
"""ctl.sh can ask bootstrap.py to keep wrapper-provided env values."""
os.environ["HERMES_WEBUI_PRESERVE_ENV"] = "1"
os.environ["HERMES_HOME"] = "/runtime/hermesOne"
os.environ["HERMES_WEBUI_PASSWORD"] = ""
self._run(
tmp_path,
"HERMES_HOME=/repo/default\nHERMES_WEBUI_PASSWORD=repo-password\n",
)
assert os.environ.get("HERMES_HOME") == "/runtime/hermesOne"
assert os.environ.get("HERMES_WEBUI_PASSWORD") == ""
def test_does_not_set_empty_values(self, tmp_path):
"""A key whose value is empty after stripping is not set to a non-empty string."""
os.environ.pop("HERMES_EMPTY_KEY", None)

View File

@@ -138,6 +138,13 @@ def test_start_writes_pid_under_hermes_home_runs_foreground_no_browser_and_logs(
assert not pid_file.exists()
def test_start_uses_nohup_so_daemon_survives_launcher_exit():
ctl_text = CTL.read_text(encoding="utf-8")
assert "trap '' HUP" in ctl_text
assert 'exec nohup "${python_exe}"' in ctl_text
def test_start_loads_dotenv_but_inline_overrides_win(tmp_path):
repo_root = tmp_path / "repo"
repo_root.mkdir()