mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
fix(overviews): exclude muted findings from severity overview (#9283)
This commit is contained in:
committed by
GitHub
parent
6426558b18
commit
789fc84e31
@@ -28,6 +28,7 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
### Fixed
|
||||
- Scans no longer fail when findings have UIDs exceeding 300 characters; such findings are now skipped with detailed logging [(#9246)](https://github.com/prowler-cloud/prowler/pull/9246)
|
||||
- Refresh output report timestamps for each scan [(#9272)](https://github.com/prowler-cloud/prowler/pull/9272)
|
||||
- Severity overview endpoint now ignores muted findings as expected [(#9283)](https://github.com/prowler-cloud/prowler/pull/9283)
|
||||
|
||||
### Security
|
||||
- Django updated to the latest 5.1 security release, 5.1.14, due to problems with potential [SQL injection](https://github.com/prowler-cloud/prowler/security/dependabot/113) and [denial-of-service vulnerability](https://github.com/prowler-cloud/prowler/security/dependabot/114) [(#9176)](https://github.com/prowler-cloud/prowler/pull/9176)
|
||||
|
||||
@@ -820,7 +820,8 @@ class ScanSummarySeverityFilter(ScanSummaryFilter):
|
||||
elif value == OverviewStatusChoices.PASS:
|
||||
return queryset.annotate(status_count=F("_pass"))
|
||||
else:
|
||||
return queryset.annotate(status_count=F("total"))
|
||||
# Exclude muted findings by default
|
||||
return queryset.annotate(status_count=F("_pass") + F("fail"))
|
||||
|
||||
def filter_status_in(self, queryset, name, value):
|
||||
# Validate the status values
|
||||
@@ -829,7 +830,7 @@ class ScanSummarySeverityFilter(ScanSummaryFilter):
|
||||
if status_val not in valid_statuses:
|
||||
raise ValidationError(f"Invalid status value: {status_val}")
|
||||
|
||||
# If all statuses or no valid statuses, use total
|
||||
# If all statuses or no valid statuses, exclude muted findings (pass + fail)
|
||||
if (
|
||||
set(value)
|
||||
>= {
|
||||
@@ -838,7 +839,7 @@ class ScanSummarySeverityFilter(ScanSummaryFilter):
|
||||
}
|
||||
or not value
|
||||
):
|
||||
return queryset.annotate(status_count=F("total"))
|
||||
return queryset.annotate(status_count=F("_pass") + F("fail"))
|
||||
|
||||
# Build the sum expression based on status values
|
||||
sum_expression = None
|
||||
@@ -856,7 +857,7 @@ class ScanSummarySeverityFilter(ScanSummaryFilter):
|
||||
sum_expression = sum_expression + field_expr
|
||||
|
||||
if sum_expression is None:
|
||||
return queryset.annotate(status_count=F("total"))
|
||||
return queryset.annotate(status_count=F("_pass") + F("fail"))
|
||||
|
||||
return queryset.annotate(status_count=sum_expression)
|
||||
|
||||
|
||||
@@ -6280,10 +6280,10 @@ class TestOverviewViewSet:
|
||||
response = authenticated_client.get(reverse("overview-providers"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert len(response.json()["data"]) == 1
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["total"] == 4
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["total"] == 9
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["pass"] == 2
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["fail"] == 1
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["muted"] == 1
|
||||
assert response.json()["data"][0]["attributes"]["findings"]["muted"] == 6
|
||||
# Aggregated resources include all AWS providers present in the tenant
|
||||
assert response.json()["data"][0]["attributes"]["resources"]["total"] == 3
|
||||
|
||||
@@ -6335,10 +6335,10 @@ class TestOverviewViewSet:
|
||||
assert len(data) == 1
|
||||
attributes = data[0]["attributes"]
|
||||
|
||||
assert attributes["findings"]["total"] == 10
|
||||
assert attributes["findings"]["total"] == 15
|
||||
assert attributes["findings"]["pass"] == 5
|
||||
assert attributes["findings"]["fail"] == 3
|
||||
assert attributes["findings"]["muted"] == 2
|
||||
assert attributes["findings"]["muted"] == 7
|
||||
assert attributes["resources"]["total"] == 4
|
||||
|
||||
def test_overview_providers_count(
|
||||
@@ -6791,15 +6791,14 @@ class TestOverviewViewSet:
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
# Only two different services
|
||||
assert len(response.json()["data"]) == 2
|
||||
# Fixed data from the fixture, TODO improve this at some point with something more dynamic
|
||||
# Fixed data from the fixture
|
||||
service1_data = response.json()["data"][0]
|
||||
service2_data = response.json()["data"][1]
|
||||
assert service1_data["id"] == "service1"
|
||||
assert service2_data["id"] == "service2"
|
||||
|
||||
# TODO fix numbers when muted_findings filter is fixed
|
||||
assert service1_data["attributes"]["total"] == 3
|
||||
assert service2_data["attributes"]["total"] == 1
|
||||
assert service1_data["attributes"]["total"] == 7
|
||||
assert service2_data["attributes"]["total"] == 2
|
||||
|
||||
assert service1_data["attributes"]["pass"] == 1
|
||||
assert service2_data["attributes"]["pass"] == 1
|
||||
@@ -6807,8 +6806,8 @@ class TestOverviewViewSet:
|
||||
assert service1_data["attributes"]["fail"] == 1
|
||||
assert service2_data["attributes"]["fail"] == 0
|
||||
|
||||
assert service1_data["attributes"]["muted"] == 1
|
||||
assert service2_data["attributes"]["muted"] == 0
|
||||
assert service1_data["attributes"]["muted"] == 5
|
||||
assert service2_data["attributes"]["muted"] == 1
|
||||
|
||||
def test_overview_findings_provider_id_in_filter(
|
||||
self, authenticated_client, tenants_fixture, providers_fixture
|
||||
@@ -6918,6 +6917,7 @@ class TestOverviewViewSet:
|
||||
tenant=tenant,
|
||||
)
|
||||
|
||||
# Muted findings should be excluded from severity counts
|
||||
ScanSummary.objects.create(
|
||||
tenant=tenant,
|
||||
scan=scan1,
|
||||
@@ -6927,8 +6927,8 @@ class TestOverviewViewSet:
|
||||
region="region-a",
|
||||
_pass=4,
|
||||
fail=4,
|
||||
muted=0,
|
||||
total=8,
|
||||
muted=3,
|
||||
total=11,
|
||||
)
|
||||
ScanSummary.objects.create(
|
||||
tenant=tenant,
|
||||
@@ -6939,8 +6939,8 @@ class TestOverviewViewSet:
|
||||
region="region-b",
|
||||
_pass=2,
|
||||
fail=2,
|
||||
muted=0,
|
||||
total=4,
|
||||
muted=2,
|
||||
total=6,
|
||||
)
|
||||
ScanSummary.objects.create(
|
||||
tenant=tenant,
|
||||
@@ -6951,8 +6951,8 @@ class TestOverviewViewSet:
|
||||
region="region-c",
|
||||
_pass=1,
|
||||
fail=2,
|
||||
muted=0,
|
||||
total=3,
|
||||
muted=5,
|
||||
total=8,
|
||||
)
|
||||
|
||||
single_response = authenticated_client.get(
|
||||
@@ -6961,6 +6961,7 @@ class TestOverviewViewSet:
|
||||
)
|
||||
assert single_response.status_code == status.HTTP_200_OK
|
||||
single_attributes = single_response.json()["data"]["attributes"]
|
||||
# Should only count pass + fail, excluding muted (3 muted in high, 2 in medium)
|
||||
assert single_attributes["high"] == 8
|
||||
assert single_attributes["medium"] == 4
|
||||
assert single_attributes["critical"] == 0
|
||||
@@ -6971,6 +6972,7 @@ class TestOverviewViewSet:
|
||||
)
|
||||
assert combined_response.status_code == status.HTTP_200_OK
|
||||
combined_attributes = combined_response.json()["data"]["attributes"]
|
||||
# Should only count pass + fail, excluding muted (5 muted in critical)
|
||||
assert combined_attributes["high"] == 8
|
||||
assert combined_attributes["medium"] == 4
|
||||
assert combined_attributes["critical"] == 3
|
||||
|
||||
@@ -4198,7 +4198,7 @@ class OverviewViewSet(BaseRLSViewSet):
|
||||
|
||||
# Load only required fields
|
||||
queryset = self.get_queryset().only(
|
||||
"tenant_id", "scan_id", "severity", "fail", "_pass", "total"
|
||||
"tenant_id", "scan_id", "severity", "fail", "_pass", "muted"
|
||||
)
|
||||
|
||||
filtered_queryset = self.filter_queryset(queryset)
|
||||
@@ -4224,7 +4224,8 @@ class OverviewViewSet(BaseRLSViewSet):
|
||||
if "status_count" in filtered_queryset.query.annotations:
|
||||
sum_expression = Sum("status_count")
|
||||
else:
|
||||
sum_expression = Sum("total")
|
||||
# Exclude muted findings by default
|
||||
sum_expression = Sum(F("_pass") + F("fail"))
|
||||
|
||||
severity_counts = (
|
||||
filtered_queryset.values("severity")
|
||||
|
||||
@@ -1108,8 +1108,8 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
region="region1",
|
||||
_pass=1,
|
||||
fail=0,
|
||||
muted=0,
|
||||
total=1,
|
||||
muted=2,
|
||||
total=3,
|
||||
new=1,
|
||||
changed=0,
|
||||
unchanged=0,
|
||||
@@ -1117,7 +1117,7 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
fail_changed=0,
|
||||
pass_new=1,
|
||||
pass_changed=0,
|
||||
muted_new=0,
|
||||
muted_new=2,
|
||||
muted_changed=0,
|
||||
scan=scan,
|
||||
)
|
||||
@@ -1130,8 +1130,8 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
region="region2",
|
||||
_pass=0,
|
||||
fail=1,
|
||||
muted=1,
|
||||
total=2,
|
||||
muted=3,
|
||||
total=4,
|
||||
new=2,
|
||||
changed=0,
|
||||
unchanged=0,
|
||||
@@ -1139,7 +1139,7 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
fail_changed=0,
|
||||
pass_new=0,
|
||||
pass_changed=0,
|
||||
muted_new=1,
|
||||
muted_new=3,
|
||||
muted_changed=0,
|
||||
scan=scan,
|
||||
)
|
||||
@@ -1152,8 +1152,8 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
region="region1",
|
||||
_pass=1,
|
||||
fail=0,
|
||||
muted=0,
|
||||
total=1,
|
||||
muted=1,
|
||||
total=2,
|
||||
new=1,
|
||||
changed=0,
|
||||
unchanged=0,
|
||||
@@ -1161,7 +1161,7 @@ def scan_summaries_fixture(tenants_fixture, providers_fixture):
|
||||
fail_changed=0,
|
||||
pass_new=1,
|
||||
pass_changed=0,
|
||||
muted_new=0,
|
||||
muted_new=1,
|
||||
muted_changed=0,
|
||||
scan=scan,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user