mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(hermes_cli): lock dashboard xAI active_provider contracts and setup unsuppress
Cover preserve-vs-mark-if-unset for dashboard OAuth, assert TTS setup clears device_code suppression, and clarify set_active docstring callers.
This commit is contained in:
parent
f42be94049
commit
0d0ad3f9d9
3 changed files with 83 additions and 3 deletions
|
|
@ -4458,8 +4458,9 @@ def _save_xai_oauth_tokens(
|
|||
|
||||
When *set_active* is True (default), also promote ``xai-oauth`` to
|
||||
``active_provider`` — appropriate for intentional model/auth login.
|
||||
Pass ``set_active=False`` for side-tool credential bootstrap (TTS, STT,
|
||||
dashboard token save, token refresh) so inference routing is unchanged.
|
||||
Pass ``set_active=False`` for side-tool credential bootstrap (TTS/setup,
|
||||
tools config, dashboard token save, token refresh) so inference routing
|
||||
is unchanged.
|
||||
"""
|
||||
if last_refresh is None:
|
||||
last_refresh = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Regression: TTS/setup xAI OAuth must not hijack the active chat provider."""
|
||||
"""Regression: TTS/setup xAI OAuth must not hijack the active chat provider."""
|
||||
|
||||
import json
|
||||
|
||||
|
|
@ -62,10 +62,16 @@ def test_run_xai_oauth_login_from_setup_does_not_hijack_active_provider(
|
|||
)
|
||||
monkeypatch.setattr("hermes_cli.auth._is_remote_session", lambda: True)
|
||||
|
||||
from hermes_cli.auth import is_source_suppressed, suppress_credential_source
|
||||
from hermes_cli.setup import _run_xai_oauth_login_from_setup
|
||||
|
||||
suppress_credential_source("xai-oauth", "device_code")
|
||||
assert is_source_suppressed("xai-oauth", "device_code") is True
|
||||
|
||||
assert _run_xai_oauth_login_from_setup() is True
|
||||
|
||||
assert is_source_suppressed("xai-oauth", "device_code") is False
|
||||
|
||||
auth = json.loads(auth_path.read_text(encoding="utf-8"))
|
||||
assert auth["active_provider"] == "openrouter"
|
||||
xai_state = auth["providers"]["xai-oauth"]
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ The fix:
|
|||
These tests pin the corrected behavior.
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from unittest.mock import patch
|
||||
|
|
@ -665,6 +666,19 @@ def test_xai_dashboard_poller_seeds_single_entry_and_clears_suppression(tmp_path
|
|||
monkeypatch.delenv("HERMES_XAI_BASE_URL", raising=False)
|
||||
monkeypatch.delenv("XAI_BASE_URL", raising=False)
|
||||
|
||||
# Existing chat provider must not be overwritten by dashboard OAuth.
|
||||
auth_path = tmp_path / "auth.json"
|
||||
auth_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"version": 1,
|
||||
"active_provider": "openrouter",
|
||||
"providers": {},
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
# Prior `hermes auth remove xai-oauth` left the source suppressed.
|
||||
auth_mod.suppress_credential_source("xai-oauth", "device_code")
|
||||
assert auth_mod.is_source_suppressed("xai-oauth", "device_code") is True
|
||||
|
|
@ -707,6 +721,10 @@ def test_xai_dashboard_poller_seeds_single_entry_and_clears_suppression(tmp_path
|
|||
# The interactive dashboard login cleared the suppression marker.
|
||||
assert auth_mod.is_source_suppressed("xai-oauth", "device_code") is False
|
||||
|
||||
after = json.loads(auth_path.read_text(encoding="utf-8"))
|
||||
assert after["active_provider"] == "openrouter"
|
||||
assert after["providers"]["xai-oauth"]["tokens"]["access_token"] == "xai-dashboard-access"
|
||||
|
||||
# The credential pool has exactly one entry, seeded from the
|
||||
# singleton as ``device_code`` — no parallel ``manual:dashboard_*``
|
||||
# duplicate sharing the single-use refresh token.
|
||||
|
|
@ -719,6 +737,61 @@ def test_xai_dashboard_poller_seeds_single_entry_and_clears_suppression(tmp_path
|
|||
)
|
||||
|
||||
|
||||
def test_xai_dashboard_poller_marks_active_when_unset(tmp_path, monkeypatch):
|
||||
"""First dashboard xAI login may set active_provider when none is set yet."""
|
||||
from hermes_cli import auth as auth_mod
|
||||
from hermes_cli import web_server as ws
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
monkeypatch.delenv("HERMES_XAI_BASE_URL", raising=False)
|
||||
monkeypatch.delenv("XAI_BASE_URL", raising=False)
|
||||
|
||||
auth_path = tmp_path / "auth.json"
|
||||
auth_path.write_text(
|
||||
json.dumps({"version": 1, "providers": {}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
auth_mod,
|
||||
"_xai_oauth_discovery",
|
||||
lambda *a, **k: {"token_endpoint": "https://auth.x.ai/token"},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
auth_mod,
|
||||
"_xai_oauth_poll_device_token",
|
||||
lambda client, **kwargs: {
|
||||
"access_token": "xai-dashboard-first",
|
||||
"refresh_token": "rt-first",
|
||||
"id_token": "",
|
||||
"expires_in": 3600,
|
||||
"token_type": "Bearer",
|
||||
},
|
||||
)
|
||||
|
||||
session_id = "xai-dashboard-first-active-test"
|
||||
ws._oauth_sessions[session_id] = {
|
||||
"session_id": session_id,
|
||||
"provider": "xai-oauth",
|
||||
"flow": "device_code",
|
||||
"created_at": time.time(),
|
||||
"status": "pending",
|
||||
"error_message": None,
|
||||
"device_code": "device-code",
|
||||
"interval": 5,
|
||||
"expires_at": time.time() + 600,
|
||||
}
|
||||
try:
|
||||
ws._xai_device_poller(session_id)
|
||||
assert ws._oauth_sessions[session_id]["status"] == "approved"
|
||||
finally:
|
||||
ws._oauth_sessions.pop(session_id, None)
|
||||
|
||||
after = json.loads(auth_path.read_text(encoding="utf-8"))
|
||||
assert after["active_provider"] == "xai-oauth"
|
||||
assert after["providers"]["xai-oauth"]["tokens"]["access_token"] == "xai-dashboard-first"
|
||||
|
||||
|
||||
def test_unknown_pkce_provider_rejected_cleanly():
|
||||
"""A future PKCE provider without an explicit branch must NOT silently route to Anthropic.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue