mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
fix(ecr): read each registry scanning rule's frequency instead of assuming scan on push (#12560)
This commit is contained in:
+243
-2
@@ -72,6 +72,7 @@ class Test_ecr_registry_scan_images_on_push_enabled:
|
||||
assert len(result) == 0
|
||||
|
||||
def test_registry_scan_on_push_enabled(self):
|
||||
"""A BASIC registry whose one unfiltered rule is SCAN_ON_PUSH passes as scan on push."""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
@@ -119,7 +120,7 @@ class Test_ecr_registry_scan_images_on_push_enabled:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has BASIC scan with scan on push enabled."
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has BASIC scanning with scan on push for all repositories."
|
||||
)
|
||||
assert result[0].resource_id == AWS_ACCOUNT_NUMBER
|
||||
assert (
|
||||
@@ -186,6 +187,7 @@ class Test_ecr_registry_scan_images_on_push_enabled:
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
def test_scan_on_push_disabled(self):
|
||||
"""A registry with no scanning rules at all fails: no frequency is configured to read."""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
@@ -228,7 +230,7 @@ class Test_ecr_registry_scan_images_on_push_enabled:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has BASIC scanning without scan on push enabled."
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has BASIC scanning without automated scanning enabled."
|
||||
)
|
||||
assert result[0].resource_id == AWS_ACCOUNT_NUMBER
|
||||
assert (
|
||||
@@ -236,3 +238,242 @@ class Test_ecr_registry_scan_images_on_push_enabled:
|
||||
== f"arn:aws:ecr:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:registry/{AWS_ACCOUNT_NUMBER}"
|
||||
)
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
def test_enhanced_with_no_rules_fails(self):
|
||||
"""An ENHANCED registry with an empty rule set fails: nothing is scanned automatically.
|
||||
|
||||
Reviewed as a false FAIL, on the grounds that enhanced scanning defaults to continuous
|
||||
scanning for all repositories when no rules are configured. It does not. Enhanced scanning
|
||||
is filter-driven, and a repository matching no filter is not scanned at all: "Any
|
||||
repositories that don't match a filter will have an Off scan frequency and won't be
|
||||
scanned" (https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning-enhanced.html),
|
||||
and "Any repositories not matching an enhanced scanning filter will have scanning disabled"
|
||||
(https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning-filters.html). With
|
||||
no rules at all, no repository matches, so the whole registry goes unscanned.
|
||||
|
||||
Nor is this state a disguised pass. ECR materialises "continuous scanning for all
|
||||
repositories" as an explicit CONTINUOUS_SCAN rule filtered on '*' -- which the check already
|
||||
passes, and which an observed ENHANCED registry returns instead of an empty list. So an
|
||||
empty rule set is either unreachable or genuinely means nothing is scanned, and PASS here
|
||||
would report a registry that scans nothing as covered.
|
||||
"""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
ecr_client.registries[AWS_REGION_EU_WEST_1] = Registry(
|
||||
id=AWS_ACCOUNT_NUMBER,
|
||||
arn=f"arn:aws:ecr:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:registry/{AWS_ACCOUNT_NUMBER}",
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_type="ENHANCED",
|
||||
repositories=[
|
||||
Repository(
|
||||
name=repository_name,
|
||||
arn=repository_arn,
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_on_push=False,
|
||||
policy="",
|
||||
images_details=None,
|
||||
lifecycle_policy="",
|
||||
)
|
||||
],
|
||||
rules=[],
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled.ecr_client",
|
||||
ecr_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled import (
|
||||
ecr_registry_scan_images_on_push_enabled,
|
||||
)
|
||||
|
||||
check = ecr_registry_scan_images_on_push_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has ENHANCED scanning without automated scanning enabled."
|
||||
)
|
||||
|
||||
def test_continuous_scan_is_not_reported_as_scan_on_push(self):
|
||||
"""A CONTINUOUS_SCAN-only registry passes, but must not be described as scan on push.
|
||||
|
||||
Observed against a live ENHANCED registry whose single rule was CONTINUOUS_SCAN: the check
|
||||
reported \"scan with scan on push enabled\", a configuration the registry did not have. The
|
||||
verdict was right and the sentence was not, because scan-on-push was inferred from the mere
|
||||
presence of a rule and scanFrequency was never read."""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
ecr_client.registries[AWS_REGION_EU_WEST_1] = Registry(
|
||||
id=AWS_ACCOUNT_NUMBER,
|
||||
arn=f"arn:aws:ecr:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:registry/{AWS_ACCOUNT_NUMBER}",
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_type="ENHANCED",
|
||||
repositories=[
|
||||
Repository(
|
||||
name=repository_name,
|
||||
arn=repository_arn,
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_on_push=False,
|
||||
policy="",
|
||||
images_details=None,
|
||||
lifecycle_policy="",
|
||||
)
|
||||
],
|
||||
rules=[
|
||||
ScanningRule(
|
||||
scan_frequency="CONTINUOUS_SCAN",
|
||||
scan_filters=[{"filter": "*", "filterType": "WILDCARD"}],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled.ecr_client",
|
||||
ecr_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled import (
|
||||
ecr_registry_scan_images_on_push_enabled,
|
||||
)
|
||||
|
||||
check = ecr_registry_scan_images_on_push_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has ENHANCED scanning with continuous scanning for all repositories."
|
||||
)
|
||||
|
||||
def test_manual_only_scanning_fails(self):
|
||||
"""MANUAL is the third frequency the API returns, and nothing scans a pushed image.
|
||||
|
||||
The registry is BASIC because that is the only scan type MANUAL occurs under: scanFrequency
|
||||
documents CONTINUOUS_SCAN and SCAN_ON_PUSH for ENHANCED, and MANUAL as the BASIC default
|
||||
when scan on push is not specified. Before this was read, any rule at all produced PASS --
|
||||
so a registry that scans nothing until someone asks reported as scanning on push.
|
||||
"""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
ecr_client.registries[AWS_REGION_EU_WEST_1] = Registry(
|
||||
id=AWS_ACCOUNT_NUMBER,
|
||||
arn=f"arn:aws:ecr:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:registry/{AWS_ACCOUNT_NUMBER}",
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_type="BASIC",
|
||||
repositories=[
|
||||
Repository(
|
||||
name=repository_name,
|
||||
arn=repository_arn,
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_on_push=False,
|
||||
policy="",
|
||||
images_details=None,
|
||||
lifecycle_policy="",
|
||||
)
|
||||
],
|
||||
rules=[
|
||||
ScanningRule(
|
||||
scan_frequency="MANUAL",
|
||||
scan_filters=[{"filter": "*", "filterType": "WILDCARD"}],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled.ecr_client",
|
||||
ecr_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled import (
|
||||
ecr_registry_scan_images_on_push_enabled,
|
||||
)
|
||||
|
||||
check = ecr_registry_scan_images_on_push_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has BASIC scanning set to manual only, so images are not scanned when they are pushed."
|
||||
)
|
||||
|
||||
def test_both_frequencies_are_named_in_a_fixed_order(self):
|
||||
"""Two rules, one of each frequency: the wording is ordered, not set-iteration order.
|
||||
|
||||
ECR allows up to two rules, so this is a real configuration rather than a contrived one. The
|
||||
frequencies are collected into a set, and rendering a set directly would let the sentence vary
|
||||
between runs for identical input.
|
||||
"""
|
||||
ecr_client = mock.MagicMock
|
||||
ecr_client.audited_account_arn = AWS_ACCOUNT_ARN
|
||||
ecr_client.registries = {}
|
||||
ecr_client.registries[AWS_REGION_EU_WEST_1] = Registry(
|
||||
id=AWS_ACCOUNT_NUMBER,
|
||||
arn=f"arn:aws:ecr:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:registry/{AWS_ACCOUNT_NUMBER}",
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_type="ENHANCED",
|
||||
repositories=[
|
||||
Repository(
|
||||
name=repository_name,
|
||||
arn=repository_arn,
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
scan_on_push=True,
|
||||
policy="",
|
||||
images_details=None,
|
||||
lifecycle_policy="",
|
||||
)
|
||||
],
|
||||
rules=[
|
||||
ScanningRule(
|
||||
scan_frequency="CONTINUOUS_SCAN",
|
||||
scan_filters=[{"filter": "*", "filterType": "WILDCARD"}],
|
||||
),
|
||||
ScanningRule(
|
||||
scan_frequency="SCAN_ON_PUSH",
|
||||
scan_filters=[{"filter": "*", "filterType": "WILDCARD"}],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled.ecr_client",
|
||||
ecr_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.ecr.ecr_registry_scan_images_on_push_enabled.ecr_registry_scan_images_on_push_enabled import (
|
||||
ecr_registry_scan_images_on_push_enabled,
|
||||
)
|
||||
|
||||
check = ecr_registry_scan_images_on_push_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"ECR registry {AWS_ACCOUNT_NUMBER} has ENHANCED scanning with scan on push and continuous scanning for all repositories."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user