feat(api): drive provider-type filters from SDK-available providers

- Replace the static provider enum in filters with the SDK provider list
- Cache the provider-type choices for hot list endpoints
- Drop the dead provider enum filter override
This commit is contained in:
StylusFrost committed 2026-05-31 23:33:23 +02:00
1 parent f14778438e
commit 37323e691a
2 files changed
+58 -28

No files matched your search

+35 -28
View File
@@ -1,4 +1,5 @@
from datetime import date, datetime, timedelta, timezone
from functools import lru_cache
from dateutil.parser import parse
from django.conf import settings
@@ -19,7 +20,6 @@ from api.constants import SEVERITY_ORDER
from api.db_utils import (
FindingDeltaEnumField,
InvitationStateEnumField,
ProviderEnumField,
SeverityEnumField,
StatusEnumField,
)
@@ -68,6 +68,18 @@ from api.uuid_utils import (
uuid7_start,
)
from api.v1.serializers import TaskBase
from prowler.providers.common.provider import Provider as SDKProvider
@lru_cache(maxsize=1)
def get_provider_type_choices():
"""Provider-type filter choices driven by the SDK's available providers
instead of a static enum, so filtering covers external providers too.
Cached because the installed providers are fixed for the process lifetime
and provider-type filters live on hot list endpoints.
"""
return [(name, name) for name in SDKProvider.get_available_providers()]
class CustomDjangoFilterBackend(DjangoFilterBackend):
@@ -109,11 +121,11 @@ class BaseProviderFilter(FilterSet):
provider_id = UUIDFilter(field_name="provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="provider__provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
@@ -133,11 +145,11 @@ class BaseScanProviderFilter(FilterSet):
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
field_name="scan__provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="scan__provider__provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
@@ -155,10 +167,10 @@ class CommonFindingFilters(FilterSet):
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
choices=get_provider_type_choices(), field_name="scan__provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
choices=get_provider_type_choices(), field_name="scan__provider__provider"
)
provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in")
@@ -356,18 +368,18 @@ class ProviderFilter(FilterSet):
included. Providers with no connection attempt (status is null) are
excluded from this filter."""
)
provider = ChoiceFilter(choices=Provider.ProviderChoices.choices)
provider = ChoiceFilter(choices=get_provider_type_choices())
provider__in = ChoiceInFilter(
field_name="provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="provider"
choices=get_provider_type_choices(), field_name="provider"
)
provider_type__in = ChoiceInFilter(
field_name="provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
@@ -381,19 +393,14 @@ class ProviderFilter(FilterSet):
"inserted_at": ["gte", "lte"],
"updated_at": ["gte", "lte"],
}
filter_overrides = {
ProviderEnumField: {
"filter_class": CharFilter,
},
}
class ProviderRelationshipFilterSet(FilterSet):
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="provider__provider"
choices=get_provider_type_choices(), field_name="provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="provider__provider"
choices=get_provider_type_choices(), field_name="provider__provider"
)
provider_uid = CharFilter(field_name="provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="provider__uid", lookup_expr="in")
@@ -998,7 +1005,7 @@ class FindingGroupSummaryFilter(_CheckTitleToCheckIdMixin, FilterSet):
provider_id = UUIDFilter(field_name="provider_id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider_id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
provider_type__in = CharInFilter(field_name="provider__provider", lookup_expr="in")
@@ -1098,7 +1105,7 @@ class LatestFindingGroupSummaryFilter(_CheckTitleToCheckIdMixin, FilterSet):
provider_id = UUIDFilter(field_name="provider_id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider_id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
provider_type__in = CharInFilter(field_name="provider__provider", lookup_expr="in")
@@ -1301,10 +1308,10 @@ class ScanSummaryFilter(FilterSet):
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
field_name="scan__provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
field_name="scan__provider__provider", choices=get_provider_type_choices()
)
region = CharFilter(field_name="region")
@@ -1324,10 +1331,10 @@ class DailySeveritySummaryFilter(FilterSet):
provider_id = UUIDFilter(field_name="provider_id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider_id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
date_from = DateFilter(method="filter_noop")
date_to = DateFilter(method="filter_noop")
@@ -1578,11 +1585,11 @@ class ThreatScoreSnapshotFilter(FilterSet):
provider_id = UUIDFilter(field_name="provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="provider__provider", choices=Provider.ProviderChoices.choices
field_name="provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="provider__provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
compliance_id = CharFilter(field_name="compliance_id", lookup_expr="exact")
@@ -1621,11 +1628,11 @@ class ResourceGroupOverviewFilter(FilterSet):
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
field_name="scan__provider__provider", choices=get_provider_type_choices()
)
provider_type__in = ChoiceInFilter(
field_name="scan__provider__provider",
choices=Provider.ProviderChoices.choices,
choices=get_provider_type_choices(),
lookup_expr="in",
)
resource_group = CharFilter(field_name="resource_group", lookup_expr="exact")
+23
View File
@@ -0,0 +1,23 @@
from api.filters import get_provider_type_choices
from prowler.providers.common.provider import Provider as SDKProvider
class TestProviderTypeChoices:
"""Provider-type filter choices are driven by the SDK's available providers
so filtering covers external providers, not just a static enum."""
def test_choices_track_sdk_available_providers(self):
available = set(SDKProvider.get_available_providers())
choices = get_provider_type_choices()
assert {value for value, _ in choices} == available
def test_choices_include_provider_absent_from_legacy_enum(self):
from api.models import Provider
legacy = {value for value, _ in Provider.ProviderChoices.choices}
choice_values = {value for value, _ in get_provider_type_choices()}
# `llm` is exposed by the SDK but is not part of the legacy static enum.
assert "llm" in choice_values
assert "llm" not in legacy