chore(revision): add missing changes

This commit is contained in:
pedrooot committed 2026-07-23 16:21:21 +02:00
1 parent 3d50bed244
commit f07cc4cad6
37 files changed
+640 -147

No files matched your search

@@ -31,6 +31,7 @@ class Test_entra_authentication_method_authenticator_show_context:
def test_both_enabled(self):
result = self._run(
AuthenticationMethodsPolicySettings(
authenticator_state="enabled",
authenticator_display_app_information_state="enabled",
authenticator_display_location_information_state="enabled",
)
@@ -40,8 +41,19 @@ class Test_entra_authentication_method_authenticator_show_context:
def test_location_disabled(self):
result = self._run(
AuthenticationMethodsPolicySettings(
authenticator_state="enabled",
authenticator_display_app_information_state="enabled",
authenticator_display_location_information_state="disabled",
)
)
assert result[0].status == "FAIL"
def test_context_enabled_but_authenticator_disabled(self):
result = self._run(
AuthenticationMethodsPolicySettings(
authenticator_state="disabled",
authenticator_display_app_information_state="enabled",
authenticator_display_location_information_state="enabled",
)
)
assert result[0].status == "FAIL"
@@ -101,3 +101,39 @@ class Test_entra_authentication_method_email_otp_disabled:
result[0].status_extended
== "Email OTP authentication method is disabled in the tenant."
)
def test_email_otp_unknown_state(self):
entra_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_m365_provider(),
),
mock.patch(
"prowler.providers.m365.services.entra.entra_authentication_method_email_otp_disabled.entra_authentication_method_email_otp_disabled.entra_client",
new=entra_client,
),
):
from prowler.providers.m365.services.entra.entra_authentication_method_email_otp_disabled.entra_authentication_method_email_otp_disabled import (
entra_authentication_method_email_otp_disabled,
)
entra_client.authentication_method_configurations = {
"Email": AuthenticationMethodConfiguration(
id="Email",
state="unknown",
),
}
entra_client.tenant_domain = DOMAIN
check = entra_authentication_method_email_otp_disabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Email OTP authentication method state could not be determined; "
"treating as enabled/non-compliant."
)
@@ -25,8 +25,7 @@ class Test_entra_conditional_access_trusted_named_location_exists:
def test_no_locations(self):
result = self._run([])
assert len(result) == 1
assert result[0].status == "FAIL"
assert len(result) == 0
def test_trusted_ip_location(self):
result = self._run(
@@ -41,6 +41,15 @@ class Test_entra_device_registration_registering_user_not_local_admin:
assert result[0].status == "FAIL"
def test_selected_registering_users(self):
result = self._run(
DeviceRegistrationPolicy(
azure_ad_join_registering_users_type=DeviceRegistrationMembershipType.ENUMERATED.value
)
)
assert len(result) == 1
assert result[0].status == "PASS"
def test_none_registering_users(self):
result = self._run(
DeviceRegistrationPolicy(
azure_ad_join_registering_users_type=DeviceRegistrationMembershipType.NONE.value
@@ -10,7 +10,7 @@ CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_password_protec
class Test_entra_password_protection_custom_banned_list_enforced:
def _run(self, directory_settings):
entra_client = mock.MagicMock
entra_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -27,8 +27,7 @@ class Test_entra_password_protection_custom_banned_list_enforced:
def test_template_absent(self):
result = self._run({})
assert len(result) == 1
assert result[0].status == "FAIL"
assert len(result) == 0
def test_enforced_with_list(self):
result = self._run(
@@ -10,7 +10,7 @@ CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_password_protec
class Test_entra_password_protection_lockout_duration_configured:
def _run(self, directory_settings):
entra_client = mock.MagicMock
entra_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -26,7 +26,7 @@ class Test_entra_password_protection_lockout_duration_configured:
return entra_password_protection_lockout_duration_configured().execute()
def test_template_absent(self):
assert self._run({})[0].status == "FAIL"
assert len(self._run({})) == 0
def test_at_minimum(self):
result = self._run(
@@ -26,7 +26,7 @@ class Test_entra_password_protection_lockout_threshold_limited:
return entra_password_protection_lockout_threshold_limited().execute()
def test_template_absent(self):
assert self._run({})[0].status == "FAIL"
assert len(self._run({})) == 0
def test_within_limit(self):
result = self._run(
@@ -25,8 +25,9 @@ class Test_entra_password_protection_on_premises_enforced:
entra_client.directory_settings = directory_settings
return entra_password_protection_on_premises_enforced().execute()
def test_template_absent(self):
assert self._run({})[0].status == "FAIL"
def test_no_resources(self):
result = self._run({})
assert len(result) == 0
def test_enabled_and_enforced(self):
result = self._run(
@@ -11,7 +11,7 @@ CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_pim_global_admi
class Test_entra_pim_global_administrator_approval_required:
def _run(self, settings):
entra_client = mock.MagicMock
entra_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -10,7 +10,7 @@ CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_policy_default_
class Test_entra_policy_default_user_cannot_create_m365_groups:
def _run(self, directory_settings):
entra_client = mock.MagicMock
entra_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -1,8 +1,6 @@
from unittest import mock
from prowler.providers.m365.services.entra.entra_service import (
B2BCollaborationPolicy,
)
from prowler.providers.m365.services.entra.entra_service import B2BCollaborationPolicy
from tests.providers.m365.m365_fixtures import set_mocked_m365_provider
CHECK_MODULE_PATH = "prowler.providers.m365.services.entra.entra_policy_guest_invitations_restricted_to_allowed_domains.entra_policy_guest_invitations_restricted_to_allowed_domains"
@@ -47,3 +45,12 @@ class Test_entra_policy_guest_invitations_restricted_to_allowed_domains:
)
)
assert result[0].status == "FAIL"
def test_restricted_with_empty_allowed_domains(self):
result = self._run(
B2BCollaborationPolicy(
invitations_restricted_to_allowed_domains=True,
allowed_domains=[],
)
)
assert result[0].status == "FAIL"
@@ -1,5 +1,6 @@
import asyncio
import importlib
import json
from datetime import datetime, timezone
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch
@@ -1196,3 +1197,62 @@ class Test_Entra_Service:
queried_users = {call.args[0] for call in by_user_id.call_args_list}
assert queried_users == {deleted_user, live_user}
assert user_builders[deleted_user].get.await_count == 1
def test__get_named_locations_paginates_through_next_links(self):
entra_service = Entra.__new__(Entra)
page_one = json.dumps(
{
"value": [
{
"@odata.type": "#microsoft.graph.ipNamedLocation",
"id": "loc-1",
"displayName": "Trusted IPs",
"isTrusted": True,
"ipRanges": [{"cidrAddress": "10.0.0.0/8"}],
}
],
"@odata.nextLink": "next-link",
}
)
page_two = json.dumps(
{
"value": [
{
"@odata.type": "#microsoft.graph.countryNamedLocation",
"id": "loc-2",
"displayName": "Countries",
"isTrusted": False,
}
]
}
)
send_mock = AsyncMock(side_effect=[page_one, page_two])
next_link_builder = SimpleNamespace(
to_get_request_information=MagicMock(return_value="req-info-page-two")
)
with_url_mock = MagicMock(return_value=next_link_builder)
named_locations_builder = SimpleNamespace(
to_get_request_information=MagicMock(return_value="req-info-page-one"),
with_url=with_url_mock,
)
entra_service.client = SimpleNamespace(
identity=SimpleNamespace(
conditional_access=SimpleNamespace(
named_locations=named_locations_builder
)
),
request_adapter=SimpleNamespace(send_primitive_async=send_mock),
)
named_locations = asyncio.run(entra_service._get_named_locations())
# Both pages are requested and every entry is accumulated before parsing.
assert send_mock.await_count == 2
with_url_mock.assert_called_once_with("next-link")
assert [loc.id for loc in named_locations] == ["loc-1", "loc-2"]
assert named_locations[0].is_ip_location is True
assert named_locations[0].ip_ranges_count == 1
assert named_locations[1].is_ip_location is False
assert named_locations[1].is_trusted is False
@@ -10,7 +10,7 @@ CHECK_MODULE_PATH = "prowler.providers.m365.services.intune.intune_device_enroll
class Test_intune_device_enrollment_personal_device_restricted:
def _run(self, configurations):
intune_client = mock.MagicMock
intune_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
@@ -161,6 +161,64 @@ class Test_Intune_DeviceEnrollmentConfigurations:
def test_empty_response(self):
assert self._run_getter({"value": []}) == []
def test_follows_pagination_across_pages(self):
import json
first_page = {
"value": [
{
"@odata.type": "#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration",
"id": "page-one",
"priority": 0,
"iosRestriction": {
"personalDeviceEnrollmentBlocked": True,
"platformBlocked": False,
},
},
],
"@odata.nextLink": "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations?$skiptoken=abc",
}
second_page = {
"value": [
{
"@odata.type": "#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration",
"id": "page-two",
"priority": 1,
"androidRestriction": {
"personalDeviceEnrollmentBlocked": False,
"platformBlocked": True,
},
},
],
}
service = Intune.__new__(Intune)
client = mock.MagicMock()
builder = (
client.device_management.device_enrollment_configurations.with_url.return_value
)
builder.to_get_request_information.return_value = mock.MagicMock()
client.request_adapter.send_primitive_async = AsyncMock(
side_effect=[
json.dumps(first_page).encode(),
json.dumps(second_page).encode(),
]
)
service.client = client
loop = asyncio.new_event_loop()
try:
result = loop.run_until_complete(
service._get_device_enrollment_configurations()
)
finally:
loop.close()
# Configurations from BOTH pages must be collected.
assert len(result) == 2
assert {config.id for config in result} == {"page-one", "page-two"}
assert client.request_adapter.send_primitive_async.await_count == 2
class Test_Intune_Service:
def test_get_settings_secure_by_default_true(self):