fix: missing resource_name in GCP and Azure Defender checks (#8503)

Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
This commit is contained in:
Prowler Bot
2025-08-11 16:24:06 +02:00
committed by GitHub
parent 3d9d30111f
commit a2065bc80b
32 changed files with 131 additions and 27 deletions
+1
View File
@@ -16,6 +16,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
### Fixed
- Order requirements by ID in Prowler ThreatScore AWS compliance framework [(#8495)](https://github.com/prowler-cloud/prowler/pull/8495)
- Add explicit resource name to GCP and Azure Defender checks [(#8352)](https://github.com/prowler-cloud/prowler/pull/8352)
- Validation errors in Azure and M365 providers [(#8353)](https://github.com/prowler-cloud/prowler/pull/8353)
---
+1 -3
View File
@@ -550,9 +550,7 @@ class Check_Report_GCP(Check_Report):
or ""
)
self.resource_name = (
resource_name
or getattr(resource, "name", "")
or getattr(resource, "id", "")
resource_name or getattr(resource, "name", "") or "GCP Project"
)
self.project_id = project_id or getattr(resource, "project_id", "")
self.location = (
@@ -14,6 +14,11 @@ class defender_additional_email_configured_with_a_security_contact(Check):
report = Check_Report_Azure(
metadata=self.metadata(), resource=contact_configuration
)
report.resource_name = (
contact_configuration.name
if contact_configuration.name
else "Security Contact"
)
report.subscription = subscription_name
if len(contact_configuration.emails) > 0:
@@ -31,6 +31,11 @@ class defender_attack_path_notifications_properly_configured(Check):
report = Check_Report_Azure(
metadata=self.metadata(), resource=contact_configuration
)
report.resource_name = (
contact_configuration.name
if contact_configuration.name
else "Security Contact"
)
report.subscription = subscription_name
actual_risk_level = getattr(
contact_configuration, "attack_path_minimal_risk_level", None
@@ -14,6 +14,11 @@ class defender_ensure_notify_alerts_severity_is_high(Check):
report = Check_Report_Azure(
metadata=self.metadata(), resource=contact_configuration
)
report.resource_name = (
contact_configuration.name
if contact_configuration.name
else "Security Contact"
)
report.subscription = subscription_name
report.status = "FAIL"
report.status_extended = f"Notifications are not enabled for alerts with a minimum severity of high or lower in subscription {subscription_name}."
@@ -12,7 +12,13 @@ class defender_ensure_notify_emails_to_owners(Check):
) in defender_client.security_contact_configurations.items():
for contact_configuration in security_contact_configurations.values():
report = Check_Report_Azure(
metadata=self.metadata(), resource=contact_configuration
metadata=self.metadata(),
resource=contact_configuration,
)
report.resource_name = (
contact_configuration.name
if contact_configuration.name
else "Security Contact"
)
report.subscription = subscription_name
if (
+20 -2
View File
@@ -659,6 +659,9 @@ class GcpProvider(Provider):
if asset["resource"]["data"].get("name")
else project_id
)
# Handle empty or null project names
if not project_name or project_name.strip() == "":
project_name = "GCP Project"
gcp_project = GCPProject(
number=project_number,
id=project_id,
@@ -717,6 +720,9 @@ class GcpProvider(Provider):
if project.get("name")
else project_id
)
# Handle empty or null project names
if not project_name or project_name.strip() == "":
project_name = "GCP Project"
project_id = project["projectId"]
gcp_project = GCPProject(
number=project_number,
@@ -757,9 +763,15 @@ class GcpProvider(Provider):
# If no projects were able to be accessed via API, add them manually if provided by the user in arguments
if project_ids:
for input_project in project_ids:
# Handle empty or null project names
project_name = (
input_project
if input_project and input_project.strip() != ""
else "GCP Project"
)
projects[input_project] = GCPProject(
id=input_project,
name=input_project,
name=project_name,
number=0,
labels={},
lifecycle_state="ACTIVE",
@@ -768,9 +780,15 @@ class GcpProvider(Provider):
elif credentials_file:
with open(credentials_file, "r", encoding="utf-8") as file:
project_id = json.load(file)["project_id"]
# Handle empty or null project names
project_name = (
project_id
if project_id and project_id.strip() != ""
else "GCP Project"
)
projects[project_id] = GCPProject(
id=project_id,
name=project_id,
name=project_name,
number=0,
labels={},
lifecycle_state="ACTIVE",
@@ -13,7 +13,7 @@ class iam_no_service_roles_at_project_level(Check):
metadata=self.metadata(),
resource=binding,
resource_id=binding.role,
resource_name=binding.role,
resource_name=binding.role if binding.role else "Service Role",
location=cloudresourcemanager_client.region,
)
if binding.role in [
@@ -31,7 +31,6 @@ class iam_no_service_roles_at_project_level(Check):
metadata=self.metadata(),
resource=cloudresourcemanager_client.projects[project],
project_id=project,
resource_name=project,
location=cloudresourcemanager_client.region,
)
report.status = "PASS"
@@ -20,6 +20,7 @@ class logging_log_metric_filter_and_alert_for_audit_configuration_changes_enable
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled(
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_custom_role_changes_enabled(Check)
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled(
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -17,6 +17,7 @@ class logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled(
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled(Check)
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -18,6 +18,7 @@ class logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled(
metadata=self.metadata(),
resource=metric,
location=logging_client.region,
resource_name=metric.name if metric.name else "Log Metric Filter",
)
projects_with_metric.add(metric.project_id)
report.status = "FAIL"
@@ -26,6 +26,11 @@ class logging_sink_created(Check):
metadata=self.metadata(),
resource=projects_with_logging_sink[project],
location=logging_client.region,
resource_name=(
projects_with_logging_sink[project].name
if projects_with_logging_sink[project].name
else "Logging Sink"
),
)
report.status = "PASS"
report.status_extended = f"Sink {projects_with_logging_sink[project].name} is enabled exporting copies of all the log entries in project {project}."
@@ -175,7 +175,7 @@ class Test_compute_project_os_login_enabled:
result[0].status_extended,
)
assert result[0].resource_id == project.id
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].location == "global"
assert result[0].project_id == GCP_PROJECT_ID
@@ -225,6 +225,6 @@ class Test_compute_project_os_login_enabled:
result[0].status_extended,
)
assert result[0].resource_id == project.id
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].location == "global"
assert result[0].project_id == GCP_PROJECT_ID
@@ -44,6 +44,7 @@ class Test_iam_account_access_approval_enabled:
result[0].status_extended,
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == "test"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == "global"
@@ -95,5 +96,58 @@ class Test_iam_account_access_approval_enabled:
result[0].status_extended,
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == "test"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == "global"
def test_iam_project_with_settings_empty_project_name(self):
cloudresourcemanager_client = mock.MagicMock()
accessapproval_client = mock.MagicMock()
accessapproval_client.project_ids = [GCP_PROJECT_ID]
accessapproval_client.region = "global"
accessapproval_client.projects = {
GCP_PROJECT_ID: GCPProject(
id=GCP_PROJECT_ID,
number="123456789012",
name="",
labels={},
lifecycle_state="ACTIVE",
)
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_gcp_provider(),
),
mock.patch(
"prowler.providers.gcp.services.iam.iam_account_access_approval_enabled.iam_account_access_approval_enabled.accessapproval_client",
new=accessapproval_client,
),
mock.patch(
"prowler.providers.gcp.services.iam.iam_service.cloudresourcemanager_client",
new=cloudresourcemanager_client,
),
):
from prowler.providers.gcp.services.iam.iam_service import Setting
accessapproval_client.settings = {
GCP_PROJECT_ID: Setting(name="test", project_id=GCP_PROJECT_ID)
}
from prowler.providers.gcp.services.iam.iam_account_access_approval_enabled.iam_account_access_approval_enabled import (
iam_account_access_approval_enabled,
)
check = iam_account_access_approval_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"has Access Approval enabled",
result[0].status_extended,
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == "global"
@@ -176,7 +176,7 @@ class Test_iam_audit_logs_enabled:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -226,6 +226,6 @@ class Test_iam_audit_logs_enabled:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -113,7 +113,7 @@ class Test_iam_no_service_roles_at_project_level:
result[0].status_extended,
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "test"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == cloudresourcemanager_client.region
@@ -255,6 +255,6 @@ class Test_iam_no_service_roles_at_project_level:
result[0].status_extended,
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == cloudresourcemanager_client.region
@@ -213,7 +213,7 @@ class Test_iam_role_kms_enforce_separation_of_duties:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -277,6 +277,6 @@ class Test_iam_role_kms_enforce_separation_of_duties:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -213,7 +213,7 @@ class Test_iam_role_sa_enforce_separation_of_duties:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -277,6 +277,6 @@ class Test_iam_role_sa_enforce_separation_of_duties:
r.status_extended,
)
assert r.resource_id == GCP_PROJECT_ID
assert r.resource_name == GCP_PROJECT_ID
assert r.resource_name == "GCP Project"
assert r.project_id == GCP_PROJECT_ID
assert r.location == cloudresourcemanager_client.region
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_audit_configuration_changes_e
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_bucket_permission_changes_ena
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_custom_role_changes_enabled:
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_project_ownership_changes_ena
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_sql_instance_configuration_ch
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_ena
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled:
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -141,7 +141,7 @@ class Test_logging_log_metric_filter_and_alert_for_vpc_network_route_changes_ena
== f"There are no log metric filters or alerts associated in project {GCP_PROJECT_ID}."
)
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
@@ -204,7 +204,7 @@ class Test_logging_sink_created:
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].resource_id == GCP_PROJECT_ID
assert result[0].resource_name == GCP_PROJECT_ID
assert result[0].resource_name == "GCP Project"
assert result[0].project_id == GCP_PROJECT_ID
assert result[0].location == GCP_EU1_LOCATION
assert (