fix(cli): /config displays the live agent credential, not the env-var constructor seed

This commit is contained in:
Teknium
2026-08-19 17:39:49 -07:00
parent b035036582
commit f4a866b484
3 changed files with 68 additions and 5 deletions
+15 -3
View File
@@ -9246,10 +9246,22 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
# ``self.api_key`` may be a callable (Azure Foundry Entra ID bearer
# provider). Never invoke it; just identify the auth surface.
from agent.azure_identity_adapter import is_token_provider
if is_token_provider(self.api_key):
# Prefer the LIVE agent's credential when one exists: HermesCLI's
# constructor seeds self.api_key from OPENAI/OPENROUTER env vars
# before provider resolution runs, so on non-OpenAI providers (Nous,
# Anthropic, ...) the constructor value is a different vendor's key
# than the one actually authenticating requests. /config displaying
# an sk-proj-... OpenAI key next to a Nous base URL was the visible
# symptom (full-surface CLI QA sweep, Aug 2026).
display_key = self.api_key
agent = getattr(self, "agent", None)
if agent is not None and getattr(agent, "api_key", None):
display_key = agent.api_key
if is_token_provider(display_key):
api_key_display = "Microsoft Entra ID"
elif isinstance(self.api_key, str) and len(self.api_key) > 12:
api_key_display = f"{self.api_key[:8]}...{self.api_key[-4:]}"
elif isinstance(display_key, str) and len(display_key) > 12:
api_key_display = f"{display_key[:8]}...{display_key[-4:]}"
else:
api_key_display = "Not set!"
+51
View File
@@ -0,0 +1,51 @@
"""Regression test: /config must show the LIVE agent credential.
HermesCLI.__init__ seeds ``self.api_key`` from OPENAI_API_KEY /
OPENROUTER_API_KEY env vars before provider resolution runs. On any
non-OpenAI provider (Nous, Anthropic, ...) the constructor value is a
different vendor's key than the one actually used for requests, so
``/config`` displayed e.g. an ``sk-proj-...`` OpenAI key next to a Nous
base URL. ``show_config`` must prefer ``self.agent.api_key`` when an
agent exists.
"""
from datetime import datetime
from types import SimpleNamespace
from cli import HermesCLI
def _run_show_config(stand_in, capsys):
HermesCLI.show_config(stand_in)
return capsys.readouterr().out
def _make_stand_in(cli_key, agent_key):
agent = SimpleNamespace(api_key=agent_key) if agent_key is not None else None
return SimpleNamespace(
api_key=cli_key,
agent=agent,
model="test/model",
base_url="https://example.invalid/v1",
enabled_toolsets=[],
max_turns=5,
verbose=False,
session_start=datetime(2026, 8, 19, 12, 0, 0),
)
class TestShowConfigCredentialSource:
def test_prefers_live_agent_key(self, capsys):
out = _run_show_config(
_make_stand_in(cli_key="sk-proj-WRONGVENDORKEY1234", agent_key="nous-REALKEY-abcdef9876"),
capsys,
)
assert "nous-REA" in out
assert "sk-proj-" not in out
def test_falls_back_to_cli_key_without_agent(self, capsys):
out = _run_show_config(
_make_stand_in(cli_key="sk-proj-CONSTRUCTORKEY5678", agent_key=None),
capsys,
)
assert "sk-proj-" in out
+2 -2
View File
@@ -302,8 +302,8 @@ class TestInlinedDisplayMasks:
from pathlib import Path
src = (Path(__file__).resolve().parent.parent.parent
/ "cli.py").read_text()
assert "is_token_provider(self.api_key)" in src, (
"cli.HermesCLI.show_config must guard self.api_key via "
assert "is_token_provider(display_key)" in src, (
"cli.HermesCLI.show_config must guard the displayed key via "
"is_token_provider so callable Entra ID providers don't "
"crash /config."
)