From 3e113abdb758beabd7431ed16f2ad00dfa74e37f Mon Sep 17 00:00:00 2001 From: root Date: Fri, 27 Jun 2025 06:36:21 +0000 Subject: [PATCH 1/2] new check added --- ..._cloudfront_distributions_https_enabled.py | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py diff --git a/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py b/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py new file mode 100644 index 00000000..0d344989 --- /dev/null +++ b/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py @@ -0,0 +1,146 @@ +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_https_enabled import ( + cloudfront_distributions_https_enabled, +) + + +class TestCloudFrontDistributionsHTTPSEnabled: + """Test cases for CloudFront Distributions HTTPS Enabled check.""" + + def setup_method(self): + self.metadata = CheckMetadata( + Provider="AWS", + CheckID="cloudfront_distributions_https_enabled", + CheckTitle="CloudFront distributions require HTTPS", + CheckType=["Security"], + ServiceName="CloudFront", + SubServiceName="Distribution", + ResourceIdTemplate="arn:aws:cloudfront::{account_id}:distribution/{distribution_id}", + Severity="high", + ResourceType="AWS::CloudFront::Distribution", + Risk="Distributions allowing HTTP may expose data in transit.", + Description="Checks if CloudFront distributions require HTTPS.", + Remediation=Remediation( + Code=RemediationCode(CLI="", NativeIaC="", Terraform=""), + Recommendation=RemediationRecommendation( + Text="Require HTTPS for all CloudFront distributions.", + Url="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https.html", + ), + ), + ) + self.check = cloudfront_distributions_https_enabled(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_https_only_enabled(self): + """Test when all distributions require HTTPS.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + { + "Id": "dist-1", + "DomainName": "d1.cloudfront.net", + "ARN": "arn:aws:cloudfront::account:distribution/dist-1", + } + ] + } + } + self.mock_cf.get_distribution_config.return_value = { + "DistributionConfig": { + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "https-only"} + } + } + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.PASSED + assert ( + "CloudFront distribution 'dist-1' does NOT enforce HTTPS (policy: allow-all)." + == report.resource_ids_status[0].summary + ) + + def test_https_not_enforced(self): + """Test when a distribution allows HTTP.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + { + "Id": "dist-2", + "DomainName": "d2.cloudfront.net", + "ARN": "arn:aws:cloudfront::account:distribution/dist-2", + } + ] + } + } + self.mock_cf.get_distribution_config.return_value = { + "DistributionConfig": { + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "allow-all"} + } + } + report = self.check.execute(self.mock_session) + assert report.resource_ids_status[0].status == CheckStatus.FAILED + assert ( + "CloudFront distribution 'dist-2' does NOT enforce HTTPS (policy: allow-all)." + == 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 + ) + + def test_https_policy_check(self): + """Test the enforcement of HTTPS policy on CloudFront distributions.""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + { + "Id": "dist-3", + "DomainName": "d3.cloudfront.net", + "ARN": "arn:aws:cloudfront::account:distribution/dist-3", + } + ] + } + } + self.mock_cf.get_distribution_config.return_value = { + "DistributionConfig": { + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "allow-list"} + } + } + report = self.check.execute(self.mock_session) + assert report.resource_ids_status[0].status == CheckStatus.FAILED + assert ( + "CloudFront distribution 'dist-3' does NOT enforce HTTPS (policy: allow-all)." + == report.resource_ids_status[0].summary + ) + assert ( + len(report.resource_ids_status) == 1 + ) # Ensure no duplicate entries are added + From 03418c3493d947a7c271e207afa1b6c98ac5a239 Mon Sep 17 00:00:00 2001 From: Prajwal Choudhari Date: Mon, 14 Jul 2025 19:11:02 +0530 Subject: [PATCH 2/2] Update test_cloudfront_distributions_https_enabled.py --- ..._cloudfront_distributions_https_enabled.py | 104 +++++++++--------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py b/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py index 0d344989..495d0963 100644 --- a/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py +++ b/library/aws/tests/cloudfront/test_cloudfront_distributions_https_enabled.py @@ -44,103 +44,97 @@ def setup_method(self): def test_no_distributions(self): """Test when there are no CloudFront distributions.""" - self.mock_cf.list_distributions.return_value = { - "DistributionList": {"Items": []} - } + 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 - ) + assert len(report.resource_ids_status) == 1 + assert report.resource_ids_status[0].status == CheckStatus.NOT_APPLICABLE + assert "No CloudFront distributions found." in report.resource_ids_status[0].summary - def test_https_only_enabled(self): - """Test when all distributions require HTTPS.""" + def test_https_only_enforced(self): + """Test when HTTPS is enforced via https-only.""" self.mock_cf.list_distributions.return_value = { "DistributionList": { "Items": [ { "Id": "dist-1", - "DomainName": "d1.cloudfront.net", "ARN": "arn:aws:cloudfront::account:distribution/dist-1", + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "https-only"}, } ] } } - self.mock_cf.get_distribution_config.return_value = { - "DistributionConfig": { - "DefaultCacheBehavior": {"ViewerProtocolPolicy": "https-only"} - } - } report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.PASSED - assert ( - "CloudFront distribution 'dist-1' does NOT enforce HTTPS (policy: allow-all)." - == report.resource_ids_status[0].summary - ) + assert report.resource_ids_status[0].status == CheckStatus.PASSED + assert "enforces HTTPS (https-only)" in report.resource_ids_status[0].summary - def test_https_not_enforced(self): - """Test when a distribution allows HTTP.""" + def test_https_redirect_enforced(self): + """Test when HTTPS is enforced via redirect-to-https.""" self.mock_cf.list_distributions.return_value = { "DistributionList": { "Items": [ { "Id": "dist-2", - "DomainName": "d2.cloudfront.net", "ARN": "arn:aws:cloudfront::account:distribution/dist-2", + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "redirect-to-https"}, } ] } } - self.mock_cf.get_distribution_config.return_value = { - "DistributionConfig": { - "DefaultCacheBehavior": {"ViewerProtocolPolicy": "allow-all"} - } - } report = self.check.execute(self.mock_session) - assert report.resource_ids_status[0].status == CheckStatus.FAILED - assert ( - "CloudFront distribution 'dist-2' does NOT enforce HTTPS (policy: allow-all)." - == 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 - ) + assert report.status == CheckStatus.PASSED + assert report.resource_ids_status[0].status == CheckStatus.PASSED + assert "enforces HTTPS (redirect-to-https)" in report.resource_ids_status[0].summary - def test_https_policy_check(self): - """Test the enforcement of HTTPS policy on CloudFront distributions.""" + def test_https_not_enforced(self): + """Test when HTTPS is not enforced (allow-all).""" self.mock_cf.list_distributions.return_value = { "DistributionList": { "Items": [ { "Id": "dist-3", - "DomainName": "d3.cloudfront.net", "ARN": "arn:aws:cloudfront::account:distribution/dist-3", + "DefaultCacheBehavior": {"ViewerProtocolPolicy": "allow-all"}, } ] } } - self.mock_cf.get_distribution_config.return_value = { - "DistributionConfig": { - "DefaultCacheBehavior": {"ViewerProtocolPolicy": "allow-list"} + report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.PASSED # Report status not downgraded for failed resources + assert report.resource_ids_status[0].status == CheckStatus.FAILED + assert "does NOT enforce HTTPS (policy: allow-all)" in report.resource_ids_status[0].summary + + def test_missing_policy_defaults_to_allow_all(self): + """Test when ViewerProtocolPolicy is missing (defaults to allow-all).""" + self.mock_cf.list_distributions.return_value = { + "DistributionList": { + "Items": [ + { + "Id": "dist-4", + "ARN": "arn:aws:cloudfront::account:distribution/dist-4", + "DefaultCacheBehavior": {}, # Missing ViewerProtocolPolicy + } + ] } } report = self.check.execute(self.mock_session) + + assert report.status == CheckStatus.PASSED assert report.resource_ids_status[0].status == CheckStatus.FAILED - assert ( - "CloudFront distribution 'dist-3' does NOT enforce HTTPS (policy: allow-all)." - == report.resource_ids_status[0].summary + assert "does NOT enforce HTTPS (policy: allow-all)" in report.resource_ids_status[0].summary + + def test_client_error_handling(self): + """Test when CloudFront throws a ClientError.""" + self.mock_cf.list_distributions.side_effect = ClientError( + {"Error": {"Code": "AccessDenied"}}, "ListDistributions" ) - assert ( - len(report.resource_ids_status) == 1 - ) # Ensure no duplicate entries are added + report = self.check.execute(self.mock_session) + assert report.status == CheckStatus.UNKNOWN + assert report.resource_ids_status[0].status == CheckStatus.UNKNOWN + assert "Error retrieving CloudFront distributions." in report.resource_ids_status[0].summary