From 22ae3d0e95b3bf389dabfc230f804b9335f49823 Mon Sep 17 00:00:00 2001 From: FanouZeng-TT <124567600+FanouZeng-TT@users.noreply.github.com> Date: Thu, 17 Sep 2026 22:13:53 +0800 Subject: [PATCH] fix(backend): validate assistant search pagination (#5506) Co-authored-by: Claude Code --- .../app/gateway/routers/assistants_compat.py | 4 +- backend/tests/test_assistants_compat.py | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 backend/tests/test_assistants_compat.py diff --git a/backend/app/gateway/routers/assistants_compat.py b/backend/app/gateway/routers/assistants_compat.py index b0479e81f..f682c9a0b 100644 --- a/backend/app/gateway/routers/assistants_compat.py +++ b/backend/app/gateway/routers/assistants_compat.py @@ -37,8 +37,8 @@ class AssistantSearchRequest(BaseModel): graph_id: str | None = None name: str | None = None metadata: dict[str, Any] | None = None - limit: int = 10 - offset: int = 0 + limit: int = Field(default=10, ge=1, le=1000) + offset: int = Field(default=0, ge=0) def _get_default_assistant() -> AssistantResponse: diff --git a/backend/tests/test_assistants_compat.py b/backend/tests/test_assistants_compat.py new file mode 100644 index 000000000..a29d2613b --- /dev/null +++ b/backend/tests/test_assistants_compat.py @@ -0,0 +1,61 @@ +"""Contract tests for the LangGraph-compatible assistants endpoints.""" + +import pytest +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from app.gateway.routers import assistants_compat + + +def _assistant(name: str) -> assistants_compat.AssistantResponse: + return assistants_compat.AssistantResponse( + assistant_id=name, + graph_id="lead_agent", + name=name, + ) + + +def _make_app(monkeypatch: pytest.MonkeyPatch) -> FastAPI: + app = FastAPI() + app.include_router(assistants_compat.router) + monkeypatch.setattr( + assistants_compat, + "_list_assistants", + lambda: [_assistant("lead_agent"), _assistant("researcher"), _assistant("writer")], + ) + return app + + +@pytest.mark.parametrize( + "body", + [ + {"limit": 0}, + {"limit": -1}, + {"limit": 1001}, + {"offset": -1}, + ], +) +def test_search_rejects_invalid_pagination(monkeypatch: pytest.MonkeyPatch, body: dict[str, int]) -> None: + with TestClient(_make_app(monkeypatch)) as client: + response = client.post("/api/assistants/search", json=body) + + assert response.status_code == 422 + + +def test_search_accepts_contract_maximum_limit(monkeypatch: pytest.MonkeyPatch) -> None: + with TestClient(_make_app(monkeypatch)) as client: + response = client.post("/api/assistants/search", json={"limit": 1000}) + + assert response.status_code == 200 + assert [assistant["assistant_id"] for assistant in response.json()] == ["lead_agent", "researcher", "writer"] + + +def test_search_preserves_default_and_positive_offset(monkeypatch: pytest.MonkeyPatch) -> None: + with TestClient(_make_app(monkeypatch)) as client: + default_response = client.post("/api/assistants/search") + offset_response = client.post("/api/assistants/search", json={"offset": 1, "limit": 1}) + + assert default_response.status_code == 200 + assert [assistant["assistant_id"] for assistant in default_response.json()] == ["lead_agent", "researcher", "writer"] + assert offset_response.status_code == 200 + assert [assistant["assistant_id"] for assistant in offset_response.json()] == ["researcher"]