Files
prowler/tests/lib/outputs/compliance/ens/ens_table_test.py
T

236 lines
7.9 KiB
Python

import re
from types import SimpleNamespace
from prowler.lib.outputs.compliance.ens.ens import get_ens_table
def _strip_ansi(text):
return re.sub(r"\x1b\[[0-9;]*m", "", text)
def _make_finding(check_id, status="PASS", muted=False):
return SimpleNamespace(
check_metadata=SimpleNamespace(CheckID=check_id),
status=status,
muted=muted,
)
def _attr(marco, categoria, tipo="requisito", nivel="alto"):
return SimpleNamespace(Marco=marco, Categoria=categoria, Tipo=tipo, Nivel=nivel)
def _make_compliance(provider, attributes, framework="ENS"):
"""Build a per-check ENS compliance with the given marco/categoria attrs."""
return SimpleNamespace(
Framework=framework,
Provider=provider,
Requirements=[SimpleNamespace(Attributes=attributes)],
)
class TestENSTable:
"""Test cases for ENS compliance table rendering.
Verify multi-marco counting and provider-column attribution for the
compliance table.
"""
def test_no_cumple_marked_in_every_marco(self, capsys, tmp_path):
"""A single failing finding mapped to several marcos must mark every
one of them as NO CUMPLE, not only the first marco seen."""
bulk_metadata = {
# check_a fails and belongs to two distinct marcos/categorias.
"check_a": SimpleNamespace(
Compliance=[
_make_compliance(
"aws",
[
_attr("operacional", "control de acceso"),
_attr("organizativo", "politica de seguridad"),
],
)
]
),
# A passing finding so the overview total reaches 2.
"check_b": SimpleNamespace(
Compliance=[
_make_compliance("aws", [_attr("operacional", "control de acceso")])
]
),
}
findings = [
_make_finding("check_a", "FAIL"),
_make_finding("check_b", "PASS"),
]
get_ens_table(
findings,
bulk_metadata,
"ens_rd2022_aws",
"output",
str(tmp_path),
False,
)
captured = capsys.readouterr()
plain = _strip_ansi(captured.out)
# Both marco rows the failing finding maps to must read NO CUMPLE.
# Before the fix only the first marco was marked, the second stayed
# CUMPLE. Anchor the assertion to the actual marco rows (not the
# overview header line which also mentions NO CUMPLE).
op_row = [
line
for line in plain.splitlines()
if "operacional/control de acceso" in line
]
org_row = [
line
for line in plain.splitlines()
if "organizativo/politica de seguridad" in line
]
assert len(op_row) == 1 and "NO CUMPLE" in op_row[0]
assert len(org_row) == 1 and "NO CUMPLE" in org_row[0]
def test_recomendacion_does_not_set_no_cumple(self, capsys, tmp_path):
"""A FAIL on a 'recomendacion' attribute must not flip a marco to
NO CUMPLE (this path is intentionally excluded from the fix)."""
bulk_metadata = {
"check_a": SimpleNamespace(
Compliance=[
_make_compliance(
"aws",
[
_attr(
"operacional", "control de acceso", tipo="recomendacion"
)
],
)
]
),
"check_b": SimpleNamespace(
Compliance=[
_make_compliance("aws", [_attr("organizativo", "politica")])
]
),
# A regular (non-recomendacion) check so the results table renders
# at least one marco row and the assertion below is not vacuous.
"check_c": SimpleNamespace(
Compliance=[
_make_compliance("aws", [_attr("operacional", "continuidad")])
]
),
}
findings = [
_make_finding("check_a", "FAIL"),
_make_finding("check_b", "PASS"),
_make_finding("check_c", "PASS"),
]
get_ens_table(
findings,
bulk_metadata,
"ens_rd2022_aws",
"output",
str(tmp_path),
False,
)
captured = capsys.readouterr()
plain = _strip_ansi(captured.out)
# The recomendacion FAIL must not appear as a NO CUMPLE marco row in the
# results table (the overview header line is allowed to mention it).
marco_rows = [
line
for line in plain.splitlines()
if "operacional" in line or "organizativo" in line
]
# Guard against a vacuous pass: the table must actually render rows.
assert marco_rows
assert all("NO CUMPLE" not in line for line in marco_rows)
def test_muted_multi_marco_not_undercounted(self, capsys, tmp_path):
"""A single MUTED finding mapped to several marcos must increment the
per-marco Muted column for every marco, not only the first seen."""
bulk_metadata = {
"check_a": SimpleNamespace(
Compliance=[
_make_compliance(
"aws",
[
_attr("operacional", "control de acceso"),
_attr("organizativo", "politica de seguridad"),
],
)
]
),
"check_b": SimpleNamespace(
Compliance=[
_make_compliance("aws", [_attr("operacional", "control de acceso")])
]
),
}
findings = [
_make_finding("check_a", "FAIL", muted=True),
_make_finding("check_b", "FAIL"),
]
get_ens_table(
findings,
bulk_metadata,
"ens_rd2022_aws",
"output",
str(tmp_path),
False,
)
captured = capsys.readouterr()
plain = _strip_ansi(captured.out)
# Both marco rows the muted finding maps to must report a Muted count of
# 1 in their last cell.
muted_one_rows = re.findall(r"│\s*1\s*│\s*$", plain, flags=re.MULTILINE)
assert len(muted_one_rows) == 2
def test_provider_column_not_leaked_from_other_framework(self, capsys, tmp_path):
"""The Proveedor column must come from the matched ENS compliance, not
from a different framework that trails it in the compliance list."""
bulk_metadata = {
"check_a": SimpleNamespace(
Compliance=[
_make_compliance(
"aws", [_attr("operacional", "control de acceso")]
),
_make_compliance(
"gcp", [_attr("x", "y")], framework="OtherFramework"
),
]
),
"check_b": SimpleNamespace(
Compliance=[
_make_compliance(
"aws", [_attr("operacional", "control de acceso")]
),
_make_compliance(
"gcp", [_attr("x", "y")], framework="OtherFramework"
),
]
),
}
findings = [
_make_finding("check_a", "FAIL"),
_make_finding("check_b", "PASS"),
]
get_ens_table(
findings,
bulk_metadata,
"ens_rd2022_aws",
"output",
str(tmp_path),
False,
)
captured = capsys.readouterr()
assert "aws" in captured.out
assert "gcp" not in captured.out