fix(hermes): preserve proven Claude authentication

This commit is contained in:
jenkins 2026-08-23 11:18:18 -03:00
parent 0682b2b813
commit 6b378fd410
2 changed files with 61 additions and 26 deletions

View File

@ -67,11 +67,6 @@ _auth_probe_value: dict[str, Any] = {}
HEALTH_POLL_SECONDS: Final = max( HEALTH_POLL_SECONDS: Final = max(
30, int(os.environ.get("HERMES_CLAUDE_HEALTH_POLL_SECONDS", "60")) 30, int(os.environ.get("HERMES_CLAUDE_HEALTH_POLL_SECONDS", "60"))
) )
AUTH_PROBE_GRACE_SECONDS: Final = max(
60, int(os.environ.get("HERMES_CLAUDE_AUTH_PROBE_GRACE_SECONDS", "300"))
)
def _read_secret(file_env_name: str) -> str: def _read_secret(file_env_name: str) -> str:
"""Read a secret only from its runtime-mounted file.""" """Read a secret only from its runtime-mounted file."""
path = os.environ.get(file_env_name, "").strip() path = os.environ.get(file_env_name, "").strip()
@ -296,32 +291,28 @@ def _subscription_health(force: bool = False) -> dict[str, Any]:
) )
api_provider = raw.get("apiProvider") if isinstance(raw, dict) else None api_provider = raw.get("apiProvider") if isinstance(raw, dict) else None
auth_method = raw.get("authMethod") if isinstance(raw, dict) else None auth_method = raw.get("authMethod") if isinstance(raw, dict) else None
# A concurrent inference can make Claude's secondary auth-status # Cold starts and concurrent inference can make Claude's secondary
# process time out or return no JSON. A real, recent inference is # auth-status process time out or return no JSON. Once this broker has
# stronger evidence than that inconclusive probe. Preserve the last # proven first-party access, only an explicit logged-out response or an
# proven-good auth state briefly, but never mask an explicit logged-out # authoritative inference auth failure may revoke that evidence.
# response from the CLI. # Otherwise periodic probe timeouts would repeatedly eject a working
recent_success = False # subscription from routing.
try: known_authenticated = bool(
last_success = datetime.fromisoformat( (
str(previous.get("last_success_at") or "").replace("Z", "+00:00") previous.get("authenticated") is True
and previous.get("api_provider") == "firstParty"
) )
if last_success.tzinfo is None: or previous.get("last_authenticated_at")
last_success = last_success.replace(tzinfo=timezone.utc) or previous.get("last_success_at")
age = (checked_time - last_success.astimezone(timezone.utc)).total_seconds() )
recent_success = 0 <= age <= AUTH_PROBE_GRACE_SECONDS
except (TypeError, ValueError):
pass
probe_stale = bool( probe_stale = bool(
not probe_conclusive not probe_conclusive
and recent_success and known_authenticated
and previous.get("authenticated") is True
and previous.get("api_provider") == "firstParty"
) )
if probe_stale: if probe_stale:
authenticated = True authenticated = True
api_provider = previous.get("api_provider") api_provider = previous.get("api_provider") or "firstParty"
auth_method = previous.get("auth_method") auth_method = previous.get("auth_method") or "oauth_token"
value = { value = {
"transport": "claude-code-cli-subscription", "transport": "claude-code-cli-subscription",
"state": "available" if authenticated else "unavailable", "state": "available" if authenticated else "unavailable",
@ -332,8 +323,16 @@ def _subscription_health(force: bool = False) -> dict[str, Any]:
"auth_probe_stale": probe_stale, "auth_probe_stale": probe_stale,
"subscription_type": raw.get("subscriptionType") "subscription_type": raw.get("subscriptionType")
if isinstance(raw, dict) if isinstance(raw, dict)
else None, else previous.get("subscription_type"),
} }
if authenticated:
value["last_authenticated_at"] = (
checked_at
if probe_conclusive
else previous.get("last_authenticated_at")
or previous.get("last_success_at")
or checked_at
)
# Readiness probes must not erase the most recently observed native # Readiness probes must not erase the most recently observed native
# usage window or successful route metadata. They only refresh auth. # usage window or successful route metadata. They only refresh auth.
for key in ( for key in (
@ -447,6 +446,11 @@ def _invoke(payload: dict[str, Any]) -> tuple[dict[str, Any], dict[str, int], st
health.update( health.update(
{ {
"state": "available", "state": "available",
"authenticated": True,
"api_provider": "firstParty",
"auth_method": "oauth_token",
"auth_probe_stale": False,
"last_authenticated_at": datetime.now(timezone.utc).isoformat(),
"last_success_at": datetime.now(timezone.utc).isoformat(), "last_success_at": datetime.now(timezone.utc).isoformat(),
"latency_ms": int((time.monotonic() - started) * 1000), "latency_ms": int((time.monotonic() - started) * 1000),
"model": actual_model, "model": actual_model,

View File

@ -154,6 +154,36 @@ def test_transient_auth_probe_keeps_recent_proven_access(monkeypatch, tmp_path)
assert health["auth_probe_stale"] is True assert health["auth_probe_stale"] is True
def test_transient_auth_probe_keeps_older_proven_access(monkeypatch, tmp_path) -> None:
module = _module(monkeypatch)
module.HEALTH_PATH = tmp_path / "claude.json"
module.HEALTH_PATH.write_text(
json.dumps(
{
"authenticated": False,
"last_success_at": "2026-01-01T00:00:00+00:00",
}
),
encoding="utf-8",
)
monkeypatch.setattr(
module.subprocess,
"run",
lambda *_args, **_kwargs: SimpleNamespace(
returncode=1, stdout="", stderr="transient timeout"
),
)
health = module._subscription_health(force=True)
assert health["authenticated"] is True
assert health["state"] == "available"
assert health["api_provider"] == "firstParty"
assert health["auth_method"] == "oauth_token"
assert health["auth_probe_stale"] is True
assert health["last_authenticated_at"] == "2026-01-01T00:00:00+00:00"
def test_explicit_logged_out_probe_clears_recent_access(monkeypatch, tmp_path) -> None: def test_explicit_logged_out_probe_clears_recent_access(monkeypatch, tmp_path) -> None:
module = _module(monkeypatch) module = _module(monkeypatch)
module.HEALTH_PATH = tmp_path / "claude.json" module.HEALTH_PATH = tmp_path / "claude.json"
@ -183,3 +213,4 @@ def test_explicit_logged_out_probe_clears_recent_access(monkeypatch, tmp_path) -
assert health["authenticated"] is False assert health["authenticated"] is False
assert health["state"] == "unavailable" assert health["state"] == "unavailable"
assert health["auth_probe_stale"] is False assert health["auth_probe_stale"] is False
assert "last_authenticated_at" not in health