fix(providers): recognize OpenAI data-residency hosts via one shared predicate

Pointing openai-api at OpenAI's documented regional hosts
(us.api.openai.com / eu.api.openai.com, mandatory for customers with
data-residency obligations) silently degraded Hermes because three
subsystems tested 'is this OpenAI' with exact-hostname equality against
api.openai.com.

Adds providers.is_official_openai_host(): canonical host plus dot-suffix
subdomains of api.openai.com, hostname-parsed only. Lookalike hosts
(api.openai.com.attacker.test) and path spoofs (proxy.test/api.openai.com/v1)
stay rejected, preserving the #32243 hardening: a genuine *.api.openai.com
subdomain requires control of openai.com DNS.

host_mandated_api_mode() now routes through the predicate, so regional
hosts mandate codex_responses exactly like the canonical host.
This commit is contained in:
Victor Kyriazakos 2026-07-30 19:03:32 +00:00 committed by Teknium
parent dc87d15586
commit 564e9b90af
2 changed files with 81 additions and 1 deletions

View File

@ -578,6 +578,25 @@ def is_routing_aggregator(provider: str) -> bool:
return is_aggregator(provider_norm)
def is_official_openai_host(base_url: str) -> bool:
"""True when *base_url* points at OpenAI's official API host family.
Matches the canonical host (``api.openai.com``) and OpenAI's documented
data-residency / regional hosts (``us.api.openai.com``,
``eu.api.openai.com``, and any future ``<region>.api.openai.com``)
those serve the same API surface with the same transport requirements
and the same access-scoped ``/v1/models`` listing.
Hostname-parsed matching only never substring so lookalike hosts
(``api.openai.com.attacker.test``) and path-segment spoofs
(``proxy.test/api.openai.com/v1``) are rejected. A genuine
``*.api.openai.com`` subdomain requires control of openai.com DNS, so
the dot-suffix match does not reopen the #32243 spoofing hole.
"""
hostname = base_url_hostname(base_url)
return hostname == "api.openai.com" or hostname.endswith(".api.openai.com")
def host_mandated_api_mode(base_url: str = "") -> Optional[str]:
"""Return the wire protocol a specific endpoint *requires*, or None.
@ -605,7 +624,11 @@ def host_mandated_api_mode(base_url: str = "") -> Optional[str]:
return "anthropic_messages"
if hostname == "api.anthropic.com" or url_lower.endswith("/anthropic"):
return "anthropic_messages"
if hostname == "api.openai.com":
# Official OpenAI host family: canonical + data-residency regional hosts
# (us./eu.api.openai.com) all mandate the Responses API for reasoning
# models with tools. Shared predicate keeps this lane in lockstep with
# catalog filtering and listing authority.
if is_official_openai_host(base_url):
return "codex_responses"
if hostname.startswith("bedrock-runtime.") and base_url_host_matches(base_url, "amazonaws.com"):
return "bedrock_converse"

View File

@ -0,0 +1,57 @@
"""Security + parity contract for ``is_official_openai_host``.
One predicate decides "is this endpoint OpenAI's official API surface?"
for every lane that branches on it: transport mandates
(``host_mandated_api_mode``), URL auto-detection in the runtime resolver,
model-catalog filtering, and live-listing authority. OpenAI's documented
data-residency hosts (``us.api.openai.com``, ``eu.api.openai.com``, and any
future ``<region>.api.openai.com``) are the same API surface as the
canonical host and must match; lookalike/spoof hosts must not (#32243).
"""
from __future__ import annotations
import pytest
from hermes_cli.providers import is_official_openai_host
class TestOfficialHosts:
@pytest.mark.parametrize(
"url",
[
"https://api.openai.com/v1",
"https://api.openai.com",
"https://us.api.openai.com/v1",
"https://eu.api.openai.com/v1",
"https://US.api.OpenAI.com/v1", # case-insensitive hostname
"https://in.api.openai.com/v1", # future regional variants
],
)
def test_official_hosts_match(self, url):
assert is_official_openai_host(url) is True
class TestSpoofRejection:
@pytest.mark.parametrize(
"url",
[
# Lookalike host suffix: registrable domain is attacker.test.
"https://api.openai.com.attacker.test/v1",
"https://us.api.openai.com.attacker.test/v1",
# Path-segment spoofing: host is proxy.test.
"https://proxy.test/api.openai.com/v1",
"https://proxy.test/us.api.openai.com/v1",
# Prefix tricks that are NOT dot-separated subdomains of
# api.openai.com (fooapi.openai.com is an openai.com host but
# not the official API host family this predicate is scoped to).
"https://evilapi.openai.com.attacker.test/v1",
"https://fooapi.openai.com/v1",
# Unrelated hosts.
"https://openrouter.ai/api/v1",
"https://api.anthropic.com/v1",
"",
],
)
def test_spoof_and_unrelated_hosts_rejected(self, url):
assert is_official_openai_host(url) is False