From 6cacef7d82fa136eceeae20df5fc2935cf8cb3f3 Mon Sep 17 00:00:00 2001 From: "Hugo P.Brito" Date: Wed, 8 Apr 2026 16:15:47 +0100 Subject: [PATCH] fix(intune): restore service retry logic and tests Reverts the accidental removal of intune_service.py retry logic and its corresponding tests in intune_service_test.py. --- .../m365/services/intune/intune_service.py | 13 +++-- .../services/intune/intune_service_test.py | 54 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/prowler/providers/m365/services/intune/intune_service.py b/prowler/providers/m365/services/intune/intune_service.py index 4b62f64e99..2f6c0febae 100644 --- a/prowler/providers/m365/services/intune/intune_service.py +++ b/prowler/providers/m365/services/intune/intune_service.py @@ -125,6 +125,15 @@ class Intune(M365Service): request_configuration=request_configuration ) settings = getattr(device_management, "settings", None) + secure_by_default = getattr(settings, "secure_by_default", None) + + # Some tenants/API responses omit nested settings when $select is used. + # Retry without query parameters before concluding the value is unavailable. + if settings is None or secure_by_default is None: + device_management = await self.client.device_management.get() + settings = getattr(device_management, "settings", None) + secure_by_default = getattr(settings, "secure_by_default", None) + if settings is None: return ( IntuneSettings(secure_by_default=None), @@ -132,9 +141,7 @@ class Intune(M365Service): ) return ( - IntuneSettings( - secure_by_default=getattr(settings, "secure_by_default", None) - ), + IntuneSettings(secure_by_default=secure_by_default), None, ) except Exception as error: diff --git a/tests/providers/m365/services/intune/intune_service_test.py b/tests/providers/m365/services/intune/intune_service_test.py index 3e6762391f..1e273d04e9 100644 --- a/tests/providers/m365/services/intune/intune_service_test.py +++ b/tests/providers/m365/services/intune/intune_service_test.py @@ -349,6 +349,60 @@ def test_intune_get_settings_null_settings(): assert settings.secure_by_default is None +def test_intune_get_settings_retries_without_select_when_settings_missing(): + """Test _get_settings retries without $select when settings are omitted.""" + intune = Intune.__new__(Intune) + + selected_response = SimpleNamespace(settings=None) + full_response = SimpleNamespace(settings=SimpleNamespace(secure_by_default=True)) + + mock_client = mock.MagicMock() + mock_client.device_management.get = AsyncMock( + side_effect=[selected_response, full_response] + ) + + intune.client = mock_client + + loop = asyncio.new_event_loop() + try: + settings, error = loop.run_until_complete(intune._get_settings()) + finally: + loop.close() + + assert error is None + assert settings is not None + assert settings.secure_by_default is True + assert mock_client.device_management.get.await_count == 2 + + +def test_intune_get_settings_retries_without_select_when_value_missing(): + """Test _get_settings retries without $select when secure_by_default is omitted.""" + intune = Intune.__new__(Intune) + + selected_response = SimpleNamespace( + settings=SimpleNamespace(secure_by_default=None) + ) + full_response = SimpleNamespace(settings=SimpleNamespace(secure_by_default=False)) + + mock_client = mock.MagicMock() + mock_client.device_management.get = AsyncMock( + side_effect=[selected_response, full_response] + ) + + intune.client = mock_client + + loop = asyncio.new_event_loop() + try: + settings, error = loop.run_until_complete(intune._get_settings()) + finally: + loop.close() + + assert error is None + assert settings is not None + assert settings.secure_by_default is False + assert mock_client.device_management.get.await_count == 2 + + def test_intune_get_settings_exception(): """Test _get_settings handles exceptions gracefully.""" intune = Intune.__new__(Intune)