From 854007d1c30e7c868040bc1bbcd5dcee6c991cfe Mon Sep 17 00:00:00 2001 From: joaomarcos Date: Fri, 31 Jul 2026 03:13:38 -0300 Subject: [PATCH] fix(auth): route remaining main-agent fallback key reads through secret_scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit agent_init.py's init-time fallback and chat_completion_helpers.py's try_activate_fallback() still read key_env via raw os.getenv(), missing the per-profile secret scope installed by the multiplexed gateway (same bug fixed for fallback_config.py/auxiliary_client.py in this PR). Both now delegate to hermes_cli.fallback_config.resolve_entry_api_key(), and the Ollama Cloud OLLAMA_API_KEY read now goes through agent.secret_scope.get_secret() too. agent_init.py's fallback loop had no try/except around key resolution (unlike the other three call sites), so a fail-closed UnscopedSecretError under multiplexing would have crashed init instead of skipping to the next fallback entry — added the same skip-and-continue handling. Co-Authored-By: Claude Sonnet 5 --- agent/agent_init.py | 24 ++++++++++++++---------- agent/chat_completion_helpers.py | 14 ++++++-------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/agent/agent_init.py b/agent/agent_init.py index 1e0a444bf254d..ef3199cb83749 100644 --- a/agent/agent_init.py +++ b/agent/agent_init.py @@ -1221,16 +1221,20 @@ def init_agent( _fb_entries = [fallback_model] _fb_resolved = False for _fb in _fb_entries: - _fb_explicit_key = (_fb.get("api_key") or "").strip() or None - if not _fb_explicit_key: - _fb_key_env = (_fb.get("key_env") or _fb.get("api_key_env") or "").strip() - if _fb_key_env: - _fb_explicit_key = os.getenv(_fb_key_env, "").strip() or None - _fb_client, _fb_model = resolve_provider_client( - _fb["provider"], model=_fb["model"], raw_codex=True, - explicit_base_url=_fb.get("base_url"), - explicit_api_key=_fb_explicit_key, - ) + try: + from hermes_cli.fallback_config import resolve_entry_api_key + _fb_explicit_key = resolve_entry_api_key(_fb) + _fb_client, _fb_model = resolve_provider_client( + _fb["provider"], model=_fb["model"], raw_codex=True, + explicit_base_url=_fb.get("base_url"), + explicit_api_key=_fb_explicit_key, + ) + except Exception as _fb_exc: + logger.debug( + "Init-time fallback entry %s failed: %s", + _fb.get("provider"), _fb_exc, + ) + continue if _fb_client is not None: agent.provider = _fb["provider"] agent.model = _fb_model or _fb["model"] diff --git a/agent/chat_completion_helpers.py b/agent/chat_completion_helpers.py index d11b830fd8c66..a025f58f5a2d9 100644 --- a/agent/chat_completion_helpers.py +++ b/agent/chat_completion_helpers.py @@ -1788,19 +1788,17 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool # Pass base_url and api_key from fallback config so custom # endpoints (e.g. Ollama Cloud) resolve correctly instead of # falling through to OpenRouter defaults. + from hermes_cli.fallback_config import resolve_entry_api_key + fb_base_url_hint = (fb.get("base_url") or "").strip() or None - fb_api_key_hint = (fb.get("api_key") or "").strip() or None - if not fb_api_key_hint: - # key_env and api_key_env are both documented aliases (see - # _normalize_custom_provider_entry in hermes_cli/config.py). - fb_key_env = (fb.get("key_env") or fb.get("api_key_env") or "").strip() - if fb_key_env: - fb_api_key_hint = os.getenv(fb_key_env, "").strip() or None + fb_api_key_hint = resolve_entry_api_key(fb) # For Ollama Cloud endpoints, pull OLLAMA_API_KEY from env # when no explicit key is in the fallback config. Host match # (not substring) — see GHSA-76xc-57q6-vm5m. if fb_base_url_hint and base_url_host_matches(fb_base_url_hint, "ollama.com") and not fb_api_key_hint: - fb_api_key_hint = os.getenv("OLLAMA_API_KEY") or None + from agent.secret_scope import get_secret + + fb_api_key_hint = get_secret("OLLAMA_API_KEY") or None fb_client, _resolved_fb_model = resolve_provider_client( fb_provider, model=fb_model, raw_codex=True, explicit_base_url=fb_base_url_hint,