fix(auth): heal poisoned Nous inference URL on refresh instead of retaining it

A nous inference_base_url that fails the host allowlist (e.g. a stale
stg-inference-api.nousresearch.com persisted before the allowlist
existed) was only replaced 'if refreshed_url:' — so when the validator
rejected the URL it left the poisoned value in place. The 'falling back
to default' warning fired but never took effect: every subsequent call,
including the auxiliary compression call, kept hitting the dead staging
endpoint and 401'd.

Reset to DEFAULT_NOUS_INFERENCE_URL when validation returns None at both
refresh sites in resolve_nous_runtime_credentials, so a poisoned
auth.json self-heals on the next refresh. The proxy adapter already did
this correctly; this brings the two auth.py sites in line.
This commit is contained in:
teknium1 2026-06-20 10:41:53 -07:00 committed by Teknium
parent 92d40c2553
commit 37a4dd4982
2 changed files with 94 additions and 4 deletions

View file

@ -5430,9 +5430,15 @@ def refresh_nous_oauth_pure(
state["refresh_token"] = refreshed.get("refresh_token") or refresh_token_value
state["token_type"] = refreshed.get("token_type") or state.get("token_type") or "Bearer"
state["scope"] = refreshed.get("scope") or state.get("scope")
# Heal a poisoned stored value: when the Portal-returned URL is
# rejected by the allowlist (returns None), reset to the production
# default instead of leaving a previously-persisted bad host (e.g. a
# stale staging URL) in place. Without this reset, an auth.json that
# was poisoned before the allowlist existed keeps re-validating to
# None on every refresh and silently re-uses the dead endpoint —
# the "falling back to default" warning never actually takes effect.
refreshed_url = _validate_nous_inference_url_from_network(refreshed.get("inference_base_url"))
if refreshed_url:
state["inference_base_url"] = refreshed_url
state["inference_base_url"] = refreshed_url or DEFAULT_NOUS_INFERENCE_URL
state["obtained_at"] = now.isoformat()
state["expires_in"] = access_ttl
state["expires_at"] = datetime.fromtimestamp(
@ -5705,9 +5711,13 @@ def resolve_nous_runtime_credentials(
state["refresh_token"] = refreshed.get("refresh_token") or refresh_token
state["token_type"] = refreshed.get("token_type") or state.get("token_type") or "Bearer"
state["scope"] = refreshed.get("scope") or state.get("scope")
# Heal a poisoned stored value (see refresh_nous_oauth_pure):
# reject → reset to production default, don't keep a stale
# staging host that re-validates to None every refresh.
# The local inference_base_url is persisted to state below
# (and used for the client), so healing it here suffices.
refreshed_url = _validate_nous_inference_url_from_network(refreshed.get("inference_base_url"))
if refreshed_url:
inference_base_url = refreshed_url
inference_base_url = refreshed_url or DEFAULT_NOUS_INFERENCE_URL
state["obtained_at"] = now.isoformat()
state["expires_in"] = access_ttl
state["expires_at"] = datetime.fromtimestamp(

View file

@ -211,3 +211,83 @@ class TestEnvOverrideNotGated:
"env override path must not gate through the network "
"validator — it would break documented dev/staging use."
)
class TestHealsPoisonedStoredValue:
"""A stored inference_base_url that is NOT in the allowlist (e.g. a
stale ``stg-inference-api.nousresearch.com`` persisted before the
allowlist existed) must be HEALED back to the production default on
the next refresh not silently retained.
Before the fix, the refresh sites only assigned the validated URL
``if refreshed_url:`` and otherwise left the poisoned value in place,
so the "falling back to default" warning was logged but never
actually took effect every subsequent call kept hitting the dead
staging endpoint (real incident: opus-4.8 routed to nous, nous pinned
to staging, every request + the aux compression call 401'd).
"""
def test_refresh_resets_rejected_url_to_default(self, monkeypatch):
import hermes_cli.auth as auth
poisoned = "https://stg-inference-api.nousresearch.com/v1"
state = {
"access_token": "tok",
"refresh_token": "rtok",
"client_id": "hermes-cli",
"portal_base_url": auth.DEFAULT_NOUS_PORTAL_URL,
"inference_base_url": poisoned,
}
# Force the refresh branch and return another rejected (staging) URL,
# exercising the validator-returns-None heal path.
monkeypatch.setattr(auth, "_nous_invoke_jwt_status", lambda *a, **k: "needs_refresh")
monkeypatch.setattr(
auth,
"_refresh_access_token",
lambda **k: {
"access_token": "newtok",
"refresh_token": "newrtok",
"expires_in": 3600,
"inference_base_url": poisoned, # Portal still hands back staging
},
)
# Skip the JWT usability assertions (orthogonal to URL healing).
monkeypatch.setattr(auth, "_assert_nous_inference_jwt_usable", lambda *a, **k: None)
monkeypatch.setattr(auth, "_select_nous_invoke_jwt", lambda *a, **k: None)
result = auth.refresh_nous_oauth_from_state(state, force_refresh=True)
assert result["inference_base_url"] == auth.DEFAULT_NOUS_INFERENCE_URL, (
"rejected Portal URL must heal to the production default, "
f"got {result['inference_base_url']!r}"
)
def test_refresh_keeps_valid_url(self, monkeypatch):
"""A legitimate allowlisted URL from the Portal is preserved."""
import hermes_cli.auth as auth
good = "https://inference-api.nousresearch.com/v1"
state = {
"access_token": "tok",
"refresh_token": "rtok",
"client_id": "hermes-cli",
"portal_base_url": auth.DEFAULT_NOUS_PORTAL_URL,
"inference_base_url": good,
}
monkeypatch.setattr(auth, "_nous_invoke_jwt_status", lambda *a, **k: "needs_refresh")
monkeypatch.setattr(
auth,
"_refresh_access_token",
lambda **k: {
"access_token": "newtok",
"refresh_token": "newrtok",
"expires_in": 3600,
"inference_base_url": good,
},
)
monkeypatch.setattr(auth, "_assert_nous_inference_jwt_usable", lambda *a, **k: None)
monkeypatch.setattr(auth, "_select_nous_invoke_jwt", lambda *a, **k: None)
result = auth.refresh_nous_oauth_from_state(state, force_refresh=True)
assert result["inference_base_url"] == good