fix(auth): refresh Nous entitlement in tool menus

This commit is contained in:
Robin Fernandes 2026-05-28 09:53:22 +10:00 committed by Teknium
parent 406901b27d
commit 1cf5e639b3
8 changed files with 304 additions and 108 deletions

View file

@ -237,7 +237,7 @@ class TestConfigWriting:
monkeypatch.setattr(
tools_config,
"get_nous_subscription_features",
lambda config: SimpleNamespace(
lambda config, **kwargs: SimpleNamespace(
features={"image_gen": SimpleNamespace(managed_by_nous=True)}
),
)

View file

@ -34,6 +34,28 @@ def test_get_nous_subscription_features_recognizes_direct_exa_backend(monkeypatc
assert features.web.current_provider == "exa"
def test_get_nous_subscription_features_force_fresh_forwards_account_request(monkeypatch):
calls = []
def fake_account_info(*, force_fresh=False):
calls.append(force_fresh)
return _account(logged_in=True, paid=True)
monkeypatch.setattr(ns, "get_env_value", lambda name: "")
monkeypatch.setattr(ns, "get_nous_portal_account_info", fake_account_info)
monkeypatch.setattr(ns, "_toolset_enabled", lambda config, key: False)
monkeypatch.setattr(ns, "_has_agent_browser", lambda: False)
monkeypatch.setattr(ns, "resolve_openai_audio_api_key", lambda: "")
monkeypatch.setattr(ns, "has_direct_modal_credentials", lambda: False)
monkeypatch.setattr(ns, "is_managed_tool_gateway_ready", lambda vendor: False)
features = ns.get_nous_subscription_features({}, force_fresh=True)
assert features.account_info is not None
assert features.account_info.paid_service_access is True
assert calls == [True]
def test_get_nous_subscription_features_prefers_managed_modal_in_auto_mode(monkeypatch):
monkeypatch.setattr("tools.tool_backend_helpers.managed_nous_tools_enabled", lambda: True)
monkeypatch.setattr(ns, "get_env_value", lambda name: "")

View file

@ -133,37 +133,6 @@ def test_show_status_reports_nous_inference_key_without_portal_login(monkeypatch
assert "Nous inference credentials are configured" in output
def test_show_status_reports_vercel_backend_contract(monkeypatch, capsys, tmp_path):
from hermes_cli import status as status_mod
import hermes_cli.auth as auth_mod
import hermes_cli.gateway as gateway_mod
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
monkeypatch.setenv("TERMINAL_ENV", "vercel_sandbox")
monkeypatch.setenv("TERMINAL_VERCEL_RUNTIME", "python3.13")
monkeypatch.setenv("TERMINAL_CONTAINER_PERSISTENT", "true")
monkeypatch.setenv("VERCEL_OIDC_TOKEN", "oidc-token")
monkeypatch.setattr(status_mod.importlib.util, "find_spec", lambda name: object() if name == "vercel" else None)
monkeypatch.setattr(status_mod, "load_config", lambda: {"terminal": {"backend": "vercel_sandbox"}}, raising=False)
monkeypatch.setattr(auth_mod, "get_nous_auth_status", lambda: {}, raising=False)
monkeypatch.setattr(auth_mod, "get_codex_auth_status", lambda: {}, raising=False)
monkeypatch.setattr(auth_mod, "get_qwen_auth_status", lambda: {}, raising=False)
monkeypatch.setattr(auth_mod, "get_xai_oauth_auth_status", lambda: {}, raising=False)
monkeypatch.setattr(gateway_mod, "find_gateway_pids", lambda exclude_pids=None: [], raising=False)
status_mod.show_status(SimpleNamespace(all=False, deep=False))
output = capsys.readouterr().out
assert "Backend: vercel_sandbox" in output
assert "Runtime: python3.13" in output
assert "Auth:" in output and "OIDC token via VERCEL_OIDC_TOKEN" in output
assert "Auth detail: mode: OIDC" in output
assert "Auth detail: active env: VERCEL_OIDC_TOKEN" in output
assert "oidc-token" not in output
assert "snapshot filesystem" in output
assert "live processes do not survive" in output
# ---------------------------------------------------------------------------
# Helpers shared by xAI OAuth status tests
# ---------------------------------------------------------------------------

View file

@ -1,5 +1,6 @@
"""Tests for hermes_cli.tools_config platform tool persistence."""
from types import SimpleNamespace
from unittest.mock import patch
import pytest
@ -554,7 +555,6 @@ def test_save_platform_tools_still_preserves_mcp_with_platform_default_present()
def test_visible_providers_include_nous_subscription_when_logged_in(monkeypatch):
monkeypatch.setattr("hermes_cli.tools_config.managed_nous_tools_enabled", lambda: True)
config = {"model": {"provider": "nous"}}
monkeypatch.setattr(
@ -572,18 +572,48 @@ def test_visible_providers_include_nous_subscription_when_logged_in(monkeypatch)
assert providers[0]["name"].startswith("Nous Subscription")
def test_visible_providers_hide_nous_subscription_when_feature_flag_is_off(monkeypatch):
monkeypatch.setattr("hermes_cli.tools_config.managed_nous_tools_enabled", lambda: False)
def test_visible_providers_force_fresh_shows_nous_subscription_after_upgrade(monkeypatch):
calls = []
def fake_subscription_features(config, *, force_fresh=False):
calls.append(("features", force_fresh))
return SimpleNamespace(
nous_auth_present=True,
account_info=NousPortalAccountInfo(
logged_in=True,
source="account_api" if force_fresh else "jwt",
fresh=force_fresh,
paid_service_access=True if force_fresh else False,
),
features={},
)
monkeypatch.setattr(
"hermes_cli.tools_config.get_nous_subscription_features",
fake_subscription_features,
)
providers = _visible_providers(
TOOL_CATEGORIES["browser"],
{"model": {"provider": "nous"}},
force_fresh=True,
)
assert providers[0]["name"].startswith("Nous Subscription")
assert ("features", True) in calls
def test_visible_providers_hide_nous_subscription_when_paid_access_is_false(monkeypatch):
config = {"model": {"provider": "nous"}}
monkeypatch.setattr(
"hermes_cli.nous_subscription.get_nous_portal_account_info",
lambda: NousPortalAccountInfo(
logged_in=True,
source="jwt",
fresh=False,
paid_service_access=True,
),
logged_in=True,
source="jwt",
fresh=False,
paid_service_access=False,
),
)
providers = _visible_providers(TOOL_CATEGORIES["browser"], config)
@ -612,7 +642,7 @@ def test_reconfigure_lists_enabled_web_without_existing_provider_config(monkeypa
monkeypatch.setattr(
"hermes_cli.tools_config._toolset_has_keys",
lambda ts_key, config=None: False,
lambda ts_key, config=None, **kwargs: False,
)
def fake_prompt_choice(question, choices, default=0):
@ -622,7 +652,7 @@ def test_reconfigure_lists_enabled_web_without_existing_provider_config(monkeypa
monkeypatch.setattr("hermes_cli.tools_config._prompt_choice", fake_prompt_choice)
monkeypatch.setattr(
"hermes_cli.tools_config._configure_tool_category_for_reconfig",
lambda ts_key, cat, config: configured.append(ts_key),
lambda ts_key, cat, config, **kwargs: configured.append(ts_key),
)
monkeypatch.setattr("hermes_cli.tools_config.save_config", lambda config: None)
@ -633,7 +663,6 @@ def test_reconfigure_lists_enabled_web_without_existing_provider_config(monkeypa
def test_first_install_nous_auto_configures_managed_defaults(monkeypatch):
monkeypatch.setattr("hermes_cli.tools_config.managed_nous_tools_enabled", lambda: True)
monkeypatch.setattr("hermes_cli.nous_subscription.managed_nous_tools_enabled", lambda: True)
config = {
"model": {"provider": "nous"},
@ -669,7 +698,7 @@ def test_first_install_nous_auto_configures_managed_defaults(monkeypatch):
)
monkeypatch.setattr(
"hermes_cli.nous_subscription.get_nous_portal_account_info",
lambda: NousPortalAccountInfo(
lambda *args, **kwargs: NousPortalAccountInfo(
logged_in=True,
source="jwt",
fresh=False,

View file

@ -71,6 +71,26 @@ class TestManagedNousToolsEnabled:
)
assert managed_nous_tools_enabled() is True
def test_force_fresh_is_forwarded(self, monkeypatch):
calls = []
def fake_account_info(*, force_fresh=False):
calls.append(force_fresh)
return NousPortalAccountInfo(
logged_in=True,
source="account_api",
fresh=True,
paid_service_access=True,
)
monkeypatch.setattr(
"hermes_cli.nous_account.get_nous_portal_account_info",
fake_account_info,
)
assert managed_nous_tools_enabled(force_fresh=True) is True
assert calls == [True]
def test_returns_false_on_exception(self, monkeypatch):
"""Should never crash — returns False on any exception."""
monkeypatch.setattr(