fix(profiles): honour active_profile when HERMES_HOME points to hermes root

Problem:
After `hermes profile use NAME`, the gateway (started via systemd with
HERMES_HOME=/root/.hermes hardcoded) ignores the active profile and
always runs as the Default profile.  WebUI, Telegram, and all non-CLI
platforms are affected.

Root cause:
_apply_profile_override() contained an early-return guard:

    if profile_name is None and os.environ.get("HERMES_HOME"):
        return   # trust the inherited value

The intent was to let child processes inherit their parent's profile via
HERMES_HOME without redundantly re-reading active_profile.  But
systemd also sets HERMES_HOME — to the hermes root (/root/.hermes),
not a profile directory — so the guard fired and silently skipped the
active_profile check.  The user's `hermes profile use NAME` write to
~/.hermes/active_profile was never seen by the gateway process.

Fix:
Only skip the active_profile check when HERMES_HOME is already a
profile directory, identified by its immediate parent directory being
named "profiles" (e.g. ~/.hermes/profiles/coder or
/opt/data/profiles/coder).  When HERMES_HOME points to a root
directory (parent name != "profiles"), continue to read active_profile.

Tests:
- test_hermes_home_at_root_with_active_profile_is_redirected: the
  bug scenario — HERMES_HOME=/root/.hermes + active_profile=coder →
  HERMES_HOME must be redirected to .../profiles/coder.
  Stash-verified: FAILS without fix, PASSES with fix.
- test_hermes_home_already_profile_dir_is_trusted: child-process
  inheritance contract unchanged — .../profiles/coder is trusted as-is.
- test_hermes_home_unset_reads_active_profile: classic path unchanged.
- test_hermes_home_unset_default_profile_no_redirect: "default" still
  produces no redirect.
4/4 tests green.

Closes #22502.
This commit is contained in:
Wesley Simplicio 2026-05-09 12:34:11 -03:00 committed by Teknium
parent 854c2ce309
commit a33c63b9f8
2 changed files with 154 additions and 5 deletions

View file

@ -144,11 +144,19 @@ def _apply_profile_override() -> None:
profile_name = None
consume = 0
# 1.5 If HERMES_HOME is already set and no explicit flag was given, trust it.
# This lets child processes (relaunch, subprocess) inherit the parent's
# profile choice without having to pass --profile again.
if profile_name is None and os.environ.get("HERMES_HOME"):
return
# 1.5 If HERMES_HOME is already set and no explicit flag was given, trust it
# only when it already points to a specific profile directory. The
# distinguishing heuristic: a profile path has "profiles" as its immediate
# parent directory name (e.g. ~/.hermes/profiles/coder or
# /opt/data/profiles/coder). If HERMES_HOME points to the hermes root
# instead (e.g. systemd hardcodes HERMES_HOME=/root/.hermes), we must
# still read active_profile — the user may have switched profiles via
# `hermes profile use` and the gateway should honour that choice.
# See issue #22502.
hermes_home_env = os.environ.get("HERMES_HOME", "")
if profile_name is None and hermes_home_env:
if Path(hermes_home_env).parent.name == "profiles":
return
# 2. If no flag, check active_profile in the hermes root
if profile_name is None: