mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
test(proxy): regression tests for NO_PROXY bypass on keepalive client
Pin the behaviour added in the preceding commit — `_get_proxy_for_base_url()` must return None for hosts covered by NO_PROXY and the HTTPS_PROXY otherwise, and the full `_create_openai_client()` path must NOT mount HTTPProxy for a NO_PROXY host. Refs: #14966
This commit is contained in:
parent
cbc39a8672
commit
166b960fe4
1 changed files with 76 additions and 1 deletions
|
|
@ -22,7 +22,7 @@ from unittest.mock import patch
|
|||
|
||||
import httpx
|
||||
|
||||
from run_agent import AIAgent, _get_proxy_from_env
|
||||
from run_agent import AIAgent, _get_proxy_from_env, _get_proxy_for_base_url
|
||||
|
||||
|
||||
def _make_agent():
|
||||
|
|
@ -143,3 +143,78 @@ def test_create_openai_client_no_proxy_when_env_unset(mock_openai, monkeypatch):
|
|||
"pools were %r" % (pool_types,)
|
||||
)
|
||||
http_client.close()
|
||||
|
||||
|
||||
def test_get_proxy_for_base_url_returns_none_when_host_bypassed(monkeypatch):
|
||||
"""NO_PROXY must suppress the proxy for matching base_urls.
|
||||
|
||||
Regression for #14966: users running a local inference endpoint
|
||||
(Ollama, LM Studio, llama.cpp) with a global HTTPS_PROXY would see
|
||||
the keepalive client route loopback traffic through the proxy, which
|
||||
typically answers 502 for local hosts. NO_PROXY should opt those
|
||||
hosts out via stdlib ``urllib.request.proxy_bypass_environment``.
|
||||
"""
|
||||
for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY",
|
||||
"https_proxy", "http_proxy", "all_proxy",
|
||||
"NO_PROXY", "no_proxy"):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:7897")
|
||||
monkeypatch.setenv("NO_PROXY", "localhost,127.0.0.1,192.168.0.0/16")
|
||||
|
||||
# Local endpoint — must bypass the proxy.
|
||||
assert _get_proxy_for_base_url("http://127.0.0.1:11434/v1") is None
|
||||
assert _get_proxy_for_base_url("http://localhost:1234/v1") is None
|
||||
|
||||
# Non-local endpoint — proxy still applies.
|
||||
assert _get_proxy_for_base_url("https://api.openai.com/v1") == "http://127.0.0.1:7897"
|
||||
|
||||
|
||||
def test_get_proxy_for_base_url_returns_proxy_when_no_proxy_unset(monkeypatch):
|
||||
for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY",
|
||||
"https_proxy", "http_proxy", "all_proxy",
|
||||
"NO_PROXY", "no_proxy"):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://corp:8080")
|
||||
assert _get_proxy_for_base_url("http://127.0.0.1:11434/v1") == "http://corp:8080"
|
||||
|
||||
|
||||
def test_get_proxy_for_base_url_returns_none_when_proxy_unset(monkeypatch):
|
||||
for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY",
|
||||
"https_proxy", "http_proxy", "all_proxy",
|
||||
"NO_PROXY", "no_proxy"):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
monkeypatch.setenv("NO_PROXY", "localhost,127.0.0.1")
|
||||
assert _get_proxy_for_base_url("http://127.0.0.1:11434/v1") is None
|
||||
assert _get_proxy_for_base_url("https://api.openai.com/v1") is None
|
||||
|
||||
|
||||
@patch("run_agent.OpenAI")
|
||||
def test_create_openai_client_bypasses_proxy_for_no_proxy_host(mock_openai, monkeypatch):
|
||||
"""E2E: with HTTPS_PROXY + NO_PROXY=localhost, a local base_url gets a
|
||||
keepalive client with NO HTTPProxy mount."""
|
||||
for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY",
|
||||
"https_proxy", "http_proxy", "all_proxy",
|
||||
"NO_PROXY", "no_proxy"):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:7897")
|
||||
monkeypatch.setenv("NO_PROXY", "localhost,127.0.0.1")
|
||||
|
||||
agent = _make_agent()
|
||||
kwargs = {
|
||||
"api_key": "***",
|
||||
"base_url": "http://127.0.0.1:11434/v1",
|
||||
}
|
||||
agent._create_openai_client(kwargs, reason="test", shared=False)
|
||||
|
||||
forwarded = mock_openai.call_args.kwargs
|
||||
http_client = _extract_http_client(forwarded)
|
||||
assert isinstance(http_client, httpx.Client)
|
||||
pool_types = [
|
||||
type(mount._pool).__name__
|
||||
for mount in http_client._mounts.values()
|
||||
if mount is not None and hasattr(mount, "_pool")
|
||||
]
|
||||
assert "HTTPProxy" not in pool_types, (
|
||||
"NO_PROXY host must not route through HTTPProxy; pools were %r" % (pool_types,)
|
||||
)
|
||||
http_client.close()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue