mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(terminal): stop stripping CLAUDE_CODE_OAUTH_TOKEN from spawned subprocesses (#56935)
CLAUDE_CODE_OAUTH_TOKEN is set and owned by the user's Claude Code install (subscription OAuth), not a Hermes-managed inference credential — Claude subscription auth is not a working Hermes provider path. Blocklisting it broke agent-spawned claude CLIs: with no token in the child env, claude fell through to the shared macOS Keychain / ~/.claude/.credentials.json store and, on auth failure, cleared it — logging the user out of their interactive Claude sessions and the desktop app. Exempt it from _HERMES_PROVIDER_ENV_BLOCKLIST (it arrives via the anthropic registry entry, so discard explicitly with rationale). ANTHROPIC_API_KEY / ANTHROPIC_TOKEN and every other provider credential remain stripped, and the GHSA-rhgp-j443-p4rf fail-closed passthrough guard is unchanged for everything still on the blocklist. Fixes #55878
This commit is contained in:
parent
8b1ad38ecb
commit
14639ded77
2 changed files with 29 additions and 6 deletions
|
|
@ -80,7 +80,6 @@ class TestProviderEnvBlocklist:
|
|||
must also be blocked — not just the hand-written extras."""
|
||||
registry_vars = {
|
||||
"ANTHROPIC_TOKEN": "ant-tok",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": "cc-tok",
|
||||
"ZAI_API_KEY": "zai-key",
|
||||
"Z_AI_API_KEY": "z-ai-key",
|
||||
"GLM_API_KEY": "glm-key",
|
||||
|
|
@ -326,11 +325,18 @@ class TestBlocklistCoverage:
|
|||
|
||||
def test_registry_vars_are_in_blocklist(self):
|
||||
"""Every api_key_env_var and base_url_env_var from PROVIDER_REGISTRY
|
||||
must appear in the blocklist — ensures no drift."""
|
||||
must appear in the blocklist — ensures no drift.
|
||||
|
||||
CLAUDE_CODE_OAUTH_TOKEN is the one deliberate exemption: it is owned
|
||||
by the user's Claude Code install, not Hermes (#55878).
|
||||
"""
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
|
||||
exempt = {"CLAUDE_CODE_OAUTH_TOKEN"}
|
||||
for pconfig in PROVIDER_REGISTRY.values():
|
||||
for var in pconfig.api_key_env_vars:
|
||||
if var in exempt:
|
||||
continue
|
||||
assert var in _HERMES_PROVIDER_ENV_BLOCKLIST, (
|
||||
f"Registry var {var} (provider={pconfig.id}) missing from blocklist"
|
||||
)
|
||||
|
|
@ -371,11 +377,19 @@ class TestBlocklistCoverage:
|
|||
)
|
||||
|
||||
def test_extra_auth_vars_covered(self):
|
||||
"""Non-registry auth vars (ANTHROPIC_TOKEN, CLAUDE_CODE_OAUTH_TOKEN)
|
||||
must also be in the blocklist."""
|
||||
extras = {"ANTHROPIC_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN"}
|
||||
"""Non-registry auth vars (ANTHROPIC_TOKEN) must also be in the
|
||||
blocklist."""
|
||||
extras = {"ANTHROPIC_TOKEN"}
|
||||
assert extras.issubset(_HERMES_PROVIDER_ENV_BLOCKLIST)
|
||||
|
||||
def test_claude_code_oauth_token_is_inheritable(self):
|
||||
"""CLAUDE_CODE_OAUTH_TOKEN is owned by the user's Claude Code install
|
||||
(subscription OAuth), not a Hermes inference credential. Stripping it
|
||||
made agent-spawned ``claude`` fall through to the shared Keychain /
|
||||
~/.claude credential store and clobber the user's interactive login
|
||||
on auth failure (#55878). It must stay inheritable."""
|
||||
assert "CLAUDE_CODE_OAUTH_TOKEN" not in _HERMES_PROVIDER_ENV_BLOCKLIST
|
||||
|
||||
def test_non_registry_provider_vars_are_in_blocklist(self):
|
||||
extras = {
|
||||
"GOOGLE_API_KEY",
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ def _build_provider_env_blocklist() -> frozenset:
|
|||
"ANTHROPIC_BASE_URL",
|
||||
"ANTHROPIC_API_KEY",
|
||||
"ANTHROPIC_TOKEN",
|
||||
"CLAUDE_CODE_OAUTH_TOKEN",
|
||||
"LLM_MODEL",
|
||||
"GOOGLE_API_KEY",
|
||||
# Path to a GCP service-account JSON, not a bare key, so
|
||||
|
|
@ -212,6 +211,16 @@ def _build_provider_env_blocklist() -> frozenset:
|
|||
"GATEWAY_RELAY_SECRET",
|
||||
"GATEWAY_RELAY_DELIVERY_KEY",
|
||||
})
|
||||
# CLAUDE_CODE_OAUTH_TOKEN is deliberately NOT stripped. It is set and
|
||||
# owned by the user's Claude Code install (subscription OAuth), not a
|
||||
# Hermes-managed inference credential — Claude subscription auth is not a
|
||||
# working Hermes provider path. Stripping it broke agent-spawned
|
||||
# ``claude`` CLIs: the child fell through to the shared macOS Keychain /
|
||||
# ``~/.claude/.credentials.json`` store and, on auth failure, cleared it,
|
||||
# logging the user out of their interactive Claude sessions (#55878).
|
||||
# It arrives via the registry loop above (anthropic api_key_env_vars),
|
||||
# so remove it explicitly.
|
||||
blocked.discard("CLAUDE_CODE_OAUTH_TOKEN")
|
||||
return frozenset(blocked)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue