fix(sdk): use case-insensitive comparison for Azure VM backup checks (#10417)

Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
This commit is contained in:
Prowler Bot
2026-03-23 10:53:52 +01:00
committed by GitHub
parent 4d5c38ca76
commit 21e1f583f7
5 changed files with 185 additions and 2 deletions
+8
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler SDK** are documented in this file.
## [5.21.2] (Prowler UNRELEASED)
### 🐞 Fixed
- Azure `vm_backup_enabled` and `vm_sufficient_daily_backup_retention_period` checks now compare VM names case-insensitively to avoid false negatives when Azure stores backup item names in a different case [(#10373)](https://github.com/prowler-cloud/prowler/pull/10373)
---
## [5.21.0] (Prowler v5.21.0)
### 🚀 Added
@@ -31,7 +31,8 @@ class vm_backup_enabled(Check):
for backup_item in vault.backup_protected_items.values():
if (
backup_item.workload_type == DataSourceType.VM
and backup_item.name.split(";")[-1] == vm.resource_name
and backup_item.name.split(";")[-1].lower()
== vm.resource_name.lower()
):
found = True
found_vault_name = vault.name
@@ -27,7 +27,8 @@ class vm_sufficient_daily_backup_retention_period(Check):
for backup_item in vault.backup_protected_items.values():
if (
backup_item.workload_type == DataSourceType.VM
and backup_item.name.split(";")[-1] == vm.resource_name
and backup_item.name.split(";")[-1].lower()
== vm.resource_name.lower()
):
backup_found = True
policy_id = backup_item.backup_policy_id
@@ -221,6 +221,85 @@ class Test_vm_backup_enabled:
== f"VM {vm_name} in subscription {AZURE_SUBSCRIPTION_ID} is not protected by Azure Backup."
)
def test_vm_protected_by_backup_case_insensitive(self):
vm_id = str(uuid4())
vm_name = "vmtest"
vault_id = str(uuid4())
vault_name = "vault1"
mock_vm_client = mock.MagicMock()
mock_recovery_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_backup_enabled.vm_backup_enabled.vm_client",
new=mock_vm_client,
),
mock.patch(
"prowler.providers.azure.services.vm.vm_backup_enabled.vm_backup_enabled.recovery_client",
new=mock_recovery_client,
),
):
from azure.mgmt.recoveryservicesbackup.activestamp.models import (
DataSourceType,
)
from prowler.providers.azure.services.recovery.recovery_service import (
BackupItem,
BackupVault,
)
from prowler.providers.azure.services.vm.vm_backup_enabled.vm_backup_enabled import (
vm_backup_enabled,
)
from prowler.providers.azure.services.vm.vm_service import (
ManagedDiskParameters,
OSDisk,
StorageProfile,
VirtualMachine,
)
vm = VirtualMachine(
resource_id=vm_id,
resource_name=vm_name,
location="eastus",
security_profile=None,
extensions=[],
storage_profile=StorageProfile(
os_disk=OSDisk(
name="os_disk_name",
operating_system_type="Linux",
managed_disk=ManagedDiskParameters(id="managed_disk_id"),
),
data_disks=[],
),
)
backup_item = BackupItem(
id=str(uuid4()),
name="someprefix;VMTEST",
workload_type=DataSourceType.VM,
)
vault = BackupVault(
id=vault_id,
name=vault_name,
location="eastus",
backup_protected_items={backup_item.id: backup_item},
)
mock_vm_client.virtual_machines = {AZURE_SUBSCRIPTION_ID: {vm_id: vm}}
mock_recovery_client.vaults = {AZURE_SUBSCRIPTION_ID: {vault_id: vault}}
check = vm_backup_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].resource_name == vm_name
assert result[0].resource_id == vm_id
assert (
result[0].status_extended
== f"VM {vm_name} in subscription {AZURE_SUBSCRIPTION_ID} is protected by Azure Backup (vault: {vault_name})."
)
def test_vm_protected_by_backup_non_vm_workload(self):
vm_id = str(uuid4())
vm_name = "VMTest"
@@ -156,6 +156,100 @@ class Test_vm_sufficient_daily_backup_retention_period:
in result[0].status_extended
)
def test_vm_with_sufficient_retention_case_insensitive(self):
from azure.mgmt.recoveryservicesbackup.activestamp.models import DataSourceType
from prowler.providers.azure.services.recovery.recovery_service import (
BackupItem,
BackupPolicy,
BackupVault,
)
from prowler.providers.azure.services.vm.vm_service import (
ManagedDiskParameters,
OSDisk,
StorageProfile,
VirtualMachine,
)
vm_id = str(uuid4())
vm_name = "vmtest"
vault_id = str(uuid4())
policy_id = str(uuid4())
retention_days = 14
min_retention_days = 7
vm = VirtualMachine(
resource_id=vm_id,
resource_name=vm_name,
location="eastus",
security_profile=None,
extensions=[],
storage_profile=StorageProfile(
os_disk=OSDisk(
name="os_disk_name",
operating_system_type="Linux",
managed_disk=ManagedDiskParameters(id="managed_disk_id"),
),
data_disks=[],
),
)
backup_item = BackupItem(
id=str(uuid4()),
name="someprefix;VMTEST",
workload_type=DataSourceType.VM,
backup_policy_id=policy_id,
)
backup_policy = BackupPolicy(
id=policy_id,
name="policy1",
retention_days=retention_days,
)
vault = BackupVault(
id=vault_id,
name="vault1",
location="eastus",
backup_protected_items={backup_item.id: backup_item},
backup_policies={policy_id: backup_policy},
)
vm_client = mock.MagicMock()
recovery_client = mock.MagicMock()
vm_client.virtual_machines = {AZURE_SUBSCRIPTION_ID: {vm_id: vm}}
recovery_client.vaults = {AZURE_SUBSCRIPTION_ID: {vault_id: vault}}
vm_client.audit_config = {
"vm_backup_min_daily_retention_days": min_retention_days
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(
audit_config=vm_client.audit_config
),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_sufficient_daily_backup_retention_period.vm_sufficient_daily_backup_retention_period.vm_client",
new=vm_client,
),
mock.patch(
"prowler.providers.azure.services.vm.vm_sufficient_daily_backup_retention_period.vm_sufficient_daily_backup_retention_period.recovery_client",
new=recovery_client,
),
):
from prowler.providers.azure.services.vm.vm_sufficient_daily_backup_retention_period.vm_sufficient_daily_backup_retention_period import (
vm_sufficient_daily_backup_retention_period,
)
check = vm_sufficient_daily_backup_retention_period()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].resource_name == vm_name
assert result[0].resource_id == vm_id
assert (
f"has a daily backup retention period of {retention_days} days"
in result[0].status_extended
)
def test_vm_with_insufficient_retention(self):
from azure.mgmt.recoveryservicesbackup.activestamp.models import DataSourceType