fix(sdk): dedupe entry-point compliance frameworks against built-ins

The entry-point loop in get_available_compliance_frameworks appended
framework names without checking whether the same name was already
provided by a built-in. The loader (Compliance.get_bulk) already
respects "built-in wins" via an explicit guard, but the listing
function did not, causing --list-compliance and
--list-compliance-requirements to print the same name twice on
collision with a built-in.

Adds the same dedup guard already used by the universal frameworks
loop a few lines above, restoring symmetry across the three
compliance discovery layers.

Includes a regression test that registers a fake entry point with
a name colliding with a known built-in (cis_2.0_aws) and asserts
the framework appears exactly once in the resulting list.
This commit is contained in:
StylusFrost
2026-05-07 09:32:48 +02:00
parent 020388824e
commit e5b9fee942
2 changed files with 29 additions and 3 deletions
+3 -3
View File
@@ -150,9 +150,9 @@ def get_available_compliance_frameworks(provider=None):
if os.path.isdir(path):
for file in os.scandir(path):
if file.is_file() and file.name.endswith(".json"):
available_compliance_frameworks.append(
file.name.removesuffix(".json")
)
name = file.name.removesuffix(".json")
if name not in available_compliance_frameworks:
available_compliance_frameworks.append(name)
return available_compliance_frameworks
+26
View File
@@ -463,6 +463,32 @@ class Test_Config:
all_frameworks = get_available_compliance_frameworks()
assert "csa_ccm_4.0" in all_frameworks
@mock.patch("prowler.config.config._get_ep_compliance_dirs")
def test_get_available_compliance_frameworks_dedupes_ep_collisions_with_builtins(
self, mock_dirs
):
"""Entry-point compliance frameworks that collide with a built-in
name must appear only once in the available frameworks list.
Built-in wins silently — same policy as the universal frameworks
loop and as Compliance.get_bulk."""
import json
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
# cis_2.0_aws ships as a built-in under prowler/compliance/aws/
json_path = os.path.join(tmpdir, "cis_2.0_aws.json")
with open(json_path, "w") as f:
json.dump({"Framework": "CIS", "Provider": "aws"}, f)
mock_dirs.return_value = {"aws": tmpdir}
frameworks = get_available_compliance_frameworks("aws")
assert frameworks.count("cis_2.0_aws") == 1, (
f"Expected cis_2.0_aws to appear exactly once, got "
f"{frameworks.count('cis_2.0_aws')} occurrences in: {frameworks}"
)
def test_load_and_validate_config_file_aws(self):
path = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
config_test_file = f"{path}/fixtures/config.yaml"