fix(ai): confine benchmark requests
Disable proxy discovery and redirect following so validated Ollama origins cannot escape the approved network boundary. Run the standard-library safety suite in CI.
This commit is contained in:
@@ -37,6 +37,11 @@ jobs:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: job-tracker-ui/package-lock.json
|
||||
|
||||
- name: Test repository safety scripts
|
||||
# Standard-library only and plan-only: this validates the synthetic benchmark harness
|
||||
# without contacting Ollama, pulling a model, or requiring package installation.
|
||||
run: python3 scripts/test-ollama-evaluation.py
|
||||
|
||||
- name: Build backend
|
||||
run: dotnet build JobTrackerApi/JobTrackerApi.csproj --configuration Release
|
||||
|
||||
|
||||
@@ -40,6 +40,22 @@ TASK_INSTRUCTIONS = {
|
||||
}
|
||||
|
||||
|
||||
class NoRedirectHandler(urllib.request.HTTPRedirectHandler):
|
||||
"""Keep a validated Ollama origin from redirecting a request elsewhere."""
|
||||
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl): # noqa: ANN001
|
||||
return None
|
||||
|
||||
|
||||
def build_http_opener() -> urllib.request.OpenerDirector:
|
||||
# Do not inherit HTTP(S)_PROXY from the operator shell and never follow redirects. The
|
||||
# explicitly validated loopback/private origin is the only network boundary this tool may use.
|
||||
return urllib.request.build_opener(urllib.request.ProxyHandler({}), NoRedirectHandler())
|
||||
|
||||
|
||||
HTTP_OPENER = build_http_opener()
|
||||
|
||||
|
||||
def sha256_text(value: str) -> str:
|
||||
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
||||
|
||||
@@ -115,7 +131,7 @@ def request_json(base_url: str, path: str, payload: dict[str, Any] | None = None
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="GET" if data is None else "POST",
|
||||
)
|
||||
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||
with HTTP_OPENER.open(request, timeout=timeout) as response:
|
||||
return json.loads(response.read().decode("utf-8"))
|
||||
|
||||
|
||||
@@ -130,7 +146,7 @@ def stream_generate(base_url: str, payload: dict[str, Any], timeout: float) -> t
|
||||
first_token_at: float | None = None
|
||||
parts: list[str] = []
|
||||
final: dict[str, Any] = {}
|
||||
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||
with HTTP_OPENER.open(request, timeout=timeout) as response:
|
||||
for raw_line in response:
|
||||
if not raw_line.strip():
|
||||
continue
|
||||
|
||||
@@ -4,7 +4,9 @@ import importlib.util
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
|
||||
SCRIPT = Path(__file__).with_name("run-ollama-evaluation.py")
|
||||
@@ -54,6 +56,13 @@ class OllamaEvaluationTests(unittest.TestCase):
|
||||
MODULE.validate_base_url("http://ollama:11434", True)
|
||||
self.assertEqual("http://192.168.1.20:11434", MODULE.validate_base_url("http://192.168.1.20:11434", True))
|
||||
|
||||
def test_http_opener_disables_proxies_and_redirects(self):
|
||||
with mock.patch.object(urllib.request, "getproxies", side_effect=AssertionError("proxy discovery must stay disabled")):
|
||||
opener = MODULE.build_http_opener()
|
||||
self.assertFalse(any(isinstance(handler, urllib.request.ProxyHandler) for handler in opener.handlers))
|
||||
self.assertTrue(any(isinstance(handler, MODULE.NoRedirectHandler) for handler in MODULE.HTTP_OPENER.handlers))
|
||||
self.assertIsNone(MODULE.NoRedirectHandler().redirect_request(None, None, 302, "Found", {}, "http://example.invalid"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user