mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
fix(sdk): unwrap namespaced config for all built-in and external providers
load_and_validate_config_file only detected the namespaced format for 5 hardcoded providers (aws, gcp, azure, kubernetes, m365). For every other built-in (github, nhn, vercel, cloudflare, iac, llm, image, mongodbatlas, oraclecloud, openstack, alibabacloud, googleworkspace) and for any external plug-in, the full YAML was returned wrapped instead of the provider's own block. Replace the hardcoded list with a dynamic check: if the file has a top-level key matching the provider and its value is a dict, unwrap it. Keep the legacy flat format for AWS only (historical, pre-multicloud) and identify it by the absence of nested-dict top-level values, which prevents cross-provider config leakage when a namespaced file has no section for the requested provider.
This commit is contained in:
@@ -9,6 +9,10 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Support for external/custom providers, checks, and compliance frameworks without modifying core code [(#10700)](https://github.com/prowler-cloud/prowler/pull/10700)
|
||||
- SARIF output format for the IaC provider, enabling GitHub Code Scanning integration via `--output-formats sarif` [(#10626)](https://github.com/prowler-cloud/prowler/pull/10626)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- `load_and_validate_config_file` now unwraps namespaced config for every built-in and external provider, and no longer leaks the full file as the provider's config when the file is namespaced [(#10700)](https://github.com/prowler-cloud/prowler/pull/10700)
|
||||
|
||||
---
|
||||
|
||||
## [5.24.3] (Prowler v5.24.3)
|
||||
|
||||
+18
-10
@@ -239,18 +239,26 @@ def load_and_validate_config_file(provider: str, config_file_path: str) -> dict:
|
||||
with open(config_file_path, "r", encoding=encoding_format_utf_8) as f:
|
||||
config_file = yaml.safe_load(f)
|
||||
|
||||
# Not to introduce a breaking change, allow the old format config file without any provider keys
|
||||
# and a new format with a key for each provider to include their configuration values within.
|
||||
if any(
|
||||
key in config_file
|
||||
for key in ["aws", "gcp", "azure", "kubernetes", "m365"]
|
||||
# Namespaced format: each provider has its own top-level key.
|
||||
# Works for every built-in and every external plugin without a hardcoded list.
|
||||
# Flat legacy format is AWS-only (historical, pre-multicloud). We identify it
|
||||
# by the absence of nested-dict top-level values (namespaced files always
|
||||
# have dict values; the legacy AWS format only has primitives/lists).
|
||||
if (
|
||||
isinstance(config_file, dict)
|
||||
and provider in config_file
|
||||
and isinstance(config_file[provider], dict)
|
||||
):
|
||||
config = config_file.get(provider, {})
|
||||
config = config_file.get(provider, {}) or {}
|
||||
elif (
|
||||
isinstance(config_file, dict)
|
||||
and config_file
|
||||
and provider == "aws"
|
||||
and not any(isinstance(v, dict) for v in config_file.values())
|
||||
):
|
||||
config = config_file
|
||||
else:
|
||||
config = config_file if config_file else {}
|
||||
# Not to break Azure, K8s and GCP does not support or use the old config format
|
||||
if provider in ["azure", "gcp", "kubernetes", "m365"]:
|
||||
config = {}
|
||||
config = {}
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@@ -465,6 +465,32 @@ class Test_Config:
|
||||
assert load_and_validate_config_file("azure", config_test_file) == {}
|
||||
assert load_and_validate_config_file("kubernetes", config_test_file) == {}
|
||||
|
||||
def test_load_and_validate_config_file_namespaced_non_listed_provider(self):
|
||||
path = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
config_test_file = f"{path}/fixtures/config_namespaced_external.yaml"
|
||||
# github is a built-in not in the legacy hardcoded list; namespaced format must unwrap it.
|
||||
assert load_and_validate_config_file("github", config_test_file) == {
|
||||
"token": "abc",
|
||||
"org": "prowler-cloud",
|
||||
}
|
||||
|
||||
def test_load_and_validate_config_file_namespaced_external_provider(self):
|
||||
path = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
config_test_file = f"{path}/fixtures/config_namespaced_external.yaml"
|
||||
# External plug-in provider: namespaced format must unwrap its block.
|
||||
assert load_and_validate_config_file("custom_plugin", config_test_file) == {
|
||||
"setting": "value",
|
||||
"nested": {"key": 42},
|
||||
}
|
||||
|
||||
def test_load_and_validate_config_file_namespaced_missing_provider(self):
|
||||
path = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
config_test_file = f"{path}/fixtures/config_namespaced_external.yaml"
|
||||
# Provider with no section in a namespaced file must return empty config,
|
||||
# not the full file (prevents cross-provider config leakage).
|
||||
assert load_and_validate_config_file("aws", config_test_file) == {}
|
||||
assert load_and_validate_config_file("gcp", config_test_file) == {}
|
||||
|
||||
def test_load_and_validate_config_file_invalid_config_file_path(self, caplog):
|
||||
provider = "aws"
|
||||
config_file_path = "invalid/path/to/fixer_config.yaml"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Namespaced config covering a non-listed built-in (github) and an external plugin.
|
||||
github:
|
||||
token: abc
|
||||
org: prowler-cloud
|
||||
custom_plugin:
|
||||
setting: value
|
||||
nested:
|
||||
key: 42
|
||||
Reference in New Issue
Block a user