From 26483661da4e75247b10b3b146e7355a8e769871 Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:54:40 +0100 Subject: [PATCH] Restrict provider discovery to admins Require admin access before serving provider discovery data from GET /api/providers. This prevents normal authenticated users from triggering provider discovery or receiving cached provider host data. Keep GET /api/models available to normal users and leave the existing admin-only GET /api/discover behavior unchanged. Add a focused regression test to ensure unauthorized callers cannot trigger discovery and cannot receive cached provider data. --- routes/model_routes.py | 3 ++- tests/test_review_regressions.py | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/routes/model_routes.py b/routes/model_routes.py index 4959450..a92f06b 100644 --- a/routes/model_routes.py +++ b/routes/model_routes.py @@ -890,8 +890,9 @@ def setup_model_routes(model_discovery): _PROVIDERS_CACHE_TTL = 30 # seconds @router.get("/providers") - def providers(refresh: bool = False): + def providers(request: Request, refresh: bool = False): """Get all available providers (cached for 30s).""" + require_admin(request) now = _time.time() if not refresh and _providers_cache["data"] is not None and (now - _providers_cache["time"]) < _PROVIDERS_CACHE_TTL: return _providers_cache["data"] diff --git a/tests/test_review_regressions.py b/tests/test_review_regressions.py index f31f742..05db027 100644 --- a/tests/test_review_regressions.py +++ b/tests/test_review_regressions.py @@ -97,6 +97,42 @@ def _install_core_auth_stub(monkeypatch): return auth_mod +def test_providers_requires_admin_before_discovery_and_cache(monkeypatch): + _install_model_route_import_stubs(monkeypatch) + import routes.model_routes as model_routes + + class _Discovery: + def __init__(self): + self.calls = 0 + + def get_providers(self): + self.calls += 1 + return {"providers": [{"host": "internal.example"}]} + + discovery = _Discovery() + router = model_routes.setup_model_routes(discovery) + endpoint = next( + route.endpoint + for route in router.routes + if getattr(route, "path", "") == "/api/providers" + ) + request = SimpleNamespace() + + assert endpoint(request, refresh=True) == {"providers": [{"host": "internal.example"}]} + assert discovery.calls == 1 + + def deny_admin(_request): + raise PermissionError("admin required") + + monkeypatch.setattr(model_routes, "require_admin", deny_admin) + + with pytest.raises(PermissionError): + endpoint(request, refresh=True) + with pytest.raises(PermissionError): + endpoint(request, refresh=False) + assert discovery.calls == 1 + + def test_default_chat_does_not_auto_pick_shared_endpoint_for_fresh_user(monkeypatch): _install_model_route_import_stubs(monkeypatch) import routes.model_routes as model_routes