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
|
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():
|
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,)
|
"pools were %r" % (pool_types,)
|
||||||
)
|
)
|
||||||
http_client.close()
|
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