From 0a6aa7cce1be07a7fe8051254997bcea864e1010 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 03:31:05 -0700 Subject: [PATCH] fix(env_loader): log routed-scope dotenv skip once per home; port single-profile control test Follow-up to the #77592 salvage: emit a once-per-home debug line where the multiplex guard skips the process-global dotenv load (requested on #77562), and port the single-profile control test from #77970 so the guard is pinned to the multiplex flag rather than the home override alone. Co-authored-by: DonShelly <25538402+DonShelly@users.noreply.github.com> --- hermes_cli/env_loader.py | 14 ++++++++++++ tests/test_env_loader_secret_sources.py | 30 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/hermes_cli/env_loader.py b/hermes_cli/env_loader.py index 7afca4229b..a0e1fbfd95 100644 --- a/hermes_cli/env_loader.py +++ b/hermes_cli/env_loader.py @@ -51,6 +51,10 @@ _SECRET_SOURCE_VALUES_BY_HOME: dict[str, dict[str, str]] = {} _APPLIED_HOMES: set[str] = set() _SECRET_SOURCE_CACHE_LOCK = threading.RLock() +# Routed profile homes whose dotenv load was skipped under multiplex, so the +# skip is logged once per home rather than on every lazy import mid-turn. +_SCOPED_SKIP_LOGGED: set[str] = set() + def _known_hermes_env_keys() -> set[str]: """Return the combined set of known Hermes env-var keys. @@ -501,6 +505,16 @@ def load_hermes_dotenv( from hermes_constants import get_hermes_home_override if is_multiplex_active() and get_hermes_home_override() is not None: + home_key = str(home_path.resolve()) + if home_key not in _SCOPED_SKIP_LOGGED: + _SCOPED_SKIP_LOGGED.add(home_key) + import logging + + logging.getLogger(__name__).debug( + "multiplex: skipping process-global dotenv load for routed " + "profile home %s (credentials resolve via the profile scope)", + home_path, + ) if load_external_secrets: from hermes_cli import _early_recovery diff --git a/tests/test_env_loader_secret_sources.py b/tests/test_env_loader_secret_sources.py index 065270458b..c2959144c9 100644 --- a/tests/test_env_loader_secret_sources.py +++ b/tests/test_env_loader_secret_sources.py @@ -174,6 +174,36 @@ def test_cold_profile_bitwarden_uses_profile_bootstrap_without_global_env( assert os.environ.get("ANTHROPIC_API_KEY") is None +def test_single_profile_scoped_load_keeps_override_behavior(tmp_path, monkeypatch): + """Without multiplex, a scoped load keeps its historical override behaviour. + + Ported from #77970 (@DonShelly): the guard must key on the multiplex flag, + not on the home override alone -- single-profile ``-p`` runs still load. + """ + from agent import secret_scope + from hermes_constants import reset_hermes_home_override, set_hermes_home_override + + monkeypatch.delenv("HERMES_TEST_SHARED_ADAPTER_CONFIG", raising=False) + other_home = tmp_path / "other" + other_home.mkdir() + (other_home / ".env").write_text("HERMES_TEST_SHARED_ADAPTER_CONFIG=second\n") + + was_active = secret_scope.is_multiplex_active() + secret_scope.set_multiplex_active(False) + home_token = set_hermes_home_override(other_home) + try: + loaded = env_loader.load_hermes_dotenv(hermes_home=other_home) + finally: + secret_scope.set_multiplex_active(was_active) + reset_hermes_home_override(home_token) + + try: + assert os.environ.get("HERMES_TEST_SHARED_ADAPTER_CONFIG") == "second" + assert (other_home / ".env") in loaded + finally: + os.environ.pop("HERMES_TEST_SHARED_ADAPTER_CONFIG", None) + + def test_multiplex_dotenv_load_hydrates_sources_without_global_env( tmp_path, monkeypatch ):