From c0ae8b9739da2d7eaad5ed1385a166aeb6d34023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 18 Jun 2026 08:56:04 +0200 Subject: [PATCH] feat(compliance): add DORA compliance framework for Azure (#11551) --- api/src/backend/api/compliance.py | 4 +- api/src/backend/api/v1/views.py | 4 +- api/src/backend/tasks/tasks.py | 4 +- .../security-compliance-framework.mdx | 12 +- prowler/CHANGELOG.md | 2 + .../{dora.json => dora_2022_2554.json} | 245 ++++++++++++++++++ ui/.prettierignore | 1 + ui/CHANGELOG.md | 1 + .../compliance-download-container.test.tsx | 4 +- .../icons/compliance/IconCompliance.tsx | 5 +- ui/dependency-log.json | 12 +- ui/lib/compliance/compliance-mapper.ts | 2 +- .../compliance-report-types.test.ts | 2 +- ui/lib/compliance/compliance-report-types.ts | 2 +- ui/types/compliance.ts | 2 +- 15 files changed, 276 insertions(+), 26 deletions(-) rename prowler/compliance/{dora.json => dora_2022_2554.json} (69%) diff --git a/api/src/backend/api/compliance.py b/api/src/backend/api/compliance.py index 202825185b..77c45cbffd 100644 --- a/api/src/backend/api/compliance.py +++ b/api/src/backend/api/compliance.py @@ -112,14 +112,14 @@ def get_compliance_frameworks(provider_type: Provider.ProviderChoices) -> list[s """List compliance framework identifiers available for `provider_type`. Includes both per-provider frameworks and universal top-level frameworks - (e.g. ``dora``, ``csa_ccm_4.0``). + (e.g. ``dora_2022_2554``, ``csa_ccm_4.0``). Args: provider_type (Provider.ProviderChoices): The cloud provider type (e.g., "aws", "azure", "gcp", "m365"). Returns: - list[str]: Framework identifiers (e.g., "cis_1.4_aws", "dora"). + list[str]: Framework identifiers (e.g., "cis_1.4_aws", "dora_2022_2554"). """ global AVAILABLE_COMPLIANCE_FRAMEWORKS if provider_type not in AVAILABLE_COMPLIANCE_FRAMEWORKS: diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 7e9aae5b94..4cf39cdce1 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -1884,7 +1884,7 @@ class ProviderViewSet(DisablePaginationMixin, BaseRLSViewSet): description=( "Download a specific compliance report as an OCSF JSON file. " "Only universal frameworks that declare an output configuration " - "produce this artifact (currently 'dora' and 'csa_ccm_4.0'); any " + "produce this artifact (currently 'dora_2022_2554' and 'csa_ccm_4.0'); any " "other framework returns 404." ), parameters=[ @@ -1893,7 +1893,7 @@ class ProviderViewSet(DisablePaginationMixin, BaseRLSViewSet): type=str, location=OpenApiParameter.PATH, required=True, - description="The compliance report name, like 'dora'", + description="The compliance report name, like 'dora_2022_2554'", ), ], responses={ diff --git a/api/src/backend/tasks/tasks.py b/api/src/backend/tasks/tasks.py index e617339973..e1e7100ae6 100644 --- a/api/src/backend/tasks/tasks.py +++ b/api/src/backend/tasks/tasks.py @@ -560,7 +560,7 @@ def generate_outputs_task(scan_id: str, provider_id: str, tenant_id: str): # Per-framework exporters in `COMPLIANCE_CLASS_MAP` consume the legacy bulk. frameworks_bulk = Compliance.get_bulk(provider_type) - # Universal-only frameworks (top-level JSONs like `dora.json`) are emitted + # Universal-only frameworks (top-level JSONs like `dora_2022_2554.json`) are emitted # via `process_universal_compliance_frameworks` below. universal_bulk = get_prowler_provider_compliance(provider_type) universal_only_names = { @@ -650,7 +650,7 @@ def generate_outputs_task(scan_id: str, provider_id: str, tenant_id: str): writer.batch_write_data_to_file(**extra) writer._data.clear() - # Universal-only frameworks (e.g. `dora.json`). + # Universal-only frameworks (e.g. `dora_2022_2554.json`). if universal_only_names: process_universal_compliance_frameworks( input_compliance_frameworks=universal_only_names, diff --git a/docs/developer-guide/security-compliance-framework.mdx b/docs/developer-guide/security-compliance-framework.mdx index 030d876aab..cf756c4da0 100644 --- a/docs/developer-guide/security-compliance-framework.mdx +++ b/docs/developer-guide/security-compliance-framework.mdx @@ -38,7 +38,7 @@ Before adding a new framework, complete the following checks: - **Verify the framework is not already supported.** Inspect `prowler/compliance/` and every `prowler/compliance//` for an existing JSON file matching the name and version. - **Confirm the required checks exist.** Every requirement that can be automated must point to one or more existing Prowler checks. For each missing check, implement it first by following the [Prowler Checks](/developer-guide/checks) guide. - **Review a reference framework.** Use an existing framework with a similar structure as your template: - - Universal: `prowler/compliance/dora.json`, `prowler/compliance/csa_ccm_4.0.json`. + - Universal: `prowler/compliance/dora_2022_2554.json`, `prowler/compliance/csa_ccm_4.0.json`. - Legacy: `prowler/compliance/aws/cis_2.0_aws.json` (canonical CIS shape), `prowler/compliance/aws/ccc_aws.json`, `prowler/compliance/aws/ens_rd2022_aws.json`, `prowler/compliance/aws/nist_800_53_revision_5_aws.json`. ## Universal Compliance Framework @@ -51,9 +51,9 @@ Place the file at the top level of the compliance directory: prowler/compliance/.json ``` -Examples in the repository: `prowler/compliance/csa_ccm_4.0.json`, `prowler/compliance/dora.json`. +Examples in the repository: `prowler/compliance/csa_ccm_4.0.json`, `prowler/compliance/dora_2022_2554.json`. -The file is auto-discovered — there is **no** need to register it in any `__init__.py`, modify `prowler/lib/outputs/`, or update any other Python module. The framework key Prowler CLI accepts via `--compliance` is the basename of the JSON file without `.json` (`dora.json` → `dora`). +The file is auto-discovered — there is **no** need to register it in any `__init__.py`, modify `prowler/lib/outputs/`, or update any other Python module. The framework key Prowler CLI accepts via `--compliance` is the basename of the JSON file without `.json` (`dora_2022_2554.json` → `dora_2022_2554`). ### Top-level structure @@ -70,7 +70,7 @@ The file is auto-discovered — there is **no** need to register it in any `__in } ``` -A `provider` field at the top level is **optional**. The framework's effective provider list is derived by `ComplianceFramework.get_providers()` (`compliance_models.py:739`) from the union of all keys appearing in `requirement.checks` across all requirements; the explicit `provider` field is used **only as a fallback** when no requirement carries any `checks` key. This is what enables a single file (e.g. `dora.json`) to cover AWS today and add Azure / GCP / etc. tomorrow without restructuring. +A `provider` field at the top level is **optional**. The framework's effective provider list is derived by `ComplianceFramework.get_providers()` (`compliance_models.py:739`) from the union of all keys appearing in `requirement.checks` across all requirements; the explicit `provider` field is used **only as a fallback** when no requirement carries any `checks` key. This is what enables a single file (e.g. `dora_2022_2554.json`) to cover AWS today and add Azure / GCP / etc. tomorrow without restructuring. Provider keys inside `requirement.checks` must match the directory names under `prowler/providers/`. The valid keys at present are: `aws`, `azure`, `gcp`, `m365`, `kubernetes`, `iac`, `github`, `googleworkspace`, `alibabacloud`, `cloudflare`, `mongodbatlas`, `nhn`, `openstack`, `oraclecloud`, `llm`. Comparison in `supports_provider()` is case-insensitive, but lowercase is the convention used everywhere in the repository. @@ -493,7 +493,7 @@ Before opening a PR, validate the JSON loads cleanly against the model and that ### 1. Schema validation -For **universal** frameworks, load the file and inspect what was parsed. The framework key inside `bulk` is the **basename of the JSON file** (without `.json`); for `prowler/compliance/dora.json` that key is `dora`, for `prowler/compliance/aws/cis_5.0_aws.json` it is `cis_5.0_aws`. +For **universal** frameworks, load the file and inspect what was parsed. The framework key inside `bulk` is the **basename of the JSON file** (without `.json`); for `prowler/compliance/dora_2022_2554.json` that key is `dora_2022_2554`, for `prowler/compliance/aws/cis_5.0_aws.json` it is `cis_5.0_aws`. ```python from prowler.lib.check.compliance_models import ( @@ -619,7 +619,7 @@ The following issues are the most common when contributing a compliance framewor Use the following files as templates when modeling a new contribution. -- `prowler/compliance/dora.json` — universal schema, single-provider populated (AWS), ready to extend with more providers. +- `prowler/compliance/dora_2022_2554.json` — universal schema, single-provider populated (AWS), ready to extend with more providers. - `prowler/compliance/csa_ccm_4.0.json` — universal schema, multi-provider populated (AWS, Azure, GCP, AlibabaCloud, OracleCloud). - `prowler/compliance/aws/cis_2.0_aws.json` — legacy CIS attribute shape. - `prowler/compliance/aws/nist_800_53_revision_5_aws.json` — legacy generic attribute shape. diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index ada7536290..13203e2fde 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -22,6 +22,8 @@ All notable changes to the **Prowler SDK** are documented in this file. - Public `Provider.get_class()` method that resolves a provider class by name for both built-in and external (entry-point) providers [(#11398)](https://github.com/prowler-cloud/prowler/pull/11398) - Jira timeout preventing the calls from hanging indefinitely when the Jira endpoint is unreachable or slow [(#11602)](https://github.com/prowler-cloud/prowler/pull/11602) - TLS certificate verification in the `codepipeline_project_repo_private` check, which previously used an unverified SSL context, leaving the repository-visibility probe open to MITM tampering [(#11603)](https://github.com/prowler-cloud/prowler/pull/11603) +- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the Azure provider, mapping existing Azure checks across the five DORA pillars [(#11551)](https://github.com/prowler-cloud/prowler/pull/11551) +- Rename DORA to DORA_2022_2554 to follow the naming _ in compliance frameworks [(#11551)](https://github.com/prowler-cloud/prowler/pull/11551) - `entra_directory_sync_object_takeover_blocked` check for the M365 provider, verifying that hybrid Entra tenants block cloud object takeover through both soft-match and hard-match directory synchronization [(#11098)](https://github.com/prowler-cloud/prowler/pull/11098) - `entra_conditional_access_policy_no_deleted_object_references` check for M365 provider [(#11236)](https://github.com/prowler-cloud/prowler/pull/11236) diff --git a/prowler/compliance/dora.json b/prowler/compliance/dora_2022_2554.json similarity index 69% rename from prowler/compliance/dora.json rename to prowler/compliance/dora_2022_2554.json index 2378a307c6..1bc4ed41da 100644 --- a/prowler/compliance/dora.json +++ b/prowler/compliance/dora_2022_2554.json @@ -114,6 +114,22 @@ "organizations_account_part_of_organizations", "iam_user_mfa_enabled_console_access", "iam_user_hardware_mfa_enabled" + ], + "azure": [ + "entra_global_admin_in_less_than_five_users", + "entra_privileged_user_has_mfa", + "entra_non_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa", + "entra_security_defaults_enabled", + "entra_conditional_access_policy_require_mfa_for_admin_portals", + "entra_conditional_access_policy_require_mfa_for_management_api", + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps", + "entra_policy_ensure_default_user_cannot_create_tenants", + "entra_users_cannot_create_microsoft_365_groups", + "iam_subscription_roles_owner_custom_not_created", + "iam_role_user_access_admin_restricted", + "iam_custom_role_has_permissions_to_administer_resource_locks" ] } }, @@ -136,6 +152,24 @@ "organizations_delegated_administrators", "guardduty_centrally_managed", "guardduty_delegated_admin_enabled_all_regions" + ], + "azure": [ + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_defender_for_app_services_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_defender_for_databases_is_on", + "defender_ensure_defender_for_os_relational_databases_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_cosmosdb_is_on", + "defender_ensure_mcas_is_enabled", + "defender_ensure_wdatp_is_enabled", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "policy_ensure_asc_enforcement_enabled" ] } }, @@ -167,6 +201,22 @@ "cloudfront_distributions_using_deprecated_ssl_protocols", "cloudfront_distributions_https_enabled", "rds_instance_transport_encrypted" + ], + "azure": [ + "storage_ensure_minimum_tls_version_12", + "storage_secure_transfer_required_is_enabled", + "storage_smb_channel_encryption_with_secure_algorithm", + "storage_smb_protocol_version_is_latest", + "app_minimum_tls_version_12", + "app_ensure_http_is_redirected_to_https", + "app_ensure_using_http20", + "sqlserver_recommended_minimal_tls_version", + "mysql_flexible_server_minimum_tls_version_12", + "mysql_flexible_server_ssl_connection_enabled", + "postgresql_flexible_server_enforce_ssl_enabled", + "keyvault_key_rotation_enabled", + "storage_key_rotation_90_days", + "aks_network_policy_enabled" ] } }, @@ -189,6 +239,12 @@ "ec2_elastic_ip_unassigned", "ec2_networkacl_unused", "secretsmanager_secret_unused" + ], + "azure": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "network_watcher_enabled", + "network_public_ip_shodan", + "vm_scaleset_not_empty" ] } }, @@ -236,6 +292,43 @@ "ec2_instance_account_imdsv2_enabled", "efs_encryption_at_rest_enabled", "awslambda_function_not_publicly_accessible" + ], + "azure": [ + "storage_account_public_network_access_disabled", + "storage_blob_public_access_level_is_disabled", + "storage_default_network_access_rule_is_denied", + "storage_ensure_private_endpoints_in_storage_accounts", + "storage_ensure_encryption_with_customer_managed_keys", + "storage_infrastructure_encryption_is_enabled", + "storage_account_key_access_disabled", + "storage_default_to_entra_authorization_enabled", + "containerregistry_not_publicly_accessible", + "containerregistry_uses_private_link", + "cosmosdb_account_use_private_endpoints", + "cosmosdb_account_firewall_use_selected_networks", + "keyvault_private_endpoints", + "keyvault_access_only_through_private_endpoints", + "keyvault_rbac_enabled", + "app_function_not_publicly_accessible", + "aisearch_service_not_publicly_accessible", + "aks_clusters_public_access_disabled", + "aks_clusters_created_with_private_nodes", + "sqlserver_unrestricted_inbound_access", + "postgresql_flexible_server_allow_access_services_disabled", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk", + "vm_ensure_using_managed_disks", + "vm_trusted_launch_enabled", + "vm_linux_enforce_ssh_authentication", + "vm_jit_access_enabled", + "sqlserver_tde_encryption_enabled", + "sqlserver_tde_encrypted_with_cmk", + "databricks_workspace_cmk_encryption_enabled", + "network_ssh_internet_access_restricted", + "network_rdp_internet_access_restricted", + "network_http_internet_access_restricted", + "network_udp_internet_access_restricted", + "network_bastion_host_exists" ] } }, @@ -266,6 +359,22 @@ "inspector2_is_enabled", "inspector2_active_findings_exist", "ec2_elastic_ip_shodan" + ], + "azure": [ + "defender_ensure_defender_for_server_is_on", + "defender_ensure_defender_for_containers_is_on", + "defender_ensure_defender_for_storage_is_on", + "defender_ensure_defender_for_keyvault_is_on", + "defender_ensure_defender_for_arm_is_on", + "defender_ensure_defender_for_dns_is_on", + "defender_ensure_defender_for_azure_sql_databases_is_on", + "defender_ensure_defender_for_sql_servers_is_on", + "defender_ensure_wdatp_is_enabled", + "defender_ensure_mcas_is_enabled", + "defender_container_images_scan_enabled", + "defender_container_images_resolved_vulnerabilities", + "sqlserver_microsoft_defender_enabled", + "apim_threat_detection_llm_jacking" ] } }, @@ -288,6 +397,17 @@ "backup_vaults_exist", "rds_instance_critical_event_subscription", "rds_cluster_critical_event_subscription" + ], + "azure": [ + "monitor_alert_service_health_exists", + "monitor_alert_create_update_security_solution", + "monitor_alert_delete_security_solution", + "defender_additional_email_configured_with_a_security_contact", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_attack_path_notifications_properly_configured", + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" ] } }, @@ -329,6 +449,16 @@ "elbv2_is_in_multiple_az", "cloudfront_distributions_multiple_origin_failover_configured", "dynamodb_table_protected_by_backup_plan" + ], + "azure": [ + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period", + "vm_ensure_using_managed_disks", + "storage_ensure_soft_delete_is_enabled", + "storage_ensure_file_shares_soft_delete_is_enabled", + "storage_blob_versioning_is_enabled", + "storage_geo_redundant_enabled", + "keyvault_recoverable" ] } }, @@ -348,6 +478,16 @@ "inspector2_active_findings_exist", "accessanalyzer_enabled_without_findings", "cloudtrail_insights_exist" + ], + "azure": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_assessments_vm_endpoint_protection_installed", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_system_updates_are_applied", + "sqlserver_vulnerability_assessment_enabled", + "sqlserver_va_periodic_recurring_scans_enabled", + "sqlserver_va_scan_reports_configured" ] } }, @@ -370,6 +510,13 @@ "eventbridge_schema_registry_cross_account_access", "cloudwatch_alarm_actions_enabled", "cloudwatch_alarm_actions_alarm_state_configured" + ], + "azure": [ + "defender_additional_email_configured_with_a_security_contact", + "defender_ensure_notify_emails_to_owners", + "defender_ensure_notify_alerts_severity_is_high", + "defender_attack_path_notifications_properly_configured", + "monitor_alert_service_health_exists" ] } }, @@ -406,6 +553,26 @@ "elbv2_logging_enabled", "cloudfront_distributions_logging_enabled", "s3_bucket_server_access_logging_enabled" + ], + "azure": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_storage_account_with_activity_logs_is_private", + "monitor_storage_account_with_activity_logs_cmk_encrypted", + "network_flow_log_captured_sent", + "network_flow_log_more_than_90_days", + "keyvault_logging_enabled", + "sqlserver_auditing_enabled", + "sqlserver_auditing_retention_90_days", + "mysql_flexible_server_audit_log_enabled", + "mysql_flexible_server_audit_log_connection_activated", + "postgresql_flexible_server_log_checkpoints_on", + "postgresql_flexible_server_log_connections_on", + "postgresql_flexible_server_log_disconnections_on", + "postgresql_flexible_server_log_retention_days_greater_3", + "app_http_logs_enabled", + "app_function_application_insights_enabled", + "appinsights_ensure_is_configured" ] } }, @@ -429,6 +596,15 @@ "cloudtrail_threat_detection_enumeration", "cloudtrail_threat_detection_llm_jacking", "cloudtrail_threat_detection_privilege_escalation" + ], + "azure": [ + "defender_ensure_notify_alerts_severity_is_high", + "defender_attack_path_notifications_properly_configured", + "defender_ensure_defender_for_server_is_on", + "defender_ensure_wdatp_is_enabled", + "defender_ensure_mcas_is_enabled", + "sqlserver_microsoft_defender_enabled", + "apim_threat_detection_llm_jacking" ] } }, @@ -459,6 +635,20 @@ "cloudwatch_changes_to_network_route_tables_alarm_configured", "cloudwatch_changes_to_vpcs_alarm_configured", "sns_subscription_not_using_http_endpoints" + ], + "azure": [ + "monitor_alert_create_policy_assignment", + "monitor_alert_delete_policy_assignment", + "monitor_alert_create_update_nsg", + "monitor_alert_delete_nsg", + "monitor_alert_create_update_security_solution", + "monitor_alert_delete_security_solution", + "monitor_alert_create_update_sqlserver_fr", + "monitor_alert_delete_sqlserver_fr", + "monitor_alert_create_update_public_ip_address_rule", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_service_health_exists", + "defender_additional_email_configured_with_a_security_contact" ] } }, @@ -479,6 +669,16 @@ "ec2_instance_managed_by_ssm", "ec2_instance_with_outdated_ami", "ssm_managed_compliant_patching" + ], + "azure": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_ensure_system_updates_are_applied", + "defender_container_images_scan_enabled", + "defender_assessments_vm_endpoint_protection_installed", + "sqlserver_vulnerability_assessment_enabled", + "sqlserver_va_periodic_recurring_scans_enabled", + "vm_ensure_using_approved_images", + "vm_desired_sku_size" ] } }, @@ -506,6 +706,23 @@ "rds_instance_certificate_expiration", "iam_no_expired_server_certificates_stored", "ssm_managed_compliant_patching" + ], + "azure": [ + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "defender_container_images_resolved_vulnerabilities", + "sqlserver_vulnerability_assessment_enabled", + "sqlserver_va_periodic_recurring_scans_enabled", + "sqlserver_va_scan_reports_configured", + "sqlserver_va_emails_notifications_admins_enabled", + "keyvault_key_expiration_set_in_non_rbac", + "keyvault_rbac_key_expiration_set", + "keyvault_non_rbac_secret_expiration_set", + "keyvault_rbac_secret_expiration_set", + "app_ensure_java_version_is_latest", + "app_ensure_php_version_is_latest", + "app_ensure_python_version_is_latest", + "app_function_latest_runtime_version", + "storage_smb_protocol_version_is_latest" ] } }, @@ -537,6 +754,17 @@ "vpc_endpoint_services_allowed_principals_trust_boundaries", "vpc_peering_routing_tables_with_least_privilege", "awslambda_function_using_cross_account_layers" + ], + "azure": [ + "entra_policy_guest_users_access_restrictions", + "entra_policy_guest_invite_only_for_admin_roles", + "entra_policy_restricts_user_consent_for_apps", + "entra_policy_user_consent_for_verified_apps", + "storage_cross_tenant_replication_disabled", + "containerregistry_uses_private_link", + "cosmosdb_account_use_private_endpoints", + "keyvault_access_only_through_private_endpoints", + "aks_clusters_created_with_private_nodes" ] } }, @@ -567,6 +795,15 @@ "iam_administrator_access_with_mfa", "iam_policy_attached_only_to_group_or_roles", "accessanalyzer_enabled" + ], + "azure": [ + "iam_subscription_roles_owner_custom_not_created", + "iam_role_user_access_admin_restricted", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "entra_global_admin_in_less_than_five_users", + "app_function_identity_without_admin_privileges", + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps" ] } }, @@ -590,6 +827,14 @@ "cloudtrail_threat_detection_llm_jacking", "cloudtrail_threat_detection_privilege_escalation", "accessanalyzer_enabled_without_findings" + ], + "azure": [ + "defender_ensure_mcas_is_enabled", + "defender_ensure_wdatp_is_enabled", + "defender_ensure_defender_for_server_is_on", + "defender_attack_path_notifications_properly_configured", + "sqlserver_microsoft_defender_enabled", + "apim_threat_detection_llm_jacking" ] } } diff --git a/ui/.prettierignore b/ui/.prettierignore index 5377d96f2d..8b679ff005 100644 --- a/ui/.prettierignore +++ b/ui/.prettierignore @@ -8,6 +8,7 @@ build/ coverage/ dist/ esm/ +CHANGELOG.md # Generated files next-env.d.ts diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 1baddf169a..a5b56ab23c 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the **Prowler UI** are documented in this file. ### 🐞 Fixed - Radio button no longer shifts vertically when selected [(#11608)](https://github.com/prowler-cloud/prowler/pull/11608) +- Handle rename DORA to DORA_2022_2554 to follow the naming _ in compliance frameworks [(#11551)](https://github.com/prowler-cloud/prowler/pull/11551) ### 🔐 Security diff --git a/ui/components/compliance/compliance-download-container.test.tsx b/ui/components/compliance/compliance-download-container.test.tsx index 70ff11c1c2..31c68fb1fc 100644 --- a/ui/components/compliance/compliance-download-container.test.tsx +++ b/ui/components/compliance/compliance-download-container.test.tsx @@ -163,7 +163,7 @@ describe("ComplianceDownloadContainer", () => { compact presentation="dropdown" scanId="scan-1" - complianceId="dora" + complianceId="dora_2022_2554" />, ); @@ -178,7 +178,7 @@ describe("ComplianceDownloadContainer", () => { expect(downloadComplianceOcsfMock).toHaveBeenCalledWith( "scan-1", - "dora", + "dora_2022_2554", {}, ); }); diff --git a/ui/components/icons/compliance/IconCompliance.tsx b/ui/components/icons/compliance/IconCompliance.tsx index ab0fb9a36a..6723fe8a95 100644 --- a/ui/components/icons/compliance/IconCompliance.tsx +++ b/ui/components/icons/compliance/IconCompliance.tsx @@ -69,8 +69,9 @@ const COMPLIANCE_LOGOS = [ ["c5", C5Logo], ["ccc", CCCLogo], ["csa", CSALogo], - // DORA — universal framework (`prowler/compliance/dora.json`). The - // compliance_id is just `dora`, no provider suffix. + // DORA — universal framework (`prowler/compliance/dora_2022_2554.json`). + // The compliance_id is `dora_2022_2554`; the `dora` keyword still matches + // it via `includes`, with no provider suffix. ["dora", DORALogo], ["secnumcloud", ANSSILogo], ["okta", OktaLogo], diff --git a/ui/dependency-log.json b/ui/dependency-log.json index c851552b08..b200139313 100644 --- a/ui/dependency-log.json +++ b/ui/dependency-log.json @@ -2,10 +2,10 @@ { "section": "dependencies", "name": "@ai-sdk/react", - "from": "2.0.111", - "to": "3.0.207", + "from": "3.0.207", + "to": "3.0.205", "strategy": "installed", - "generatedAt": "2026-06-15T07:44:51.977Z" + "generatedAt": "2026-06-17T11:28:12.866Z" }, { "section": "dependencies", @@ -362,10 +362,10 @@ { "section": "dependencies", "name": "ai", - "from": "5.0.109", - "to": "6.0.205", + "from": "6.0.205", + "to": "6.0.203", "strategy": "installed", - "generatedAt": "2026-06-15T07:44:51.977Z" + "generatedAt": "2026-06-17T11:28:12.866Z" }, { "section": "dependencies", diff --git a/ui/lib/compliance/compliance-mapper.ts b/ui/lib/compliance/compliance-mapper.ts index 2e44958c73..bc0995ad87 100644 --- a/ui/lib/compliance/compliance-mapper.ts +++ b/ui/lib/compliance/compliance-mapper.ts @@ -228,7 +228,7 @@ const getComplianceMappers = (): Record => ({ createElement(OktaIDaaSStigCustomDetails, { requirement }), }, // DORA (Regulation (EU) 2022/2554) — universal framework keyed by the - // `framework` field of `prowler/compliance/dora.json` ("DORA"). Groups by + // `framework` field of `prowler/compliance/dora_2022_2554.json` ("DORA"). Groups by // Pillar (5 enum values) and surfaces Pillar / Article / ArticleTitle in // the requirement detail drawer. DORA: { diff --git a/ui/lib/compliance/compliance-report-types.test.ts b/ui/lib/compliance/compliance-report-types.test.ts index 82c6cd49f9..d8d41f08ec 100644 --- a/ui/lib/compliance/compliance-report-types.test.ts +++ b/ui/lib/compliance/compliance-report-types.test.ts @@ -37,7 +37,7 @@ describe("getReportTypeForFramework", () => { describe("isOcsfSupported", () => { it("returns true for universal frameworks shipping an OCSF artifact", () => { - expect(isOcsfSupported("dora")).toBe(true); + expect(isOcsfSupported("dora_2022_2554")).toBe(true); expect(isOcsfSupported("csa_ccm_4.0")).toBe(true); }); diff --git a/ui/lib/compliance/compliance-report-types.ts b/ui/lib/compliance/compliance-report-types.ts index a9a160e09c..f8f23a67e1 100644 --- a/ui/lib/compliance/compliance-report-types.ts +++ b/ui/lib/compliance/compliance-report-types.ts @@ -178,7 +178,7 @@ export const pickLatestCisPerProvider = ( * ``isOcsfSupported``. */ const OCSF_SUPPORTED_COMPLIANCE_IDS: ReadonlySet = new Set([ - "dora", + "dora_2022_2554", "csa_ccm_4.0", ]); diff --git a/ui/types/compliance.ts b/ui/types/compliance.ts index fde9d260e9..3a46375a75 100644 --- a/ui/types/compliance.ts +++ b/ui/types/compliance.ts @@ -373,7 +373,7 @@ export interface OktaIDaaSStigRequirement extends Requirement { // DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554). // Universal framework — flat attributes dict with Pillar/Article/ArticleTitle. // `Pillar` is the canonical grouping key for tables and PDF; the enum mirrors -// the five DORA pillars declared in `prowler/compliance/dora.json`. +// the five DORA pillars declared in `prowler/compliance/dora_2022_2554.json`. export const DORA_PILLAR = { ICT_RISK_MANAGEMENT: "ICT Risk Management", INCIDENT_REPORTING: "ICT-Related Incident Reporting",