fix(sdk): exclude sdk_only providers from scan config schema

- Filter _build_aggregated_schema by Provider.get_app_providers
- Keep provider schemas in SCHEMAS for CLI config.yaml validation
- Cover the app-facing schema with tests
This commit is contained in:
StylusFrost
2026-07-22 22:50:02 +02:00
parent dcf2736e8d
commit 7ec3d81df2
4 changed files with 55 additions and 1 deletions
@@ -0,0 +1 @@
Scan configuration schema no longer exposes SDK/CLI-only providers such as `e2enetworks`; the aggregated schema served by `/scan-configurations/schema` now includes only app providers (`sdk_only = False`)
+11
View File
@@ -225,9 +225,20 @@ def _build_aggregated_schema() -> dict:
The output mirrors the layout of `prowler/config/config.yaml` (a mapping
keyed by provider type) and is what the UI consumes via `ajv`.
Only app-facing providers (`sdk_only = False`, see
`Provider.get_app_providers`) are included. SDK/CLI-only providers may
still have a schema registered in `SCHEMAS` so the CLI validates their
`config.yaml` (`load_and_validate_config_file` reads `SCHEMAS.get`), but
they must not surface in this app-facing schema.
"""
from prowler.providers.common.provider import Provider
app_providers = set(Provider.get_app_providers())
properties: dict[str, dict] = {}
for provider, schema_cls in SCHEMAS.items():
if provider not in app_providers:
continue
properties[provider] = schema_cls.model_json_schema()
return {
"$schema": "https://json-schema.org/draft/2020-12/schema",
+4 -1
View File
@@ -20,7 +20,10 @@ EXCLUSION_FIELDS = ("excluded_checks", "excluded_services")
class Test_JSON_Schema_Exposes_Exclusion_Fields:
@pytest.mark.parametrize("provider", sorted(SCHEMAS))
# The aggregated schema is app-facing and only carries app providers
# (``sdk_only = False``); iterate exactly what it exposes so SDK/CLI-only
# providers (still in ``SCHEMAS`` for CLI validation) are not asserted here.
@pytest.mark.parametrize("provider", sorted(SCAN_CONFIG_SCHEMA["properties"]))
@pytest.mark.parametrize("field", EXCLUSION_FIELDS)
def test_field_shape(self, provider, field):
field_schema = SCAN_CONFIG_SCHEMA["properties"][provider]["properties"][field]
@@ -13,11 +13,15 @@ from unittest.mock import call, patch
import pytest
from prowler.config.scan_config_schema import (
SCAN_CONFIG_SCHEMA,
_build_aggregated_schema,
_get_provider_check_ids,
_get_provider_services,
validate_and_normalize_scan_config,
validate_scan_config,
)
from prowler.config.schema.registry import SCHEMAS
from prowler.providers.common.provider import Provider
@pytest.fixture(autouse=True)
@@ -391,3 +395,38 @@ class Test_Backward_Compatible_Wrapper:
"message": "Scan config must be a mapping with provider sections.",
}
]
class Test_Aggregated_Schema_Is_App_Facing:
"""``SCAN_CONFIG_SCHEMA`` is served by the app
(``/scan-configurations/schema``) and consumed by the UI editor, so it must
expose only app providers (``sdk_only = False``). SDK/CLI-only providers
must not leak into it, even when they have a config schema registered in
``SCHEMAS`` for CLI ``config.yaml`` validation."""
def test_sdk_only_provider_is_absent_from_schema(self):
# ``e2enetworks`` is ``sdk_only = True`` yet has a schema registered in
# ``SCHEMAS``; it must not surface in the app-facing aggregated schema.
assert "e2enetworks" not in SCAN_CONFIG_SCHEMA["properties"]
def test_schema_contains_only_app_providers(self):
app_providers = set(Provider.get_app_providers())
assert set(SCAN_CONFIG_SCHEMA["properties"]).issubset(app_providers)
def test_app_provider_with_registered_schema_is_present(self):
assert "aws" in SCAN_CONFIG_SCHEMA["properties"]
def test_registry_still_registers_sdk_only_provider_for_cli(self):
# Guard against "fixing" the leak by dropping ``e2enetworks`` from
# ``SCHEMAS``: ``load_and_validate_config_file()`` relies on
# ``SCHEMAS.get(provider)`` and a missing schema silently disables
# ``config.yaml`` validation for that provider on the CLI.
assert "e2enetworks" in SCHEMAS
def test_build_filters_registry_by_app_providers(self):
# Deterministic mechanism check: only providers returned by
# ``get_app_providers()`` survive the aggregation, regardless of what
# ``SCHEMAS`` contains.
with patch.object(Provider, "get_app_providers", return_value=["aws"]):
schema = _build_aggregated_schema()
assert set(schema["properties"]) == {"aws"}