mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
fix(attack-paths): clear Neo4j database cache after scan and queries (#9878)
Co-authored-by: Josema Camacho <josema@prowler.com>
This commit is contained in:
@@ -14,6 +14,7 @@ All notable changes to the **Prowler API** are documented in this file.
|
|||||||
- Use `Findings.all_objects` to avoid the `ActiveProviderPartitionedManager` [(#9869)](https://github.com/prowler-cloud/prowler/pull/9869)
|
- Use `Findings.all_objects` to avoid the `ActiveProviderPartitionedManager` [(#9869)](https://github.com/prowler-cloud/prowler/pull/9869)
|
||||||
- Lazy load Neo4j driver for workers only [(#9872)](https://github.com/prowler-cloud/prowler/pull/9872)
|
- Lazy load Neo4j driver for workers only [(#9872)](https://github.com/prowler-cloud/prowler/pull/9872)
|
||||||
- Improve Cypher query for inserting Findings into Attack Paths scan graphs [(#9874)](https://github.com/prowler-cloud/prowler/pull/9874)
|
- Improve Cypher query for inserting Findings into Attack Paths scan graphs [(#9874)](https://github.com/prowler-cloud/prowler/pull/9874)
|
||||||
|
- Clear Neo4j database cache after Attack Paths scan and each API query [(#9877)](https://github.com/prowler-cloud/prowler/pull/9877)
|
||||||
|
|
||||||
## [1.18.0] (Prowler v5.17.0)
|
## [1.18.0] (Prowler v5.17.0)
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,17 @@ def drop_subgraph(database: str, root_node_label: str, root_node_id: str) -> int
|
|||||||
return 0 # As there are no nodes to delete, the result is empty
|
return 0 # As there are no nodes to delete, the result is empty
|
||||||
|
|
||||||
|
|
||||||
|
def clear_cache(database: str) -> None:
|
||||||
|
query = "CALL db.clearQueryCaches()"
|
||||||
|
|
||||||
|
try:
|
||||||
|
with get_session(database) as session:
|
||||||
|
session.run(query)
|
||||||
|
|
||||||
|
except GraphDatabaseQueryException as exc:
|
||||||
|
logging.warning(f"Failed to clear query cache for database `{database}`: {exc}")
|
||||||
|
|
||||||
|
|
||||||
# Neo4j functions related to Prowler + Cartography
|
# Neo4j functions related to Prowler + Cartography
|
||||||
DATABASE_NAME_TEMPLATE = "db-{attack_paths_scan_id}"
|
DATABASE_NAME_TEMPLATE = "db-{attack_paths_scan_id}"
|
||||||
|
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ class RetryableSession:
|
|||||||
return method(*args, **kwargs)
|
return method(*args, **kwargs)
|
||||||
|
|
||||||
except (
|
except (
|
||||||
neo4j.exceptions.ServiceUnavailable,
|
|
||||||
ConnectionResetError,
|
|
||||||
BrokenPipeError,
|
BrokenPipeError,
|
||||||
|
ConnectionResetError,
|
||||||
|
neo4j.exceptions.ServiceUnavailable,
|
||||||
) as exc: # pragma: no cover - depends on infra
|
) as exc: # pragma: no cover - depends on infra
|
||||||
last_exc = exc
|
last_exc = exc
|
||||||
attempt += 1
|
attempt += 1
|
||||||
|
|||||||
@@ -3867,6 +3867,7 @@ class TestAttackPathsScanViewSet:
|
|||||||
"api.v1.views.attack_paths_views_helpers.execute_attack_paths_query",
|
"api.v1.views.attack_paths_views_helpers.execute_attack_paths_query",
|
||||||
return_value=graph_payload,
|
return_value=graph_payload,
|
||||||
) as mock_execute,
|
) as mock_execute,
|
||||||
|
patch("api.v1.views.graph_database.clear_cache") as mock_clear_cache,
|
||||||
):
|
):
|
||||||
response = authenticated_client.post(
|
response = authenticated_client.post(
|
||||||
reverse(
|
reverse(
|
||||||
@@ -3889,6 +3890,7 @@ class TestAttackPathsScanViewSet:
|
|||||||
query_definition,
|
query_definition,
|
||||||
prepared_parameters,
|
prepared_parameters,
|
||||||
)
|
)
|
||||||
|
mock_clear_cache.assert_called_once_with(attack_paths_scan.graph_database)
|
||||||
result = response.json()["data"]
|
result = response.json()["data"]
|
||||||
attributes = result["attributes"]
|
attributes = result["attributes"]
|
||||||
assert attributes["nodes"] == graph_payload["nodes"]
|
assert attributes["nodes"] == graph_payload["nodes"]
|
||||||
@@ -4000,6 +4002,7 @@ class TestAttackPathsScanViewSet:
|
|||||||
"api.v1.views.attack_paths_views_helpers.execute_attack_paths_query",
|
"api.v1.views.attack_paths_views_helpers.execute_attack_paths_query",
|
||||||
return_value={"nodes": [], "relationships": []},
|
return_value={"nodes": [], "relationships": []},
|
||||||
),
|
),
|
||||||
|
patch("api.v1.views.graph_database.clear_cache"),
|
||||||
):
|
):
|
||||||
response = authenticated_client.post(
|
response = authenticated_client.post(
|
||||||
reverse(
|
reverse(
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ from rest_framework_json_api.views import RelationshipView, Response
|
|||||||
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
||||||
|
|
||||||
from api.attack_paths import (
|
from api.attack_paths import (
|
||||||
|
database as graph_database,
|
||||||
get_queries_for_provider,
|
get_queries_for_provider,
|
||||||
get_query_by_id,
|
get_query_by_id,
|
||||||
views_helpers as attack_paths_views_helpers,
|
views_helpers as attack_paths_views_helpers,
|
||||||
@@ -2435,6 +2436,7 @@ class AttackPathsScanViewSet(BaseRLSViewSet):
|
|||||||
graph = attack_paths_views_helpers.execute_attack_paths_query(
|
graph = attack_paths_views_helpers.execute_attack_paths_query(
|
||||||
attack_paths_scan, query_definition, parameters
|
attack_paths_scan, query_definition, parameters
|
||||||
)
|
)
|
||||||
|
graph_database.clear_cache(attack_paths_scan.graph_database)
|
||||||
|
|
||||||
status_code = status.HTTP_200_OK
|
status_code = status.HTTP_200_OK
|
||||||
if not graph.get("nodes"):
|
if not graph.get("nodes"):
|
||||||
|
|||||||
@@ -137,6 +137,11 @@ def run(tenant_id: str, scan_id: str, task_id: str) -> dict[str, Any]:
|
|||||||
neo4j_session, prowler_api_provider, scan_id, cartography_config
|
neo4j_session, prowler_api_provider, scan_id, cartography_config
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Clearing Neo4j cache for database {cartography_config.neo4j_database}"
|
||||||
|
)
|
||||||
|
graph_database.clear_cache(cartography_config.neo4j_database)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Completed Cartography ({attack_paths_scan.id}) for "
|
f"Completed Cartography ({attack_paths_scan.id}) for "
|
||||||
f"{prowler_api_provider.provider.upper()} provider {prowler_api_provider.id}"
|
f"{prowler_api_provider.provider.upper()} provider {prowler_api_provider.id}"
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class TestAttackPathsRun:
|
|||||||
"tasks.jobs.attack_paths.scan.graph_database.get_session",
|
"tasks.jobs.attack_paths.scan.graph_database.get_session",
|
||||||
return_value=session_ctx,
|
return_value=session_ctx,
|
||||||
) as mock_get_session,
|
) as mock_get_session,
|
||||||
|
patch("tasks.jobs.attack_paths.scan.graph_database.clear_cache"),
|
||||||
patch(
|
patch(
|
||||||
"tasks.jobs.attack_paths.scan.cartography_create_indexes.run"
|
"tasks.jobs.attack_paths.scan.cartography_create_indexes.run"
|
||||||
) as mock_cartography_indexes,
|
) as mock_cartography_indexes,
|
||||||
|
|||||||
Reference in New Issue
Block a user