fix: complete OAuth-UA salvage follow-up (stale comment + test keychain isolation)
Some checks are pending
CI / Detect affected areas (push) Waiting to run
CI / Python tests (push) Blocked by required conditions
CI / Python lints (push) Blocked by required conditions
CI / TypeScript (push) Blocked by required conditions
CI / Docs Site (push) Blocked by required conditions
CI / Deny unrelated histories (push) Blocked by required conditions
CI / Check contributors (push) Blocked by required conditions
CI / Check uv.lock (push) Blocked by required conditions
CI / Lint Docker scripts (push) Blocked by required conditions
CI / Build&Test Docker image (push) Blocked by required conditions
CI / Supply-chain scan (push) Blocked by required conditions
CI / OSV scan (push) Waiting to run
CI / All required checks pass (push) Blocked by required conditions
CI / CI timing report (push) Blocked by required conditions
Deploy Site / deploy-vercel (push) Waiting to run
Deploy Site / deploy-docs (push) Waiting to run

Two review findings on the #57922 salvage:

1. Stale inline comment at the login-exchange site still claimed the token
   endpoint uses the claude-code/ UA prefix and 404s claude-cli/ — now
   contradicts the axios/ fix. Repointed it at _OAUTH_TOKEN_USER_AGENT.

2. The inherited Path.home test isolation on the three TestRefreshOauthToken
   tests only stubbed the ~/.claude *file* source, not the macOS Keychain.
   _refresh_oauth_token re-reads read_claude_code_credentials() (keychain
   first) in its adopt-already-refreshed branch, so on any macOS dev/CI runner
   with real Claude Code creds the branch short-circuits and the 3 tests fail.
   Stub read_claude_code_credentials -> None so the tests are hermetic.

(The remaining TestResolveAnthropicToken/TestResolveWithRefresh/TestRunOauthSetupToken
failures on macOS are the same pre-existing keychain-leak class on origin/main,
unrelated to this OAuth-UA fix, and pass in CI — left out of scope.)
This commit is contained in:
kshitijk4poor 2026-07-04 15:10:28 +05:30 committed by kshitij
parent 4c5b4417bb
commit 09693cd3a3
2 changed files with 15 additions and 2 deletions

View file

@ -1488,8 +1488,9 @@ def run_hermes_oauth_login_pure() -> Optional[Dict[str, Any]]:
# Anthropic migrated the OAuth token endpoint to platform.claude.com;
# console.anthropic.com now 404s. Try the new host first, then fall
# back to console for older deployments (mirrors the refresh path).
# Use the claude-code/ UA prefix: Anthropic blocks claude-cli/ on the
# OAuth token endpoint (returns 404 for all versions).
# UA is _OAUTH_TOKEN_USER_AGENT (a non-claude-code UA) — see the
# constant's definition for why the token endpoint must not send
# claude-code/ (429 UA-prefix block).
result = None
last_error = None
for endpoint in _OAUTH_TOKEN_URLS:

View file

@ -509,11 +509,20 @@ class TestResolveAnthropicToken:
class TestRefreshOauthToken:
def test_returns_none_without_refresh_token(self, tmp_path, monkeypatch):
monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path)
# Neutralize live Claude Code sources (macOS Keychain + ~/.claude file)
# so the adopt-already-refreshed branch can't short-circuit with a real
# credential on a dev/CI machine that happens to have Claude Code creds.
monkeypatch.setattr(
"agent.anthropic_adapter.read_claude_code_credentials", lambda: None
)
creds = {"accessToken": "expired", "refreshToken": "", "expiresAt": 0}
assert _refresh_oauth_token(creds) is None
def test_successful_refresh(self, tmp_path, monkeypatch):
monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path)
monkeypatch.setattr(
"agent.anthropic_adapter.read_claude_code_credentials", lambda: None
)
creds = {
"accessToken": "old-token",
@ -547,6 +556,9 @@ class TestRefreshOauthToken:
def test_failed_refresh_returns_none(self, tmp_path, monkeypatch):
monkeypatch.setattr("agent.anthropic_adapter.Path.home", lambda: tmp_path)
monkeypatch.setattr(
"agent.anthropic_adapter.read_claude_code_credentials", lambda: None
)
creds = {
"accessToken": "old",
"refreshToken": "refresh-123",