diff --git a/api/projects/views.py b/api/projects/views.py index 1277b7867e72..e48efb8e55d3 100644 --- a/api/projects/views.py +++ b/api/projects/views.py @@ -100,7 +100,13 @@ def get_queryset(self): # type: ignore[no-untyped-def] organisation_id = self.request.query_params.get("organisation") if organisation_id: - queryset = queryset.filter(organisation__id=organisation_id) + try: + # Validate that organisation_id is numeric before filtering + int(organisation_id) + queryset = queryset.filter(organisation__id=organisation_id) + except (ValueError, TypeError): + # Return empty queryset if organisation_id is not a valid integer + return Project.objects.none() project_uuid = self.request.query_params.get("uuid") if project_uuid: diff --git a/api/tests/unit/projects/test_unit_projects_views.py b/api/tests/unit/projects/test_unit_projects_views.py index 7989b4e0449d..2f2bad5a0b99 100644 --- a/api/tests/unit/projects/test_unit_projects_views.py +++ b/api/tests/unit/projects/test_unit_projects_views.py @@ -1055,3 +1055,38 @@ def test_list_projects__default_enforce_feature_owners__returns_false( assert len(response.json()) > 0 assert "enforce_feature_owners" in response.json()[0] assert response.json()[0]["enforce_feature_owners"] is False + + +def test_list_projects__non_numeric_organisation_parameter__returns_empty_list( + admin_client: APIClient, + project: Project, +) -> None: + # Given - a request with non-numeric organisation query parameter + url = reverse("api-v1:projects:project-list") + "?organisation=invalid_string" + + # When + response = admin_client.get(url) + + # Then - should return 200 with empty list, not crash with 500 + assert response.status_code == status.HTTP_200_OK + assert response.json() == [] + + +def test_list_projects__non_numeric_organisation_parameter_with_valid_projects__returns_empty_list( + admin_client: APIClient, + project: Project, + organisation: Organisation, +) -> None: + # Given - a request with non-numeric organisation query parameter + # even though there are projects in the system + url = ( + reverse("api-v1:projects:project-list") + + f"?organisation=invalid_id_{organisation.id}" + ) + + # When + response = admin_client.get(url) + + # Then - should return 200 with empty list, not crash with 500 + assert response.status_code == status.HTTP_200_OK + assert response.json() == []