fix(api): support finding-group aggregated filters

- Apply status and severity filters on aggregated finding-group results

- Prefilter summary groups by finding-level filter matches for advanced dimensions

- Add coverage for latest/list filters and keep check_title sorting support
This commit is contained in:
Adrián Jesús Peña Rodríguez
2026-03-23 16:20:00 +01:00
parent 14356e3187
commit efe14dfa7d
3 changed files with 452 additions and 57 deletions
+98
View File
@@ -15,6 +15,7 @@ from django_filters.rest_framework import (
from rest_framework_json_api.django_filters.backends import DjangoFilterBackend
from rest_framework_json_api.serializers import ValidationError
from api.constants import SEVERITY_ORDER
from api.db_utils import (
FindingDeltaEnumField,
InvitationStateEnumField,
@@ -803,11 +804,17 @@ class FindingGroupFilter(CommonFindingFilters):
check_id = CharFilter(field_name="check_id", lookup_expr="exact")
check_id__in = CharInFilter(field_name="check_id", lookup_expr="in")
check_id__icontains = CharFilter(field_name="check_id", lookup_expr="icontains")
check_title__icontains = CharFilter(
field_name="check_metadata__CheckTitle", lookup_expr="icontains"
)
scan = UUIDFilter(field_name="scan_id", lookup_expr="exact")
scan__in = UUIDInFilter(field_name="scan_id", lookup_expr="in")
class Meta:
model = Finding
fields = {
"check_id": ["exact", "in", "icontains"],
"scan": ["exact", "in"],
}
def filter_queryset(self, queryset):
@@ -895,11 +902,17 @@ class LatestFindingGroupFilter(CommonFindingFilters):
check_id = CharFilter(field_name="check_id", lookup_expr="exact")
check_id__in = CharInFilter(field_name="check_id", lookup_expr="in")
check_id__icontains = CharFilter(field_name="check_id", lookup_expr="icontains")
check_title__icontains = CharFilter(
field_name="check_metadata__CheckTitle", lookup_expr="icontains"
)
scan = UUIDFilter(field_name="scan_id", lookup_expr="exact")
scan__in = UUIDInFilter(field_name="scan_id", lookup_expr="in")
class Meta:
model = Finding
fields = {
"check_id": ["exact", "in", "icontains"],
"scan": ["exact", "in"],
}
@@ -1048,6 +1061,91 @@ class LatestFindingGroupSummaryFilter(FilterSet):
}
class FindingGroupAggregatedComputedFilter(FilterSet):
"""Filter aggregated finding-group rows by computed status/severity."""
STATUS_CHOICES = (
("FAIL", "Fail"),
("PASS", "Pass"),
("MUTED", "Muted"),
)
status = ChoiceFilter(method="filter_status", choices=STATUS_CHOICES)
status__in = CharInFilter(method="filter_status_in", lookup_expr="in")
severity = ChoiceFilter(method="filter_severity", choices=SeverityChoices)
severity__in = CharInFilter(method="filter_severity_in", lookup_expr="in")
def filter_status(self, queryset, name, value):
return queryset.filter(aggregated_status=value)
def filter_status_in(self, queryset, name, value):
values = value
if isinstance(value, str):
values = [part.strip() for part in value.split(",") if part.strip()]
allowed = {choice[0] for choice in self.STATUS_CHOICES}
invalid = [
status_value for status_value in values if status_value not in allowed
]
if invalid:
raise ValidationError(
[
{
"detail": f"invalid status filter: {invalid[0]}",
"status": "400",
"source": {"pointer": "/data"},
"code": "invalid",
}
]
)
if not values:
return queryset
return queryset.filter(aggregated_status__in=values)
def filter_severity(self, queryset, name, value):
severity_order = SEVERITY_ORDER.get(value)
if severity_order is None:
raise ValidationError(
[
{
"detail": f"invalid severity filter: {value}",
"status": "400",
"source": {"pointer": "/data"},
"code": "invalid",
}
]
)
return queryset.filter(severity_order=severity_order)
def filter_severity_in(self, queryset, name, value):
values = value
if isinstance(value, str):
values = [part.strip() for part in value.split(",") if part.strip()]
orders = []
for severity_value in values:
severity_order = SEVERITY_ORDER.get(severity_value)
if severity_order is None:
raise ValidationError(
[
{
"detail": f"invalid severity filter: {severity_value}",
"status": "400",
"source": {"pointer": "/data"},
"code": "invalid",
}
]
)
orders.append(severity_order)
if not orders:
return queryset
return queryset.filter(severity_order__in=orders)
class ProviderSecretFilter(FilterSet):
inserted_at = DateFilter(
field_name="inserted_at",
+259 -57
View File
@@ -1055,9 +1055,9 @@ class TestProviderViewSet:
included_data = response.json()["included"]
for expected_type in expected_resources:
assert any(
d.get("type") == expected_type for d in included_data
), f"Expected type '{expected_type}' not found in included data"
assert any(d.get("type") == expected_type for d in included_data), (
f"Expected type '{expected_type}' not found in included data"
)
def test_providers_retrieve(self, authenticated_client, providers_fixture):
provider1, *_ = providers_fixture
@@ -4919,13 +4919,13 @@ class TestAttackPathsScanViewSet:
content_type=API_JSON_CONTENT_TYPE,
)
if i < 10:
assert (
response.status_code == status.HTTP_200_OK
), f"Request {i + 1} should succeed with 200 OK, got {response.status_code}"
assert response.status_code == status.HTTP_200_OK, (
f"Request {i + 1} should succeed with 200 OK, got {response.status_code}"
)
else:
assert (
response.status_code == status.HTTP_429_TOO_MANY_REQUESTS
), f"Request {i + 1} should be throttled"
assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS, (
f"Request {i + 1} should be throttled"
)
# -- Timeout simulation -------------------------------------------------------
@@ -5128,9 +5128,9 @@ class TestResourceViewSet:
included_data = response.json()["included"]
for expected_type in expected_resources:
assert any(
d.get("type") == expected_type for d in included_data
), f"Expected type '{expected_type}' not found in included data"
assert any(d.get("type") == expected_type for d in included_data), (
f"Expected type '{expected_type}' not found in included data"
)
@pytest.mark.parametrize(
"filter_name, filter_value, expected_count",
@@ -5679,9 +5679,9 @@ class TestResourceViewSet:
(e for e in errors if e["source"]["parameter"] == expected_invalid_param),
None,
)
assert (
error is not None
), f"Expected error for parameter '{expected_invalid_param}'"
assert error is not None, (
f"Expected error for parameter '{expected_invalid_param}'"
)
assert error["code"] == "invalid"
assert error["status"] == "400" # Must be string per JSON:API spec
assert expected_invalid_param in error["detail"]
@@ -6213,16 +6213,16 @@ class TestResourceViewSet:
# Test with completely malformed token
client.credentials(HTTP_AUTHORIZATION="Bearer not.a.valid.jwt.token")
response = client.get(reverse("resource-events", kwargs={"pk": resource.id}))
assert (
response.status_code == status.HTTP_401_UNAUTHORIZED
), f"Expected 401 for malformed token but got {response.status_code}"
assert response.status_code == status.HTTP_401_UNAUTHORIZED, (
f"Expected 401 for malformed token but got {response.status_code}"
)
# Test with empty bearer token
client.credentials(HTTP_AUTHORIZATION="Bearer ")
response = client.get(reverse("resource-events", kwargs={"pk": resource.id}))
assert (
response.status_code == status.HTTP_401_UNAUTHORIZED
), f"Expected 401 for empty bearer token but got {response.status_code}"
assert response.status_code == status.HTTP_401_UNAUTHORIZED, (
f"Expected 401 for empty bearer token but got {response.status_code}"
)
@pytest.mark.django_db
@@ -6283,9 +6283,9 @@ class TestFindingViewSet:
included_data = response.json()["included"]
for expected_type in expected_resources:
assert any(
d.get("type") == expected_type for d in included_data
), f"Expected type '{expected_type}' not found in included data"
assert any(d.get("type") == expected_type for d in included_data), (
f"Expected type '{expected_type}' not found in included data"
)
@pytest.mark.parametrize(
"filter_name, filter_value, expected_count",
@@ -6824,9 +6824,9 @@ class TestJWTFields:
reverse("token-obtain"), data, format="json"
)
assert (
response.status_code == status.HTTP_200_OK
), f"Unexpected status code: {response.status_code}"
assert response.status_code == status.HTTP_200_OK, (
f"Unexpected status code: {response.status_code}"
)
access_token = response.data["attributes"]["access"]
payload = jwt.decode(access_token, options={"verify_signature": False})
@@ -6840,23 +6840,23 @@ class TestJWTFields:
# Verify expected fields
for field in expected_fields:
assert field in payload, f"The field '{field}' is not in the JWT"
assert (
payload[field] == expected_fields[field]
), f"The value of '{field}' does not match"
assert payload[field] == expected_fields[field], (
f"The value of '{field}' does not match"
)
# Verify time fields are integers
for time_field in ["exp", "iat", "nbf"]:
assert time_field in payload, f"The field '{time_field}' is not in the JWT"
assert isinstance(
payload[time_field], int
), f"The field '{time_field}' is not an integer"
assert isinstance(payload[time_field], int), (
f"The field '{time_field}' is not an integer"
)
# Verify identification fields are non-empty strings
for id_field in ["jti", "sub", "tenant_id"]:
assert id_field in payload, f"The field '{id_field}' is not in the JWT"
assert (
isinstance(payload[id_field], str) and payload[id_field]
), f"The field '{id_field}' is not a valid string"
assert isinstance(payload[id_field], str) and payload[id_field], (
f"The field '{id_field}' is not a valid string"
)
@pytest.mark.django_db
@@ -10795,9 +10795,9 @@ class TestIntegrationViewSet:
included_data = response.json()["included"]
for expected_type in expected_resources:
assert any(
d.get("type") == expected_type for d in included_data
), f"Expected type '{expected_type}' not found in included data"
assert any(d.get("type") == expected_type for d in included_data), (
f"Expected type '{expected_type}' not found in included data"
)
@pytest.mark.parametrize(
"integration_type, configuration, credentials",
@@ -12234,9 +12234,9 @@ class TestLighthouseConfigViewSet:
)
# Check that API key is masked with asterisks only
masked_api_key = data["attributes"]["api_key"]
assert all(
c == "*" for c in masked_api_key
), "API key should contain only asterisks"
assert all(c == "*" for c in masked_api_key), (
"API key should contain only asterisks"
)
@pytest.mark.parametrize(
"field_name, invalid_value",
@@ -15245,6 +15245,85 @@ class TestFindingGroupViewSet:
# rds_encryption has all muted findings
assert data[0]["attributes"]["status"] == "MUTED"
def test_finding_groups_status_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test finding groups can be filtered by aggregated status."""
response = authenticated_client.get(
reverse("finding-group-list"),
{"filter[inserted_at]": TODAY, "filter[status]": "FAIL"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["status"] == "FAIL" for item in data)
def test_finding_groups_status_in_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test finding groups support status__in filter on aggregated status."""
response = authenticated_client.get(
reverse("finding-group-list"),
{"filter[inserted_at]": TODAY, "filter[status__in]": "FAIL,PASS"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["status"] in {"FAIL", "PASS"} for item in data)
def test_finding_groups_severity_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test finding groups can be filtered by aggregated severity."""
response = authenticated_client.get(
reverse("finding-group-list"),
{"filter[inserted_at]": TODAY, "filter[severity]": "critical"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["severity"] == "critical" for item in data)
@pytest.mark.parametrize(
"filter_name,filter_value",
[
("region", "__region_does_not_exist__"),
("service", "__service_does_not_exist__"),
("category", "__category_does_not_exist__"),
("resource_groups", "__group_does_not_exist__"),
("resource_type", "__type_does_not_exist__"),
("scan", "00000000-0000-7000-8000-000000000001"),
],
)
def test_finding_groups_finding_level_filters_are_applied(
self,
authenticated_client,
finding_groups_fixture,
filter_name,
filter_value,
):
"""Test finding-level filters are applied in /finding-groups aggregation."""
response = authenticated_client.get(
reverse("finding-group-list"),
{"filter[inserted_at]": TODAY, f"filter[{filter_name}]": filter_value},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) == 0
def test_finding_groups_delta_filter_is_applied(
self, authenticated_client, finding_groups_fixture
):
"""Test delta filter is applied in /finding-groups aggregation."""
response = authenticated_client.get(
reverse("finding-group-list"),
{"filter[inserted_at]": TODAY, "filter[delta]": "new"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["new_count"] > 0 for item in data)
def test_finding_groups_provider_aggregation(
self, authenticated_client, finding_groups_fixture
):
@@ -15704,12 +15783,12 @@ class TestFindingGroupViewSet:
assert response_p1.status_code == status.HTTP_200_OK
p1_check_ids = {item["id"] for item in response_p1.json()["data"]}
# Provider1 has scan1 with 4 checks
assert (
len(p1_check_ids) == 4
), f"Provider1 should have 4 checks, got {len(p1_check_ids)}"
assert (
"cloudtrail_enabled" not in p1_check_ids
), "cloudtrail_enabled should NOT be in provider1"
assert len(p1_check_ids) == 4, (
f"Provider1 should have 4 checks, got {len(p1_check_ids)}"
)
assert "cloudtrail_enabled" not in p1_check_ids, (
"cloudtrail_enabled should NOT be in provider1"
)
# Get finding groups for provider2 only
response_p2 = authenticated_client.get(
@@ -15719,12 +15798,12 @@ class TestFindingGroupViewSet:
assert response_p2.status_code == status.HTTP_200_OK
p2_check_ids = {item["id"] for item in response_p2.json()["data"]}
# Provider2 has scan2 with 1 check
assert (
len(p2_check_ids) == 1
), f"Provider2 should have 1 check, got {len(p2_check_ids)}"
assert (
"cloudtrail_enabled" in p2_check_ids
), "cloudtrail_enabled should be in provider2"
assert len(p2_check_ids) == 1, (
f"Provider2 should have 1 check, got {len(p2_check_ids)}"
)
assert "cloudtrail_enabled" in p2_check_ids, (
"cloudtrail_enabled should be in provider2"
)
# Test provider_type filter actually filters data
def test_finding_groups_provider_type_filter_actually_filters(
@@ -15747,9 +15826,9 @@ class TestFindingGroupViewSet:
{"filter[inserted_at]": TODAY, "filter[provider_type]": "gcp"},
)
assert response_gcp.status_code == status.HTTP_200_OK
assert (
len(response_gcp.json()["data"]) == 0
), "GCP filter should return 0 results"
assert len(response_gcp.json()["data"]) == 0, (
"GCP filter should return 0 results"
)
def test_finding_groups_pagination(
self, authenticated_client, finding_groups_fixture
@@ -15853,6 +15932,116 @@ class TestFindingGroupViewSet:
assert len(data) == 1
assert data[0]["id"] == "cloudtrail_enabled"
def test_finding_groups_latest_status_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test /latest supports status filter on aggregated status."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{"filter[status]": "FAIL"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["status"] == "FAIL" for item in data)
def test_finding_groups_latest_status_in_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test /latest supports status__in filter on aggregated status."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{"filter[status__in]": "FAIL,PASS"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["status"] in {"FAIL", "PASS"} for item in data)
def test_finding_groups_latest_severity_filter(
self, authenticated_client, finding_groups_fixture
):
"""Test /latest supports severity filter on aggregated severity."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{"filter[severity]": "critical"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["severity"] == "critical" for item in data)
@pytest.mark.parametrize(
"filter_name,filter_value",
[
("region", "__region_does_not_exist__"),
("service", "__service_does_not_exist__"),
("category", "__category_does_not_exist__"),
("resource_groups", "__group_does_not_exist__"),
("resource_type", "__type_does_not_exist__"),
("scan", "00000000-0000-7000-8000-000000000001"),
],
)
def test_finding_groups_latest_finding_level_filters_are_applied(
self,
authenticated_client,
finding_groups_fixture,
filter_name,
filter_value,
):
"""Test finding-level filters are applied in /finding-groups/latest aggregation."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{f"filter[{filter_name}]": filter_value},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) == 0
def test_finding_groups_check_title_filter_applies_with_delta(
self, authenticated_client, finding_groups_fixture
):
"""Test check_title filter is honored when finding-level path is used."""
response = authenticated_client.get(
reverse("finding-group-list"),
{
"filter[inserted_at]": TODAY,
"filter[delta]": "new",
"filter[check_title.icontains]": "__missing_check_title__",
},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) == 0
def test_finding_groups_latest_check_title_filter_applies_with_delta(
self, authenticated_client, finding_groups_fixture
):
"""Test /latest check_title filter is honored on finding-level path."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{
"filter[delta]": "new",
"filter[check_title.icontains]": "__missing_check_title__",
},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) == 0
def test_finding_groups_latest_delta_filter_is_applied(
self, authenticated_client, finding_groups_fixture
):
"""Test delta filter is applied in /finding-groups/latest aggregation."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{"filter[delta]": "new"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
assert len(data) > 0
assert all(item["attributes"]["new_count"] > 0 for item in data)
def test_finding_groups_latest_aggregates_latest_per_provider(
self, authenticated_client, providers_fixture
):
@@ -15934,6 +16123,19 @@ class TestFindingGroupViewSet:
check_ids = [item["id"] for item in data]
assert check_ids == sorted(check_ids)
def test_finding_groups_latest_sort_by_check_title(
self, authenticated_client, finding_groups_fixture
):
"""Test /latest supports sorting by check_title."""
response = authenticated_client.get(
reverse("finding-group-latest"),
{"sort": "check_title"},
)
assert response.status_code == status.HTTP_200_OK
data = response.json()["data"]
check_titles = [item["attributes"]["check_title"] for item in data]
assert check_titles == sorted(check_titles)
def test_finding_groups_latest_ignores_date_filters(
self, authenticated_client, finding_groups_fixture
):
+95
View File
@@ -31,6 +31,7 @@ from django.contrib.postgres.search import SearchQuery
from django.db import transaction
from django.db.models import (
Case,
CharField,
Count,
DecimalField,
ExpressionWrapper,
@@ -124,6 +125,7 @@ from api.filters import (
CustomDjangoFilterBackend,
DailySeveritySummaryFilter,
FindingFilter,
FindingGroupAggregatedComputedFilter,
FindingGroupFilter,
FindingGroupSummaryFilter,
IntegrationFilter,
@@ -6872,6 +6874,39 @@ class FindingGroupViewSet(BaseRLSViewSet):
"resource_type__icontains": "type__icontains",
}
def _get_finding_level_filter_keys(self, latest: bool = False) -> set[str]:
"""Derive filters that require finding-level prefiltering."""
summary_filterset = (
LatestFindingGroupSummaryFilter if latest else FindingGroupSummaryFilter
)
finding_filterset = LatestFindingGroupFilter if latest else FindingGroupFilter
summary_supported = set(summary_filterset.base_filters.keys()) | {
"status",
"status__in",
"severity",
"severity__in",
}
finding_supported = set(finding_filterset.base_filters.keys())
return finding_supported - summary_supported
def _requires_finding_level_aggregation(
self, params: QueryDict, latest: bool = False
) -> bool:
finding_level_keys = self._get_finding_level_filter_keys(latest=latest)
return any(key in finding_level_keys for key in params.keys())
def _get_matching_check_ids_from_findings(
self, normalized_params: QueryDict, latest: bool = False
):
"""Return check_ids matching advanced finding-level filters."""
finding_queryset = self._get_finding_queryset()
filterset_class = LatestFindingGroupFilter if latest else FindingGroupFilter
filterset = filterset_class(normalized_params, queryset=finding_queryset)
if not filterset.is_valid():
raise ValidationError(filterset.errors)
return filterset.qs.values("check_id").distinct()
def _split_resource_filters(self, params: QueryDict) -> tuple[QueryDict, QueryDict]:
resource_keys = set(self.RESOURCE_FILTER_MAP)
finding_params = QueryDict(mutable=True)
@@ -6998,6 +7033,7 @@ class FindingGroupViewSet(BaseRLSViewSet):
"""Validate and map JSON:API sort fields for aggregated finding groups."""
sort_field_map = {
"check_id": "check_id",
"check_title": "check_title",
"severity": "severity_order",
"fail_count": "fail_count",
"pass_count": "pass_count",
@@ -7035,6 +7071,43 @@ class FindingGroupViewSet(BaseRLSViewSet):
return ordering
def _apply_aggregated_computed_filters(
self, queryset, normalized_params: QueryDict
):
"""Apply computed filters (status/severity) on aggregated finding-group rows."""
status_params = QueryDict(mutable=True)
if normalized_params.get("status"):
status_params.setlist("status", [normalized_params.get("status")])
if normalized_params.getlist("status__in"):
status_params.setlist("status__in", normalized_params.getlist("status__in"))
if normalized_params.get("severity"):
status_params.setlist("severity", [normalized_params.get("severity")])
if normalized_params.getlist("severity__in"):
status_params.setlist(
"severity__in", normalized_params.getlist("severity__in")
)
if not status_params:
return queryset
if status_params.get("status") or status_params.getlist("status__in"):
queryset = queryset.annotate(
aggregated_status=Case(
When(fail_count__gt=0, then=Value("FAIL")),
When(pass_count__gt=0, then=Value("PASS")),
default=Value("MUTED"),
output_field=CharField(),
)
)
filterset = FindingGroupAggregatedComputedFilter(
status_params, queryset=queryset
)
if not filterset.is_valid():
raise ValidationError(filterset.errors)
return filterset.qs
def _build_resource_mapping_queryset(
self, filtered_queryset, resource_ids=None, tenant_id: str | None = None
):
@@ -7166,6 +7239,17 @@ class FindingGroupViewSet(BaseRLSViewSet):
# Re-aggregate daily summaries across the date range
aggregated_queryset = self._aggregate_daily_summaries(filtered_queryset)
aggregated_queryset = self._apply_aggregated_computed_filters(
aggregated_queryset, normalized_params
)
if self._requires_finding_level_aggregation(normalized_params, latest=False):
matching_check_ids = self._get_matching_check_ids_from_findings(
normalized_params, latest=False
)
aggregated_queryset = aggregated_queryset.filter(
check_id__in=Subquery(matching_check_ids)
)
# Apply ordering (respect JSON:API sort param or use default)
sort_param = request.query_params.get("sort")
@@ -7239,6 +7323,17 @@ class FindingGroupViewSet(BaseRLSViewSet):
# Re-aggregate daily summaries
aggregated_queryset = self._aggregate_daily_summaries(latest_per_check)
aggregated_queryset = self._apply_aggregated_computed_filters(
aggregated_queryset, normalized_params
)
if self._requires_finding_level_aggregation(normalized_params, latest=True):
matching_check_ids = self._get_matching_check_ids_from_findings(
normalized_params, latest=True
)
aggregated_queryset = aggregated_queryset.filter(
check_id__in=Subquery(matching_check_ids)
)
# Apply ordering
sort_param = request.query_params.get("sort")