From d21ac579e99f5561de724f13500b930bb28848d7 Mon Sep 17 00:00:00 2001 From: QuenVix Date: Sat, 23 May 2026 09:11:22 +0300 Subject: [PATCH] fix(gateway): honor key_env in auth-failure fallback resolution --- gateway/run.py | 9 +++- .../test_session_model_override_routing.py | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/gateway/run.py b/gateway/run.py index 56269591f22..f690ade2004 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -1004,10 +1004,17 @@ def _try_resolve_fallback_provider() -> dict | None: if not isinstance(entry, dict): continue try: + explicit_api_key = entry.get("api_key") + if not explicit_api_key: + key_env = str( + entry.get("key_env") or entry.get("api_key_env") or "" + ).strip() + if key_env: + explicit_api_key = os.getenv(key_env, "").strip() or None runtime = resolve_runtime_provider( requested=entry.get("provider"), explicit_base_url=entry.get("base_url"), - explicit_api_key=entry.get("api_key"), + explicit_api_key=explicit_api_key, ) logger.info( "Fallback provider resolved: %s model=%s", diff --git a/tests/gateway/test_session_model_override_routing.py b/tests/gateway/test_session_model_override_routing.py index 26acdc157aa..b1e50c07bf3 100644 --- a/tests/gateway/test_session_model_override_routing.py +++ b/tests/gateway/test_session_model_override_routing.py @@ -218,3 +218,46 @@ fallback_providers: assert runtime_kwargs["provider"] == "openrouter" assert runtime_kwargs["api_key"] == "sk-openrouter" + +def test_gateway_auth_fallback_resolves_key_env_for_custom_provider(tmp_path, monkeypatch): + """Auth-failure fallback should honor key_env/api_key_env custom-endpoint hints.""" + config = tmp_path / "config.yaml" + config.write_text( + """ +fallback_providers: + - provider: custom + model: fallback-model + base_url: https://fallback.example/v1 + key_env: MY_FALLBACK_KEY +""".lstrip(), + encoding="utf-8", + ) + monkeypatch.setattr(gateway_run, "_hermes_home", tmp_path) + monkeypatch.setenv("MY_FALLBACK_KEY", "env-secret") + + def fake_resolve_runtime_provider(*, requested=None, explicit_base_url=None, explicit_api_key=None): + assert requested == "custom" + assert explicit_base_url == "https://fallback.example/v1" + assert explicit_api_key == "env-secret" + return { + "api_key": explicit_api_key, + "base_url": explicit_base_url, + "provider": "custom", + "api_mode": "chat_completions", + "command": None, + "args": [], + "credential_pool": None, + } + + import hermes_cli.runtime_provider as runtime_provider + + monkeypatch.setattr(runtime_provider, "resolve_runtime_provider", fake_resolve_runtime_provider) + + runtime_kwargs = gateway_run._try_resolve_fallback_provider() + + assert runtime_kwargs is not None + assert runtime_kwargs["provider"] == "custom" + assert runtime_kwargs["api_key"] == "env-secret" + assert runtime_kwargs["base_url"] == "https://fallback.example/v1" + assert runtime_kwargs["model"] == "fallback-model" +