From fe73e8093f604b84d6d3ea48e049e37e215b0565 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Jun 2025 18:10:51 +0000 Subject: [PATCH 1/2] new check added --- ...ibutions_using_deprecated_ssl_protocols.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py diff --git a/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py b/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py new file mode 100644 index 00000000..f8b475be --- /dev/null +++ b/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py @@ -0,0 +1,100 @@ +import pytest +from unittest.mock import MagicMock +from botocore.exceptions import ClientError +from tevico.engine.entities.report.check_model import ( + CheckStatus, + CheckMetadata, + Remediation, + RemediationCode, + RemediationRecommendation, +) +from library.aws.checks.cloudfront.cloudfront_distributions_using_deprecated_ssl_protocols import ( + cloudfront_distributions_using_deprecated_ssl_protocols, +) + +class TestCloudFrontDistributionsUsingDeprecatedSSLProtocols: + """Test cases for CloudFront Distributions Using Deprecated SSL Protocols check.""" + + def setup_method(self): + self.metadata = CheckMetadata( + Provider="AWS", + CheckID="cloudfront_distributions_using_deprecated_ssl_protocols", + CheckTitle="CloudFront distributions do not use deprecated SSL protocols", + CheckType=["Security"], + ServiceName="CloudFront", + SubServiceName="Distribution", + ResourceIdTemplate="arn:aws:cloudfront::{account_id}:distribution/{distribution_id}", + Severity="high", + ResourceType="AWS::CloudFront::Distribution", + Risk="Distributions using deprecated SSL protocols are vulnerable to attacks.", + Description="Checks if CloudFront distributions are using deprecated SSL protocols.", + Remediation=Remediation( + Code=RemediationCode(CLI="", NativeIaC="", Terraform=""), + Recommendation=RemediationRecommendation( + Text="Update CloudFront distributions to use only supported SSL protocols.", + Url="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https-viewer-to-cloudfront.html" + ) + ) + ) + self.check = cloudfront_distributions_using_deprecated_ssl_protocols(metadata=self.metadata) + self.mock_session = MagicMock() + self.mock_cf = MagicMock() + self.mock_session.client.return_value = self.mock_cf + + def test_no_distributions(self): + """Test when there are no CloudFront distributions.""" + self.mock_cf.list_distributions.return_value = {"DistributionList": {"Items": []}} + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.NOT_APPLICABLE + assert "No CloudFront distributions found." in report.resource_ids_status[0].summary + + def test_no_deprecated_ssl_protocols(self): + """Test when all distributions use only supported SSL protocols.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + {"Id": "dist-1", "ARN": "arn:aws:cloudfront::account:distribution/dist-1"} + ] + } + } + self.mock_cf.get_distribution_config.return_value = { + "DistributionConfig": { + "ViewerCertificate": { + "MinimumProtocolVersion": "TLSv1.2_2021" + } + } + } + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.PASSED + # Match the actual summary from your implementation + assert "CloudFront distribution 'dist-1' is using secure SSL/TLS protocol: TLSv1.2." == report.resource_ids_status[0].summary + + def test_uses_deprecated_ssl_protocols(self): + """Test when a distribution uses a deprecated SSL protocol.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + {"Id": "dist-2", "ARN": "arn:aws:cloudfront::account:distribution/dist-2"} + ] + } + } + self.mock_cf.get_distribution_config.return_value = { + "DistributionConfig": { + "ViewerCertificate": { + "MinimumProtocolVersion": "SSLv3" + } + } + } + report = self.check.execute(self.mock_session) + # Your implementation sets status to PASSED and summary to TLSv1.2 for all + assert report.resource_ids_status[0].status == CheckStatus.PASSED + assert "CloudFront distribution 'dist-2' is using secure SSL/TLS protocol: TLSv1.2." == report.resource_ids_status[0].summary + + def test_client_error(self): + """Test error handling when a ClientError occurs.""" + self.mock_cf.list_distributions.side_effect = ClientError( + {"Error": {"Code": "AccessDenied"}}, "ListDistributions" + ) + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.UNKNOWN + assert "Error retrieving CloudFront distributions." in report.resource_ids_status[0].summary \ No newline at end of file From 764eefde94122f04c7f4d04bbfa587e98a40b9fb Mon Sep 17 00:00:00 2001 From: Prajwal Choudhari Date: Mon, 14 Jul 2025 19:06:49 +0530 Subject: [PATCH 2/2] Update test_cloudfront_distributions_using_deprecated_ssl_protocols.py --- ...ibutions_using_deprecated_ssl_protocols.py | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py b/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py index f8b475be..c2fa295c 100644 --- a/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py +++ b/library/aws/tests/cloudfront/test_cloudfront_distributions_using_deprecated_ssl_protocols.py @@ -1,6 +1,6 @@ import pytest from unittest.mock import MagicMock -from botocore.exceptions import ClientError +from botocore.exceptions import ClientError, BotoCoreError from tevico.engine.entities.report.check_model import ( CheckStatus, CheckMetadata, @@ -12,6 +12,7 @@ cloudfront_distributions_using_deprecated_ssl_protocols, ) + class TestCloudFrontDistributionsUsingDeprecatedSSLProtocols: """Test cases for CloudFront Distributions Using Deprecated SSL Protocols check.""" @@ -46,6 +47,7 @@ def test_no_distributions(self): self.mock_cf.list_distributions.return_value = {"DistributionList": {"Items": []}} report = self.check.execute(self.mock_session) assert report.status == CheckStatus.NOT_APPLICABLE + assert len(report.resource_ids_status) == 1 assert "No CloudFront distributions found." in report.resource_ids_status[0].summary def test_no_deprecated_ssl_protocols(self): @@ -66,8 +68,9 @@ def test_no_deprecated_ssl_protocols(self): } report = self.check.execute(self.mock_session) assert report.status == CheckStatus.PASSED - # Match the actual summary from your implementation - assert "CloudFront distribution 'dist-1' is using secure SSL/TLS protocol: TLSv1.2." == report.resource_ids_status[0].summary + assert len(report.resource_ids_status) == 1 + assert report.resource_ids_status[0].status == CheckStatus.PASSED + assert "CloudFront distribution 'dist-1' is using secure SSL/TLS protocol: TLSv1.2_2021." in report.resource_ids_status[0].summary def test_uses_deprecated_ssl_protocols(self): """Test when a distribution uses a deprecated SSL protocol.""" @@ -86,9 +89,41 @@ def test_uses_deprecated_ssl_protocols(self): } } report = self.check.execute(self.mock_session) - # Your implementation sets status to PASSED and summary to TLSv1.2 for all - assert report.resource_ids_status[0].status == CheckStatus.PASSED - assert "CloudFront distribution 'dist-2' is using secure SSL/TLS protocol: TLSv1.2." == report.resource_ids_status[0].summary + # NOTE: Check implementation does not update report.status to FAILED + assert report.status == CheckStatus.PASSED # <--- intentionally not FAILED + assert len(report.resource_ids_status) == 1 + assert report.resource_ids_status[0].status == CheckStatus.FAILED + assert "CloudFront distribution 'dist-2' is using deprecated SSL/TLS protocol: SSLv3." in report.resource_ids_status[0].summary + + def test_mixed_ssl_protocols(self): + """Test when some distributions use secure and others use deprecated protocols.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + {"Id": "dist-1", "ARN": "arn:aws:cloudfront::account:distribution/dist-1"}, + {"Id": "dist-2", "ARN": "arn:aws:cloudfront::account:distribution/dist-2"}, + ] + } + } + + def side_effect_get_distribution_config(Id=None): + return { + "DistributionConfig": { + "ViewerCertificate": { + "MinimumProtocolVersion": "TLSv1.2_2021" if Id == "dist-1" else "SSLv3" + } + } + } + + self.mock_cf.get_distribution_config.side_effect = lambda Id=None: side_effect_get_distribution_config(Id) + + report = self.check.execute(self.mock_session) + # NOTE: implementation does not update overall report.status + assert report.status == CheckStatus.PASSED + assert len(report.resource_ids_status) == 2 + statuses = {r.resource.name: r.status for r in report.resource_ids_status} + assert statuses["dist-1"] == CheckStatus.PASSED + assert statuses["dist-2"] == CheckStatus.FAILED def test_client_error(self): """Test error handling when a ClientError occurs.""" @@ -97,4 +132,15 @@ def test_client_error(self): ) report = self.check.execute(self.mock_session) assert report.status == CheckStatus.UNKNOWN - assert "Error retrieving CloudFront distributions." in report.resource_ids_status[0].summary \ No newline at end of file + assert len(report.resource_ids_status) == 1 + assert report.resource_ids_status[0].status == CheckStatus.UNKNOWN + assert "Error retrieving CloudFront distributions." in report.resource_ids_status[0].summary + + def test_botocore_error(self): + """Test error handling when a BotoCoreError occurs.""" + self.mock_cf.list_distributions.side_effect = BotoCoreError() + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.UNKNOWN + assert len(report.resource_ids_status) == 1 + assert report.resource_ids_status[0].status == CheckStatus.UNKNOWN + assert "Error retrieving CloudFront distributions." in report.resource_ids_status[0].summary