Forráskód Böngészése

fix: validate benchmark urls with httpx

Problem: BenchmarkTarget accepted printable IDNA and IP host forms that the production httpx transport rejects, delaying failure until client construction.

Risk: Transport-compatible validation could reject supported Unicode hosts or weaken existing port checks; regression coverage preserves httpx-accepted Unicode URLs and rejects invalid IDNA, IP literal, textual port, and out-of-range port forms.
zhenyu.hu 2 hete
szülő
commit
a5569f70bc
2 módosított fájl, 27 hozzáadás és 1 törlés
  1. 6 1
      src/agent_lab/application/benchmark.py
  2. 21 0
      tests/test_benchmark_config.py

+ 6 - 1
src/agent_lab/application/benchmark.py

@@ -5,6 +5,7 @@ from types import MappingProxyType
 from typing import Literal, TypeAlias
 from urllib.parse import urlsplit
 
+import httpx
 from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
 
 from agent_lab.application.contracts import (
@@ -72,7 +73,6 @@ def _validate_base_url(value: str) -> str:
     try:
         parsed = urlsplit(value)
         hostname = parsed.hostname
-        parsed.port
     except ValueError as exc:
         raise ValueError("base_url must be a valid HTTP(S) URL") from exc
     if parsed.scheme not in {"http", "https"} or not parsed.netloc or not hostname:
@@ -83,6 +83,11 @@ def _validate_base_url(value: str) -> str:
         raise ValueError("base_url must not contain a query")
     if "#" in value:
         raise ValueError("base_url must not contain a fragment")
+    try:
+        transport_url = httpx.URL(value)
+        _ = (transport_url.host, transport_url.port, parsed.port)
+    except (httpx.InvalidURL, ValueError) as exc:
+        raise ValueError("base_url must be a valid HTTP(S) URL") from exc
     return value
 
 

+ 21 - 0
tests/test_benchmark_config.py

@@ -82,6 +82,27 @@ def test_benchmark_config_rejects_unsafe_or_non_http_base_urls(base_url: str):
         BenchmarkConfig.model_validate(payload)
 
 
+@pytest.mark.parametrize(
+    "base_url",
+    [
+        pytest.param("https://🚀.example/v1", id="invalid-idna-host"),
+        pytest.param("https://xn--.example/v1", id="malformed-a-label"),
+        pytest.param(
+            "https://provider.example:not-a-port/v1",
+            id="invalid-port",
+        ),
+        pytest.param(
+            "https://provider.example:65536/v1",
+            id="out-of-range-port",
+        ),
+        pytest.param("https://[v1.invalid]/v1", id="invalid-ip-literal"),
+    ],
+)
+def test_benchmark_target_rejects_urls_incompatible_with_httpx(base_url: str):
+    with pytest.raises(ValidationError, match="base_url"):
+        BenchmarkTarget(base_url=base_url, model="benchmark-model")
+
+
 @pytest.mark.parametrize(
     "character",
     [