mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 21:11:53 +00:00
114 lines
4.6 KiB
Python
114 lines
4.6 KiB
Python
"""Coverage for the ``excluded_checks`` / ``excluded_services`` fields
|
|
added to :class:`prowler.config.schema.base.ProviderConfigBase`.
|
|
|
|
Because the fields live on the base class, every registered provider
|
|
schema exposes them and every provider must therefore share the same
|
|
whitespace / uniqueness / non-empty guarantees. These tests lock in that
|
|
contract at the base level and at the JSON-Schema level (which the UI
|
|
editor consumes via ``ajv``).
|
|
"""
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from prowler.config.scan_config_schema import SCAN_CONFIG_SCHEMA
|
|
from prowler.config.schema.aws import AWSProviderConfig
|
|
from prowler.config.schema.registry import SCHEMAS
|
|
from prowler.config.schema.validator import validate_provider_config
|
|
|
|
EXCLUSION_FIELDS = ("excluded_checks", "excluded_services")
|
|
|
|
|
|
class Test_JSON_Schema_Exposes_Exclusion_Fields:
|
|
@pytest.mark.parametrize("provider", sorted(SCHEMAS))
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_field_shape(self, provider, field):
|
|
field_schema = SCAN_CONFIG_SCHEMA["properties"][provider]["properties"][field]
|
|
assert field_schema["type"] == "array"
|
|
assert field_schema["items"] == {"type": "string", "minLength": 1}
|
|
assert field_schema["uniqueItems"] is True
|
|
assert field_schema["default"] == []
|
|
|
|
|
|
class Test_Exclusion_Field_Validation:
|
|
def _model(self, **kwargs):
|
|
return AWSProviderConfig.model_validate(kwargs)
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_empty_string_is_rejected(self, field):
|
|
with pytest.raises(ValidationError):
|
|
self._model(**{field: [""]})
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_whitespace_only_string_is_rejected(self, field):
|
|
with pytest.raises(ValidationError):
|
|
self._model(**{field: [" "]})
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_raw_duplicates_are_rejected(self, field):
|
|
with pytest.raises(ValidationError):
|
|
self._model(**{field: ["s3", "s3"]})
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_normalized_duplicates_are_rejected(self, field):
|
|
# After whitespace normalization ``" s3 "`` collapses to ``"s3"``
|
|
# and must be caught by the duplicate check.
|
|
with pytest.raises(ValidationError):
|
|
self._model(**{field: ["s3", " s3 "]})
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_whitespace_is_stripped(self, field):
|
|
model = self._model(**{field: [" identifier "]})
|
|
assert getattr(model, field) == ["identifier"]
|
|
|
|
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
|
|
def test_non_string_item_is_rejected(self, field):
|
|
with pytest.raises(ValidationError):
|
|
self._model(**{field: [123]})
|
|
|
|
|
|
class Test_Exclusion_Defaults_Are_Not_Injected:
|
|
"""The strict normalization path uses ``model_dump(exclude_unset=True)``
|
|
so pre-existing configs that never set an exclusion field must round-trip
|
|
without the default empty list being materialized."""
|
|
|
|
def test_absent_fields_are_not_injected_by_validator(self):
|
|
# The lenient SDK runtime path also uses ``exclude_unset=True`` under
|
|
# the hood; asserting on the validator output guards the promise
|
|
# against future refactors.
|
|
assert validate_provider_config("aws", {}, SCHEMAS["aws"]) == {}
|
|
|
|
def test_absent_fields_are_not_injected_when_other_keys_are_present(self):
|
|
assert validate_provider_config(
|
|
"aws",
|
|
{"max_ec2_instance_age_in_days": 180},
|
|
SCHEMAS["aws"],
|
|
) == {"max_ec2_instance_age_in_days": 180}
|
|
|
|
def test_explicit_empty_list_round_trips(self):
|
|
# Explicitly setting ``excluded_checks: []`` is different from
|
|
# omitting it — the empty list is user-provided and must be
|
|
# preserved by the strict-normalization contract.
|
|
assert validate_provider_config(
|
|
"aws",
|
|
{"excluded_checks": []},
|
|
SCHEMAS["aws"],
|
|
) == {"excluded_checks": []}
|
|
|
|
|
|
class Test_Extra_Fields_Are_Preserved:
|
|
"""``extra="allow"`` must keep plugin-provided keys around so the
|
|
ecosystem contract in ``validator_test.py`` still holds after adding
|
|
the exclusion fields."""
|
|
|
|
def test_unknown_keys_are_preserved_alongside_exclusions(self):
|
|
out = validate_provider_config(
|
|
"aws",
|
|
{"excluded_checks": ["s3_bucket_public_access"], "plugin_option": "kept"},
|
|
SCHEMAS["aws"],
|
|
)
|
|
assert out == {
|
|
"excluded_checks": ["s3_bucket_public_access"],
|
|
"plugin_option": "kept",
|
|
}
|