Files
prowler/tests/config/schema/loader_integration_test.py
Pedro Martín 0610866b73 feat(config): add SDK config's validator (#11518)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2026-06-23 09:40:32 +02:00

125 lines
4.9 KiB
Python

"""End-to-end tests that exercise the real ``load_and_validate_config_file``
through a temp YAML file. Anything that breaks here would break the actual
``prowler aws -c …`` code path."""
import logging
import os
import pathlib
from typing import Callable
import pytest
from prowler.config.config import load_and_validate_config_file
@pytest.fixture
def write_config(tmp_path: pathlib.Path) -> Callable[[str], str]:
def _write(content: str) -> str:
path = tmp_path / "config.yaml"
path.write_text(content)
return str(path)
return _write
class Test_Loader_With_Schema_Integration:
def test_shipped_default_config_loads_without_warnings(self, caplog):
"""The default ``prowler/config/config.yaml`` must round-trip every
provider WITHOUT emitting any schema warnings. If this fails,
someone added a key to the YAML without updating the schema."""
repo_root = pathlib.Path(os.path.dirname(os.path.realpath(__file__))).parents[2]
shipped = repo_root / "prowler" / "config" / "config.yaml"
with caplog.at_level(logging.WARNING, logger="prowler"):
for provider in [
"aws",
"azure",
"gcp",
"kubernetes",
"m365",
"github",
"mongodbatlas",
"cloudflare",
"vercel",
]:
cfg = load_and_validate_config_file(provider, str(shipped))
# Provider always exists in the shipped file → non-empty.
assert cfg, f"{provider} returned an empty config"
offending = [
r.getMessage()
for r in caplog.records
if "prowler.config[" in r.getMessage()
]
assert not offending, (
"Shipped config.yaml triggered schema warnings — schema or YAML out of sync:\n"
+ "\n".join(offending)
)
def test_user_config_with_bad_threshold_falls_back(self, write_config, caplog):
path = write_config(
"aws:\n"
" threat_detection_privilege_escalation_threshold: 5.0\n"
" lambda_min_azs: 2\n"
)
with caplog.at_level(logging.WARNING, logger="prowler"):
cfg = load_and_validate_config_file("aws", path)
assert cfg == {"lambda_min_azs": 2}
assert any(
"threat_detection_privilege_escalation_threshold" in r.getMessage()
for r in caplog.records
)
def test_old_format_config_still_works(self, write_config):
# Old format = flat keys, no provider header.
path = write_config(
"max_ec2_instance_age_in_days: 90\n"
"ecr_repository_vulnerability_minimum_severity: HIGH\n"
)
cfg = load_and_validate_config_file("aws", path)
assert cfg == {
"max_ec2_instance_age_in_days": 90,
"ecr_repository_vulnerability_minimum_severity": "HIGH",
}
def test_unknown_keys_pass_through_via_loader(self, write_config):
path = write_config(
"aws:\n" " third_party_plugin_setting: hello\n" " lambda_min_azs: 2\n"
)
cfg = load_and_validate_config_file("aws", path)
assert cfg == {
"third_party_plugin_setting": "hello",
"lambda_min_azs": 2,
}
def test_quoted_numeric_is_coerced_via_loader(self, write_config):
# YAML quotes the number: ``"180"`` arrives as a Python str.
# The schema must coerce it to int so downstream comparisons work.
path = write_config('aws:\n max_ec2_instance_age_in_days: "180"\n')
cfg = load_and_validate_config_file("aws", path)
assert cfg == {"max_ec2_instance_age_in_days": 180}
assert isinstance(cfg["max_ec2_instance_age_in_days"], int)
def test_invalid_yaml_shape_list_as_string_drops_key(self, write_config, caplog):
path = write_config(
"aws:\n"
" disallowed_regions: me-south-1\n" # forgot list dashes
" lambda_min_azs: 2\n"
)
with caplog.at_level(logging.WARNING, logger="prowler"):
cfg = load_and_validate_config_file("aws", path)
assert cfg == {"lambda_min_azs": 2}
assert any("disallowed_regions" in r.getMessage() for r in caplog.records)
def test_other_providers_unaffected_by_aws_block(self, write_config):
path = write_config(
"aws:\n max_ec2_instance_age_in_days: 90\n" "gcp:\n mig_min_zones: 5\n"
)
assert load_and_validate_config_file("aws", path) == {
"max_ec2_instance_age_in_days": 90
}
assert load_and_validate_config_file("gcp", path) == {"mig_min_zones": 5}
def test_missing_provider_block_returns_empty(self, write_config):
path = write_config("aws:\n max_ec2_instance_age_in_days: 90\n")
assert load_and_validate_config_file("azure", path) == {}