chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
R3 LLM-broker tests: a request selects a provider BY NAME only; base_url and
|
||||
api_token are always server-derived, so the configured provider key can never
|
||||
be redirected to an attacker endpoint (the reported credential-exfil gadget).
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from llm_broker import resolve_llm, allowed_provider_families, LLMProviderNotAllowed
|
||||
|
||||
pytestmark = pytest.mark.posture
|
||||
|
||||
CONF = {"llm": {"provider": "openai/gpt-4o-mini"}}
|
||||
|
||||
|
||||
class TestProviderAllowlist:
|
||||
def test_default_provider_allowed(self):
|
||||
out = resolve_llm(CONF, None)
|
||||
assert out["provider"] == "openai/gpt-4o-mini"
|
||||
|
||||
def test_same_family_allowed(self):
|
||||
out = resolve_llm(CONF, "openai/gpt-4o")
|
||||
assert out["provider"] == "openai/gpt-4o"
|
||||
|
||||
def test_other_family_rejected(self):
|
||||
with pytest.raises(LLMProviderNotAllowed):
|
||||
resolve_llm(CONF, "anthropic/claude-3-opus")
|
||||
|
||||
def test_explicit_allowlist_widens(self):
|
||||
conf = {"llm": {"provider": "openai/gpt-4o-mini",
|
||||
"allowed_providers": ["anthropic/claude-3-opus"]}}
|
||||
assert resolve_llm(conf, "anthropic/claude-3-opus")["provider"].startswith("anthropic/")
|
||||
|
||||
|
||||
class TestBaseUrlIsServerOnly:
|
||||
def test_resolve_has_no_request_base_url_param(self):
|
||||
import inspect
|
||||
params = list(inspect.signature(resolve_llm).parameters)
|
||||
# only (config, requested_provider) - no way to inject base_url/api_token
|
||||
assert params == ["config", "requested_provider"]
|
||||
|
||||
def test_base_url_is_canonical_from_env(self, monkeypatch):
|
||||
monkeypatch.setenv("OPENAI_BASE_URL", "https://api.openai.example")
|
||||
out = resolve_llm(CONF, "openai/gpt-4o-mini")
|
||||
assert out["base_url"] == "https://api.openai.example"
|
||||
|
||||
def test_no_base_url_when_unset(self, monkeypatch):
|
||||
monkeypatch.delenv("OPENAI_BASE_URL", raising=False)
|
||||
monkeypatch.delenv("LLM_BASE_URL", raising=False)
|
||||
out = resolve_llm(CONF, "openai/gpt-4o-mini")
|
||||
assert out["base_url"] is None
|
||||
|
||||
|
||||
class TestRequestSurfaceRemoved:
|
||||
def test_markdown_request_has_no_base_url(self):
|
||||
from schemas import MarkdownRequest
|
||||
assert "base_url" not in MarkdownRequest.model_fields
|
||||
|
||||
def test_llm_job_payload_has_no_base_url(self):
|
||||
from job import LlmJobPayload
|
||||
assert "base_url" not in LlmJobPayload.model_fields
|
||||
|
||||
def test_llm_endpoint_has_no_base_url_query(self, server_module):
|
||||
import inspect
|
||||
assert "base_url" not in inspect.signature(server_module.llm_endpoint).parameters
|
||||
|
||||
def test_md_endpoint_rejects_disallowed_provider(self, stock_client, server_module):
|
||||
from auth import create_access_token
|
||||
h = {"Authorization": f"Bearer {create_access_token({'sub': 'u@x.com'})}"}
|
||||
# LLM filter + a provider outside the allowed family -> 400 (not a 500,
|
||||
# and no LLM call to an attacker endpoint).
|
||||
r = stock_client.post(
|
||||
"/md",
|
||||
json={"url": "https://example.com", "f": "llm", "provider": "attacker/model",
|
||||
"base_url": "http://169.254.169.254"},
|
||||
headers=h,
|
||||
)
|
||||
assert r.status_code == 400, r.status_code
|
||||
Reference in New Issue
Block a user