From ad3aa2a2cca8da40a8790bc9d24f788b2977c30b Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 7 Jul 2025 16:57:14 +0200 Subject: [PATCH] fix(findings): avoid backfill on empty scans (#8188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Víctor Fernández Poyatos --- api/CHANGELOG.md | 7 ++++ api/pyproject.toml | 2 +- api/src/backend/api/specs/v1.yaml | 2 +- api/src/backend/api/tests/test_views.py | 55 +++++++++++++++++++++++++ api/src/backend/api/v1/views.py | 16 +++++-- 5 files changed, 76 insertions(+), 6 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 615691cad0..3cc4d24b2e 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -6,6 +6,13 @@ All notable changes to the **Prowler API** are documented in this file. --- +## [v1.9.1] (Prowler v5.8.1) + +### Fixed +- Scan with no resources will not trigger legacy code for findings metadata [(#8183)](https://github.com/prowler-cloud/prowler/pull/8183) + +--- + ## [v1.9.0] (Prowler v5.8.0) ### Added diff --git a/api/pyproject.toml b/api/pyproject.toml index 143f0647fd..348aca7c71 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -36,7 +36,7 @@ name = "prowler-api" package-mode = false # Needed for the SDK compatibility requires-python = ">=3.11,<3.13" -version = "1.9.0" +version = "1.9.1" [project.scripts] celery = "src.backend.config.settings.celery" diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index c17b6e996e..5d190d67ca 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Prowler API - version: 1.9.0 + version: 1.9.1 description: |- Prowler API specification. diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index fd744af4df..ed3c56f6d6 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -3371,6 +3371,61 @@ class TestFindingViewSet: ] } + def test_findings_metadata_backfill( + self, authenticated_client, scans_fixture, findings_fixture + ): + scan = scans_fixture[0] + scan.unique_resource_count = 1 + scan.save() + + with patch( + "api.v1.views.backfill_scan_resource_summaries_task.apply_async" + ) as mock_backfill_task: + response = authenticated_client.get( + reverse("finding-metadata"), + {"filter[scan]": str(scan.id)}, + ) + assert response.status_code == status.HTTP_200_OK + mock_backfill_task.assert_called() + + def test_findings_metadata_backfill_no_resources( + self, authenticated_client, scans_fixture + ): + scan_id = str(scans_fixture[0].id) + with patch( + "api.v1.views.backfill_scan_resource_summaries_task.apply_async" + ) as mock_backfill_task: + response = authenticated_client.get( + reverse("finding-metadata"), + {"filter[scan]": scan_id}, + ) + assert response.status_code == status.HTTP_200_OK + mock_backfill_task.assert_not_called() + + def test_findings_metadata_latest_backfill( + self, authenticated_client, scans_fixture, findings_fixture + ): + scan = scans_fixture[0] + scan.unique_resource_count = 1 + scan.save() + + with patch( + "api.v1.views.backfill_scan_resource_summaries_task.apply_async" + ) as mock_backfill_task: + response = authenticated_client.get(reverse("finding-metadata_latest")) + assert response.status_code == status.HTTP_200_OK + mock_backfill_task.assert_called() + + def test_findings_metadata_latest_backfill_no_resources( + self, authenticated_client, scans_fixture + ): + with patch( + "api.v1.views.backfill_scan_resource_summaries_task.apply_async" + ) as mock_backfill_task: + response = authenticated_client.get(reverse("finding-metadata_latest")) + assert response.status_code == status.HTTP_200_OK + mock_backfill_task.assert_not_called() + def test_findings_latest(self, authenticated_client, latest_scan_finding): response = authenticated_client.get( reverse("finding-latest"), diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 6fe771ebfc..5e0bc93584 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -271,7 +271,7 @@ class SchemaView(SpectacularAPIView): def get(self, request, *args, **kwargs): spectacular_settings.TITLE = "Prowler API" - spectacular_settings.VERSION = "1.9.0" + spectacular_settings.VERSION = "1.9.1" spectacular_settings.DESCRIPTION = ( "Prowler API specification.\n\nThis file is auto-generated." ) @@ -2127,9 +2127,12 @@ class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): # ToRemove: Temporary fallback mechanism if not queryset.exists(): - scan_ids = Scan.objects.filter( + raw_scans_ids = Scan.objects.filter( tenant_id=tenant_id, **scan_based_filters - ).values_list("id", flat=True) + ).values_list("id", "unique_resource_count") + scan_ids = [ + scan_id for scan_id, count in raw_scans_ids if count and count > 0 + ] for scan_id in scan_ids: backfill_scan_resource_summaries_task.apply_async( kwargs={"tenant_id": tenant_id, "scan_id": scan_id} @@ -2215,7 +2218,12 @@ class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet): .order_by("provider_id", "-inserted_at") .distinct("provider_id") ) - latest_scans_ids = list(latest_scans_queryset.values_list("id", flat=True)) + raw_latest_scans_ids = list( + latest_scans_queryset.values_list("id", "unique_resource_count") + ) + latest_scans_ids = [ + scan_id for scan_id, count in raw_latest_scans_ids if count and count > 0 + ] queryset = ResourceScanSummary.objects.filter( tenant_id=tenant_id,