From 7dfafb93370f47b7cf58f6dd77c92135b9823c73 Mon Sep 17 00:00:00 2001 From: Josema Camacho Date: Thu, 22 Jan 2026 14:51:22 +0100 Subject: [PATCH] fix(attack-paths): read findings using replica DB and add more logs (#9861) --- api/CHANGELOG.md | 5 ++ .../backend/tasks/jobs/attack_paths/aws.py | 16 +++++++ .../tasks/jobs/attack_paths/prowler.py | 48 ++++++++++++------- .../backend/tasks/jobs/attack_paths/scan.py | 9 ++++ .../tasks/tests/test_attack_paths_scan.py | 3 ++ 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 608033ce8c..c37ff6de14 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -9,6 +9,10 @@ All notable changes to the **Prowler API** are documented in this file. - Improve API startup process by `manage.py` argument detection [(#9856)](https://github.com/prowler-cloud/prowler/pull/9856) - Deleting providers don't try to delete a `None` Neo4j database when an Attack Paths scan is scheduled [(#9858)](https://github.com/prowler-cloud/prowler/pull/9858) +### Fixed + +- Use replica database for reading Findings to add them to the Attack Paths graph [(#9861)](https://github.com/prowler-cloud/prowler/pull/9861) + ## [1.18.0] (Prowler v5.17.0) ### Added @@ -21,6 +25,7 @@ All notable changes to the **Prowler API** are documented in this file. - Attack Paths: `/api/v1/attack-paths-scans` for AWS providers backed by Neo4j [(#9805)](https://github.com/prowler-cloud/prowler/pull/9805) ### Security + - Django 5.1.15 (CVE-2025-64460, CVE-2025-13372), Werkzeug 3.1.4 (CVE-2025-66221), sqlparse 0.5.5 (PVE-2025-82038), fonttools 4.60.2 (CVE-2025-66034) [(#9730)](https://github.com/prowler-cloud/prowler/pull/9730) - `safety` to `3.7.0` and `filelock` to `3.20.3` due to [Safety vulnerability 82754 (CVE-2025-68146)](https://data.safetycli.com/v/82754/97c/) [(#9816)](https://github.com/prowler-cloud/prowler/pull/9816) - `pyasn1` to v0.6.2 to address [CVE-2026-23490](https://nvd.nist.gov/vuln/detail/CVE-2026-23490) [(#9818)](https://github.com/prowler-cloud/prowler/pull/9818) diff --git a/api/src/backend/tasks/jobs/attack_paths/aws.py b/api/src/backend/tasks/jobs/attack_paths/aws.py index e244b6cca7..1bfe4eefac 100644 --- a/api/src/backend/tasks/jobs/attack_paths/aws.py +++ b/api/src/backend/tasks/jobs/attack_paths/aws.py @@ -59,6 +59,7 @@ def start_aws_ingestion( ) # Starting with sync functions + logger.info(f"Syncing organizations for AWS account {prowler_api_provider.uid}") cartography_aws.organizations.sync( neo4j_session, {prowler_api_provider.alias: prowler_api_provider.uid}, @@ -84,13 +85,22 @@ def start_aws_ingestion( ) if "permission_relationships" in requested_syncs: + logger.info( + f"Syncing function permission_relationships for AWS account {prowler_api_provider.uid}" + ) cartography_aws.RESOURCE_FUNCTIONS["permission_relationships"](**sync_args) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 88) if "resourcegroupstaggingapi" in requested_syncs: + logger.info( + f"Syncing function resourcegroupstaggingapi for AWS account {prowler_api_provider.uid}" + ) cartography_aws.RESOURCE_FUNCTIONS["resourcegroupstaggingapi"](**sync_args) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 89) + logger.info( + f"Syncing ec2_iaminstanceprofile scoped analysis for AWS account {prowler_api_provider.uid}" + ) cartography_aws.run_scoped_analysis_job( "aws_ec2_iaminstanceprofile.json", neo4j_session, @@ -98,6 +108,9 @@ def start_aws_ingestion( ) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 90) + logger.info( + f"Syncing lambda_ecr analysis for AWS account {prowler_api_provider.uid}" + ) cartography_aws.run_analysis_job( "aws_lambda_ecr.json", neo4j_session, @@ -105,6 +118,7 @@ def start_aws_ingestion( ) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 91) + logger.info(f"Syncing metadata for AWS account {prowler_api_provider.uid}") cartography_aws.merge_module_sync_metadata( neo4j_session, group_type="AWSAccount", @@ -118,6 +132,7 @@ def start_aws_ingestion( # Removing the added extra field del common_job_parameters["AWS_ID"] + logger.info(f"Syncing cleanup_job for AWS account {prowler_api_provider.uid}") cartography_aws.run_cleanup_job( "aws_post_ingestion_principals_cleanup.json", neo4j_session, @@ -125,6 +140,7 @@ def start_aws_ingestion( ) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 93) + logger.info(f"Syncing analysis for AWS account {prowler_api_provider.uid}") cartography_aws._perform_aws_analysis( requested_syncs, neo4j_session, common_job_parameters ) diff --git a/api/src/backend/tasks/jobs/attack_paths/prowler.py b/api/src/backend/tasks/jobs/attack_paths/prowler.py index 8678045811..1cf904fea8 100644 --- a/api/src/backend/tasks/jobs/attack_paths/prowler.py +++ b/api/src/backend/tasks/jobs/attack_paths/prowler.py @@ -4,6 +4,7 @@ from cartography.client.core.tx import run_write_query from cartography.config import Config as CartographyConfig from celery.utils.log import get_task_logger +from api.db_router import MainRouter from api.db_utils import rls_transaction from api.models import Provider, ResourceFindingMapping from config.env import env @@ -95,8 +96,15 @@ def analysis( scan_id: str, config: CartographyConfig, ) -> None: + logger.info(f"Getting Prowler findings for AWS account {prowler_api_provider.uid}") findings_data = get_provider_last_scan_findings(prowler_api_provider, scan_id) + + logger.info(f"Loading Prowler findings for AWS account {prowler_api_provider.uid}") load_findings(neo4j_session, findings_data, prowler_api_provider, config) + + logger.info( + f"Cleaning up Prowler findings for AWS account {prowler_api_provider.uid}" + ) cleanup_findings(neo4j_session, prowler_api_provider, config) @@ -105,24 +113,28 @@ def get_provider_last_scan_findings( scan_id: str, ) -> list[dict[str, str]]: with rls_transaction(prowler_api_provider.tenant_id): - resource_finding_qs = ResourceFindingMapping.objects.filter( - finding__scan_id=scan_id, - ).values( - "resource__uid", - "finding__id", - "finding__uid", - "finding__inserted_at", - "finding__updated_at", - "finding__first_seen_at", - "finding__scan_id", - "finding__delta", - "finding__status", - "finding__status_extended", - "finding__severity", - "finding__check_id", - "finding__check_metadata__checktitle", - "finding__muted", - "finding__muted_reason", + resource_finding_qs = ( + ResourceFindingMapping.objects.using(MainRouter.replica_db) + .filter( + finding__scan_id=scan_id, + ) + .values( + "resource__uid", + "finding__id", + "finding__uid", + "finding__inserted_at", + "finding__updated_at", + "finding__first_seen_at", + "finding__scan_id", + "finding__delta", + "finding__status", + "finding__status_extended", + "finding__severity", + "finding__check_id", + "finding__check_metadata__checktitle", + "finding__muted", + "finding__muted_reason", + ) ) findings = [] diff --git a/api/src/backend/tasks/jobs/attack_paths/scan.py b/api/src/backend/tasks/jobs/attack_paths/scan.py index d2cf275842..88b46ccec6 100644 --- a/api/src/backend/tasks/jobs/attack_paths/scan.py +++ b/api/src/backend/tasks/jobs/attack_paths/scan.py @@ -117,13 +117,22 @@ def run(tenant_id: str, scan_id: str, task_id: str) -> dict[str, Any]: ) # Post-processing: Just keeping it to be more Cartography compliant + logger.info( + f"Syncing Cartography ontology for AWS account {prowler_api_provider.uid}" + ) cartography_ontology.run(neo4j_session, cartography_config) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 95) + logger.info( + f"Syncing Cartography analysis for AWS account {prowler_api_provider.uid}" + ) cartography_analysis.run(neo4j_session, cartography_config) db_utils.update_attack_paths_scan_progress(attack_paths_scan, 96) # Adding Prowler nodes and relationships + logger.info( + f"Syncing Prowler analysis for AWS account {prowler_api_provider.uid}" + ) prowler.analysis( neo4j_session, prowler_api_provider, scan_id, cartography_config ) diff --git a/api/src/backend/tasks/tests/test_attack_paths_scan.py b/api/src/backend/tasks/tests/test_attack_paths_scan.py index c94e8c83b6..226d53f60f 100644 --- a/api/src/backend/tasks/tests/test_attack_paths_scan.py +++ b/api/src/backend/tasks/tests/test_attack_paths_scan.py @@ -402,6 +402,9 @@ class TestAttackPathsProwlerHelpers: with patch( "tasks.jobs.attack_paths.prowler.rls_transaction", new=lambda *args, **kwargs: nullcontext(), + ), patch( + "tasks.jobs.attack_paths.prowler.MainRouter.replica_db", + "default", ): findings_data = prowler_module.get_provider_last_scan_findings( provider,