Compare commits

..

4 Commits

Author SHA1 Message Date
Josema Camacho
47b33ca4dd fix(api): remove clear_cache from attack paths read-only query endpoints - Fix tests 2026-04-07 08:54:49 +02:00
Josema Camacho
ec6516f5de ix(api): remove clear_cache from attack paths read-only query endpoints 2026-04-07 08:43:48 +02:00
kaiisfree
c99ed991b7 fix: show all checks including threat-detection in --list-checks (#10578)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: kaiisfree <kai@users.noreply.github.com>
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2026-04-06 16:55:15 +01:00
Hugo Pereira Brito
7c0034524a fix(sdk): add missing __init__.py for codebuild GitHub orgs check (#10584) 2026-04-06 16:40:04 +01:00
10 changed files with 65 additions and 22 deletions

View File

@@ -28,6 +28,7 @@ All notable changes to the **Prowler API** are documented in this file.
- Membership `post_delete` signal using raw FK ids to avoid `DoesNotExist` during cascade deletions [(#10497)](https://github.com/prowler-cloud/prowler/pull/10497)
- Finding group resources endpoints returning false 404 when filters match no results, and `sort` parameter being ignored [(#10510)](https://github.com/prowler-cloud/prowler/pull/10510)
- Jira integration failing with `JiraInvalidIssueTypeError` on non-English Jira instances due to hardcoded `"Task"` issue type; now dynamically fetches available issue types per project [(#10534)](https://github.com/prowler-cloud/prowler/pull/10534)
- Attack Paths: Remove `clear_cache` call from read-only query endpoints; cache clearing belongs to the scan/ingestion flow, not API queries [(#10586)](https://github.com/prowler-cloud/prowler/pull/10586)
### 🔐 Security

View File

@@ -4287,7 +4287,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.attack_paths_views_helpers.execute_query",
return_value=graph_payload,
) as mock_execute,
patch("api.v1.views.graph_database.clear_cache") as mock_clear_cache,
):
response = authenticated_client.post(
reverse(
@@ -4314,7 +4313,6 @@ class TestAttackPathsScanViewSet:
prepared_parameters,
provider_id,
)
mock_clear_cache.assert_called_once_with(expected_db_name)
result = response.json()["data"]
attributes = result["attributes"]
assert attributes["nodes"] == graph_payload["nodes"]
@@ -4369,7 +4367,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.attack_paths_views_helpers.execute_query",
return_value=graph_payload,
),
patch("api.v1.views.graph_database.clear_cache"),
):
response = authenticated_client.post(
reverse(
@@ -4453,7 +4450,6 @@ class TestAttackPathsScanViewSet:
"truncated": False,
},
),
patch("api.v1.views.graph_database.clear_cache"),
patch(
"api.v1.views.graph_database.get_database_name", return_value="db-test"
),
@@ -4508,7 +4504,6 @@ class TestAttackPathsScanViewSet:
"truncated": False,
},
),
patch("api.v1.views.graph_database.clear_cache"),
patch(
"api.v1.views.graph_database.get_database_name", return_value="db-test"
),
@@ -4588,7 +4583,6 @@ class TestAttackPathsScanViewSet:
"truncated": False,
},
),
patch("api.v1.views.graph_database.clear_cache"),
):
response = authenticated_client.post(
reverse(
@@ -4654,7 +4648,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.graph_database.get_database_name",
return_value="db-test",
),
patch("api.v1.views.graph_database.clear_cache"),
):
response = authenticated_client.post(
reverse(
@@ -4711,7 +4704,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.graph_database.get_database_name",
return_value="db-test",
),
patch("api.v1.views.graph_database.clear_cache"),
):
response = authenticated_client.post(
reverse(
@@ -4758,7 +4750,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.graph_database.get_database_name",
return_value="db-test",
),
patch("api.v1.views.graph_database.clear_cache"),
):
response = authenticated_client.post(
reverse(
@@ -5109,9 +5100,6 @@ class TestAttackPathsScanViewSet:
"api.v1.views.graph_database.get_database_name",
return_value="db-test",
),
patch(
"api.v1.views.graph_database.clear_cache",
),
):
for i in range(11):
response = authenticated_client.post(

View File

@@ -2628,7 +2628,6 @@ class AttackPathsScanViewSet(BaseRLSViewSet):
provider_id,
)
query_duration = time.monotonic() - start
graph_database.clear_cache(database_name)
result_nodes = len(graph.get("nodes", []))
result_relationships = len(graph.get("relationships", []))
@@ -2696,7 +2695,6 @@ class AttackPathsScanViewSet(BaseRLSViewSet):
provider_id,
)
query_duration = time.monotonic() - start
graph_database.clear_cache(database_name)
query_length = len(serializer.validated_data["query"])
result_nodes = len(graph.get("nodes", []))

12
poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
[[package]]
name = "about-time"
@@ -4444,14 +4444,14 @@ files = [
[[package]]
name = "pre-commit"
version = "4.5.1"
version = "4.2.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
python-versions = ">=3.10"
python-versions = ">=3.9"
groups = ["dev"]
files = [
{file = "pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77"},
{file = "pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61"},
{file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"},
{file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"},
]
[package.dependencies]
@@ -6743,4 +6743,4 @@ files = [
[metadata]
lock-version = "2.1"
python-versions = ">=3.10,<3.13"
content-hash = "442dc9728a450d6af769362abba1f7221e3aa6c615fc6e61d11c15b1f5a43768"
content-hash = "91739ee5e383337160f9f08b76944ab4e8629c94084c8a9d115246862557f7c5"

View File

@@ -29,6 +29,8 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `return` statements in `finally` blocks replaced across IAM, Organizations, GCP provider, and custom checks metadata to stop silently swallowing exceptions [(#10102)](https://github.com/prowler-cloud/prowler/pull/10102)
- `JiraConnection` now includes issue types per project fetched during `test_connection`, fixing `JiraInvalidIssueTypeError` on non-English Jira instances [(#10534)](https://github.com/prowler-cloud/prowler/pull/10534)
- `--list-checks` and `--list-checks-json` now include `threat-detection` category checks in their output [(#10578)](https://github.com/prowler-cloud/prowler/pull/10578)
- Missing `__init__.py` in `codebuild_project_uses_allowed_github_organizations` check preventing discovery by `--list-checks` [(#10584)](https://github.com/prowler-cloud/prowler/pull/10584)
### 🔐 Security

View File

@@ -271,6 +271,8 @@ def prowler():
categories=categories,
resource_groups=resource_groups,
provider=provider,
list_checks=getattr(args, "list_checks", False)
or getattr(args, "list_checks_json", False),
)
# if --list-checks-json, dump a json file and exit

View File

@@ -20,6 +20,7 @@ def load_checks_to_execute(
compliance_frameworks: list = None,
categories: set = None,
resource_groups: set = None,
list_checks: bool = False,
) -> set:
"""Generate the list of checks to execute based on the cloud provider and the input arguments given"""
try:
@@ -209,7 +210,12 @@ def load_checks_to_execute(
):
checks_to_execute.add(check_name)
# Only execute threat detection checks if threat-detection category is set
if (not categories or "threat-detection" not in categories) and not check_list:
# Skip this exclusion when listing checks (--list-checks or --list-checks-json)
if (
(not categories or "threat-detection" not in categories)
and not check_list
and not list_checks
):
for threat_detection_check in check_categories.get("threat-detection", []):
checks_to_execute.discard(threat_detection_check)

View File

@@ -127,7 +127,7 @@ mock = "5.2.0"
moto = {extras = ["all"], version = "5.1.11"}
openapi-schema-validator = "0.6.3"
openapi-spec-validator = "0.7.1"
pre-commit = "4.5.1"
pre-commit = "4.2.0"
pylint = "3.3.4"
pytest = "8.3.5"
pytest-cov = "6.0.0"

View File

@@ -629,3 +629,49 @@ class TestCheckLoader:
provider=self.provider,
)
assert exc_info.value.code == 1
def test_list_checks_includes_threat_detection(self):
"""Test that list_checks=True includes threat-detection checks (fixes #10576)"""
bulk_checks_metadata = {
S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME: self.get_custom_check_s3_metadata(),
CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME: self.get_threat_detection_check_metadata(),
}
result = load_checks_to_execute(
bulk_checks_metadata=bulk_checks_metadata,
provider=self.provider,
list_checks=True,
)
assert CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME in result
assert S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME in result
def test_list_checks_with_service_includes_threat_detection(self):
"""Test that list_checks=True with service filter includes threat-detection checks (fixes #10576)"""
bulk_checks_metadata = {
S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME: self.get_custom_check_s3_metadata(),
CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME: self.get_threat_detection_check_metadata(),
}
service_list = ["cloudtrail"]
result = load_checks_to_execute(
bulk_checks_metadata=bulk_checks_metadata,
service_list=service_list,
provider=self.provider,
list_checks=True,
)
assert CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME in result
assert S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME not in result
def test_scan_still_excludes_threat_detection_by_default(self):
"""Test that without list_checks, threat-detection checks are still excluded"""
bulk_checks_metadata = {
S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME: self.get_custom_check_s3_metadata(),
CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME: self.get_threat_detection_check_metadata(),
}
result = load_checks_to_execute(
bulk_checks_metadata=bulk_checks_metadata,
provider=self.provider,
)
assert CLOUDTRAIL_THREAT_DETECTION_ENUMERATION_NAME not in result
assert S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME in result