feat(provider): implement get_mutelist_finding_args for external providers and add tests

This commit is contained in:
StylusFrost
2026-04-21 18:50:18 +02:00
parent e27317437d
commit e2295bd086
3 changed files with 70 additions and 0 deletions
+3
View File
@@ -747,6 +747,9 @@ def execute(
is_finding_muted_args["tenancy_id"] = (
global_provider.identity.tenancy_id
)
else:
# External/custom provider — delegate identity args
is_finding_muted_args = global_provider.get_mutelist_finding_args()
for finding in check_findings:
if global_provider.type == "cloudflare":
is_finding_muted_args["account_id"] = finding.account_id
+11
View File
@@ -193,6 +193,17 @@ class Provider(ABC):
f"{self.__class__.__name__} has not implemented generate_compliance_output()"
)
def get_mutelist_finding_args(self) -> dict:
"""Return extra kwargs for mutelist.is_finding_muted() besides 'finding'.
External providers must return a dict with the identity key their
Mutelist subclass expects, e.g. ``{"account_id": self.identity.account_id}``.
The ``finding`` kwarg is added automatically by the caller.
"""
raise NotImplementedError(
f"{self.__class__.__name__} has not implemented get_mutelist_finding_args()"
)
@property
def is_external_tool_provider(self) -> bool:
"""True for providers that delegate scanning to an external tool."""
@@ -84,6 +84,9 @@ class FakeExternalProvider(Provider):
"region": "local",
}
def get_mutelist_finding_args(self):
return {"host_id": self.identity.host_id}
def get_html_assessment_summary(self):
return "<div>Fake Assessment</div>"
@@ -1158,7 +1161,60 @@ class TestBaseContractDefaults:
with pytest.raises(NotImplementedError):
provider.generate_compliance_output([], {}, set(), MagicMock(), {})
def test_get_mutelist_finding_args_raises_not_implemented(self):
"""Base Provider.get_mutelist_finding_args raises NotImplementedError."""
provider = FakeProviderNoHelpText()
with pytest.raises(NotImplementedError):
provider.get_mutelist_finding_args()
def test_is_external_tool_provider_defaults_to_false(self):
"""Base Provider.is_external_tool_provider returns False."""
provider = FakeProviderNoHelpText()
assert provider.is_external_tool_provider is False
# ===========================================================================
# 10. Mutelist Dispatch for External Providers
# ===========================================================================
class TestMutelistDispatch:
"""Tests for mutelist integration with external providers."""
def test_get_mutelist_finding_args_returns_identity(self, fake_provider):
"""External provider returns identity kwargs for mutelist."""
args = fake_provider.get_mutelist_finding_args()
assert args == {"host_id": "fake-host-1"}
def test_mutelist_dispatch_calls_external_provider(self, fake_provider):
"""execute() uses get_mutelist_finding_args for unknown provider types."""
from prowler.lib.check.check import execute
# Create a mock check that returns one finding
finding = MagicMock()
finding.status = "FAIL"
finding.muted = False
finding.check_metadata.Provider = "fakeexternal"
check = MagicMock()
check.execute.return_value = [finding]
check.CheckID = "fake_check"
check.ServiceName = "fake_service"
check.Severity.value = "high"
# Setup mutelist on the provider
fake_provider.mutelist = MagicMock()
fake_provider.mutelist.mutelist = {"Accounts": {}}
fake_provider.mutelist.is_finding_muted.return_value = True
output_options = MagicMock()
output_options.status = []
output_options.unix_timestamp = False
execute(check, fake_provider, None, output_options)
# is_finding_muted should have been called with host_id + finding
fake_provider.mutelist.is_finding_muted.assert_called_once_with(
host_id="fake-host-1", finding=finding
)