mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix(doctor): isolate per-provider OAuth imports to prevent fallback regression
Shared try/except import block meant that if any one status function was missing, all providers lost their OAuth fallback suppression. Split into per-provider try/except so each branch is independently safe. Add end-to-end test for xAI: bad XAI_API_KEY with healthy OAuth does not surface a blocking issue in run_doctor output. Add tests for None return, import failure isolation (xAI missing does not break Gemini), and move test_returns_false_for_unknown_provider out of the xAI-specific class.
This commit is contained in:
parent
e89d78ff09
commit
e10bb9dffa
2 changed files with 60 additions and 15 deletions
|
|
@ -160,22 +160,25 @@ def _has_healthy_oauth_fallback_for_apikey_provider(provider_label: str) -> bool
|
|||
still show a failed API-key connectivity row, but it should not promote
|
||||
that direct-key problem into the final blocking summary.
|
||||
"""
|
||||
try:
|
||||
from hermes_cli.auth import (
|
||||
get_gemini_oauth_auth_status,
|
||||
get_minimax_oauth_auth_status,
|
||||
get_xai_oauth_auth_status,
|
||||
)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
normalized = (provider_label or "").strip().lower()
|
||||
if normalized in {"google / gemini", "gemini"}:
|
||||
return bool((get_gemini_oauth_auth_status() or {}).get("logged_in"))
|
||||
try:
|
||||
from hermes_cli.auth import get_gemini_oauth_auth_status
|
||||
return bool((get_gemini_oauth_auth_status() or {}).get("logged_in"))
|
||||
except Exception:
|
||||
return False
|
||||
if normalized == "minimax":
|
||||
return bool((get_minimax_oauth_auth_status() or {}).get("logged_in"))
|
||||
try:
|
||||
from hermes_cli.auth import get_minimax_oauth_auth_status
|
||||
return bool((get_minimax_oauth_auth_status() or {}).get("logged_in"))
|
||||
except Exception:
|
||||
return False
|
||||
if normalized == "xai":
|
||||
return bool((get_xai_oauth_auth_status() or {}).get("logged_in"))
|
||||
try:
|
||||
from hermes_cli.auth import get_xai_oauth_auth_status
|
||||
return bool((get_xai_oauth_auth_status() or {}).get("logged_in"))
|
||||
except Exception:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -850,6 +850,7 @@ def _run_doctor_with_healthy_oauth_fallback(
|
|||
failing_host: str,
|
||||
gemini_oauth_status: dict,
|
||||
minimax_oauth_status: dict,
|
||||
xai_oauth_status: dict | None = None,
|
||||
) -> str:
|
||||
home = tmp_path / ".hermes"
|
||||
home.mkdir(parents=True, exist_ok=True)
|
||||
|
|
@ -886,6 +887,8 @@ def _run_doctor_with_healthy_oauth_fallback(
|
|||
monkeypatch.setattr(_auth_mod, "get_codex_auth_status", lambda: {})
|
||||
monkeypatch.setattr(_auth_mod, "get_gemini_oauth_auth_status", lambda: gemini_oauth_status)
|
||||
monkeypatch.setattr(_auth_mod, "get_minimax_oauth_auth_status", lambda: minimax_oauth_status)
|
||||
_xai_status = xai_oauth_status if xai_oauth_status is not None else {}
|
||||
monkeypatch.setattr(_auth_mod, "get_xai_oauth_auth_status", lambda: _xai_status)
|
||||
|
||||
def fake_get(url, headers=None, timeout=None):
|
||||
status = 401 if failing_host in url else 200
|
||||
|
|
@ -902,7 +905,7 @@ def _run_doctor_with_healthy_oauth_fallback(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("env_key", "bad_key", "failing_host", "gemini_oauth_status", "minimax_oauth_status", "unexpected_issue"),
|
||||
("env_key", "bad_key", "failing_host", "gemini_oauth_status", "minimax_oauth_status", "xai_oauth_status", "unexpected_issue"),
|
||||
[
|
||||
(
|
||||
"GOOGLE_API_KEY",
|
||||
|
|
@ -910,6 +913,7 @@ def _run_doctor_with_healthy_oauth_fallback(
|
|||
"googleapis.com",
|
||||
{"logged_in": True, "email": "user@example.com"},
|
||||
{},
|
||||
None,
|
||||
"Check GOOGLE_API_KEY in .env",
|
||||
),
|
||||
(
|
||||
|
|
@ -918,8 +922,18 @@ def _run_doctor_with_healthy_oauth_fallback(
|
|||
"minimax.io",
|
||||
{},
|
||||
{"logged_in": True, "region": "global"},
|
||||
None,
|
||||
"Check MINIMAX_API_KEY in .env",
|
||||
),
|
||||
(
|
||||
"XAI_API_KEY",
|
||||
"bad-xai-key",
|
||||
"api.x.ai",
|
||||
{},
|
||||
{},
|
||||
{"logged_in": True, "auth_mode": "oauth_pkce"},
|
||||
"Check XAI_API_KEY in .env",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_run_doctor_ignores_invalid_direct_keys_when_oauth_fallback_is_healthy(
|
||||
|
|
@ -930,6 +944,7 @@ def test_run_doctor_ignores_invalid_direct_keys_when_oauth_fallback_is_healthy(
|
|||
failing_host,
|
||||
gemini_oauth_status,
|
||||
minimax_oauth_status,
|
||||
xai_oauth_status,
|
||||
unexpected_issue,
|
||||
):
|
||||
out = _run_doctor_with_healthy_oauth_fallback(
|
||||
|
|
@ -940,12 +955,18 @@ def test_run_doctor_ignores_invalid_direct_keys_when_oauth_fallback_is_healthy(
|
|||
failing_host=failing_host,
|
||||
gemini_oauth_status=gemini_oauth_status,
|
||||
minimax_oauth_status=minimax_oauth_status,
|
||||
xai_oauth_status=xai_oauth_status,
|
||||
)
|
||||
|
||||
assert "invalid API key" in out
|
||||
assert unexpected_issue not in out
|
||||
|
||||
|
||||
def test_has_healthy_oauth_fallback_returns_false_for_unknown_provider():
|
||||
from hermes_cli.doctor import _has_healthy_oauth_fallback_for_apikey_provider
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("unknown-provider") is False
|
||||
|
||||
|
||||
class TestHasHealthyOauthFallbackForXai:
|
||||
def test_returns_true_when_xai_oauth_healthy(self, monkeypatch):
|
||||
from hermes_cli import auth as _auth_mod
|
||||
|
|
@ -959,6 +980,27 @@ class TestHasHealthyOauthFallbackForXai:
|
|||
from hermes_cli.doctor import _has_healthy_oauth_fallback_for_apikey_provider
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("xai") is False
|
||||
|
||||
def test_returns_false_for_unknown_provider(self):
|
||||
def test_returns_false_when_xai_oauth_returns_none(self, monkeypatch):
|
||||
from hermes_cli import auth as _auth_mod
|
||||
monkeypatch.setattr(_auth_mod, "get_xai_oauth_auth_status", lambda: None)
|
||||
from hermes_cli.doctor import _has_healthy_oauth_fallback_for_apikey_provider
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("unknown-provider") is False
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("xai") is False
|
||||
|
||||
def test_returns_false_when_xai_import_unavailable(self, monkeypatch):
|
||||
import sys
|
||||
# Simulate get_xai_oauth_auth_status missing from auth module
|
||||
monkeypatch.delattr("hermes_cli.auth.get_xai_oauth_auth_status", raising=False)
|
||||
# Force doctor module to re-import the function
|
||||
monkeypatch.delitem(sys.modules, "hermes_cli.doctor", raising=False)
|
||||
from hermes_cli.doctor import _has_healthy_oauth_fallback_for_apikey_provider
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("xai") is False
|
||||
|
||||
def test_xai_import_failure_does_not_affect_gemini(self, monkeypatch):
|
||||
import sys
|
||||
from hermes_cli import auth as _auth_mod
|
||||
# xAI function missing, but Gemini is healthy
|
||||
monkeypatch.delattr(_auth_mod, "get_xai_oauth_auth_status", raising=False)
|
||||
monkeypatch.setattr(_auth_mod, "get_gemini_oauth_auth_status", lambda: {"logged_in": True})
|
||||
monkeypatch.delitem(sys.modules, "hermes_cli.doctor", raising=False)
|
||||
from hermes_cli.doctor import _has_healthy_oauth_fallback_for_apikey_provider
|
||||
assert _has_healthy_oauth_fallback_for_apikey_provider("gemini") is True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue