From 0cf29562636bd20d9d16989ba3d7a47478ced1eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 09:11:09 +0100 Subject: [PATCH 01/63] Bump urllib3 from 1.26.17 to 1.26.18 (#242) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.17 to 1.26.18. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.17...1.26.18) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 54afd96e..2ea0232e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,4 +18,4 @@ pyyaml==6.0 s3transfer==0.5.2 six==1.16.0 typing-extensions==4.1.1 -urllib3==1.26.17 +urllib3==1.26.18 From 981e2e397f6b88b419ec4dbffabebc05cb5b7c74 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 13 Nov 2023 09:57:36 +0100 Subject: [PATCH 02/63] Update lint-and-test.yml (#247) * Update lint-and-test.yml * Update pyyaml dependency --- .github/workflows/lint-and-test.yml | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index e5eae075..8677fe47 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] name: Python ${{ matrix.python-version }} diff --git a/requirements.txt b/requirements.txt index 2ea0232e..fa70e777 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ pycfmodel==0.20.0 pydantic==1.9.0 pydash==6.0.0 python-dateutil==2.8.2 -pyyaml==6.0 +pyyaml==6.0.1 s3transfer==0.5.2 six==1.16.0 typing-extensions==4.1.1 From 25124293a08a7ff9f7259f59f98560e93b995e32 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 13 Nov 2023 09:57:50 +0100 Subject: [PATCH 03/63] Update README.md (#246) * Update README.md * Add license badge --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 287364e6..f8658527 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ ![Build Status](https://github.com/Skyscanner/cfripper/workflows/PyPI%20release/badge.svg) [![PyPI version](https://badge.fury.io/py/cfripper.svg)](https://badge.fury.io/py/cfripper) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/Skyscanner/cfripper.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Skyscanner/cfripper/alerts/) -[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/Skyscanner/cfripper.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Skyscanner/cfripper/context:python) +![License](https://img.shields.io/github/license/skyscanner/cfripper) CFRipper is a Library and CLI security analyzer for AWS CloudFormation templates. You can use CFRipper to prevent deploying insecure AWS resources into your Cloud environment. You can write your own compliance checks by adding new custom plugins. From 66d15bf4d2c70f15a09d1dc6f20f7332b70f0cec Mon Sep 17 00:00:00 2001 From: Max-Huneshagen <145039806+Max-Huneshagen@users.noreply.github.com> Date: Mon, 13 Nov 2023 10:05:45 +0100 Subject: [PATCH 04/63] Create stack name example rule (#245) * Create new stack name rule. * remove unused import * review comments * lint error * add regex reason as attribute --- cfripper/config/regex.py | 16 +++++ cfripper/rules/__init__.py | 2 + cfripper/rules/stack_name_matches_regex.py | 45 ++++++++++++++ tests/rules/test_StackNameMatchesRegexRule.py | 60 +++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 cfripper/rules/stack_name_matches_regex.py create mode 100644 tests/rules/test_StackNameMatchesRegexRule.py diff --git a/cfripper/config/regex.py b/cfripper/config/regex.py index 39bb40e2..7bd69ea6 100644 --- a/cfripper/config/regex.py +++ b/cfripper/config/regex.py @@ -173,3 +173,19 @@ - sns:Get* """ REGEX_HAS_STAR_OR_STAR_AFTER_COLON = re.compile(r"^(\w*:)*[*?]+$") + + +""" +Check that stack name only consists of alphanumerical characters and hyphens. +Valid: +- abcdefg +- ABCDEFG +- abcdEFG +- aBc-DeFG +- a1b2c3 +Invalid: +- abc_defg +- AB:cdefg +- !@£$$%aA +""" +REGEX_ALPHANUMERICAL_OR_HYPHEN = re.compile(r"^[A-Za-z0-9\-]+$") diff --git a/cfripper/rules/__init__.py b/cfripper/rules/__init__.py index 0522094f..23970fad 100644 --- a/cfripper/rules/__init__.py +++ b/cfripper/rules/__init__.py @@ -38,6 +38,7 @@ SQSQueuePolicyNotPrincipalRule, SQSQueuePolicyPublicRule, ) +from cfripper.rules.stack_name_matches_regex import StackNameMatchesRegexRule from cfripper.rules.wildcard_policies import ( GenericResourceWildcardPolicyRule, S3BucketPolicyWildcardActionRule, @@ -94,6 +95,7 @@ SQSQueuePolicyNotPrincipalRule, SQSQueuePolicyPublicRule, SQSQueuePolicyWildcardActionRule, + StackNameMatchesRegexRule, WildcardResourceRule, ) } diff --git a/cfripper/rules/stack_name_matches_regex.py b/cfripper/rules/stack_name_matches_regex.py new file mode 100644 index 00000000..ca2c8e8f --- /dev/null +++ b/cfripper/rules/stack_name_matches_regex.py @@ -0,0 +1,45 @@ +from typing import Dict, Optional + +from pycfmodel.model.cf_model import CFModel + +from cfripper.config.regex import REGEX_ALPHANUMERICAL_OR_HYPHEN +from cfripper.model.enums import RuleGranularity, RuleMode, RuleRisk +from cfripper.model.result import Result +from cfripper.rules.base_rules import Rule + + +class StackNameMatchesRegexRule(Rule): + """ + Checks that a given stack follows the naming convention given by a regex. For this to work, + the stack name must be given either in the config or in the extras using the key + "stack_name". + """ + + RULE_MODE = RuleMode.DEBUG # for demonstration purposes + RISK_VALUE = RuleRisk.LOW + GRANULARITY = RuleGranularity.STACK + REASON = "The stack name {} does not follow the naming convention, reason: {}" + REGEX = REGEX_ALPHANUMERICAL_OR_HYPHEN + REGEX_REASON = "Only alphanumerical characters and hyphens allowed." + + def _stack_name_matches_regex(self, stack_name: str) -> bool: + """Check that stack name follows naming convention.""" + return bool(self.REGEX.match(stack_name)) + + def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: + result = Result() + stack_name = self._config.stack_name or extras.get("stack_name", "") + if not stack_name: + return result + if not extras: + extras = {} + + if not self._stack_name_matches_regex(stack_name): + self.add_failure_to_result( + result, + self.REASON.format(stack_name, self.REGEX_REASON), + self.GRANULARITY, + risk_value=self.RISK_VALUE, + context={"config": self._config, "extras": extras}, + ) + return result diff --git a/tests/rules/test_StackNameMatchesRegexRule.py b/tests/rules/test_StackNameMatchesRegexRule.py new file mode 100644 index 00000000..684f1377 --- /dev/null +++ b/tests/rules/test_StackNameMatchesRegexRule.py @@ -0,0 +1,60 @@ +import pytest +from pycfmodel.model.cf_model import CFModel + +from cfripper.config.config import Config +from cfripper.rules import StackNameMatchesRegexRule + + +@pytest.mark.parametrize( + "stack_name, expected_result", + [ + ("justlowercase", True), + ("lowercase-with-hyphens", True), + ("lowercaseANDUPPERCASE", True), + ("lowercase-AND-UPPERCASE-with-hyphens", True), + ("also-123-including-456-numbers", True), + ("including_underscore", False), + ("including space", False), + ("including-other-symbols!@£$%^&*()", False), + ], +) +def test_stack_name_matches_regex(stack_name, expected_result): + rule = StackNameMatchesRegexRule(Config(stack_name=stack_name, rules=["StackNameMatchesRegexRule"])) + assert rule._stack_name_matches_regex(stack_name) == expected_result + + +def test_works_with_extras(): + rule = StackNameMatchesRegexRule(Config(stack_name="some-valid-stack-name", rules=["StackNameMatchesRegexRule"])) + extras = {"stack": {"tags": [{"key": "project", "value": "some_project"}]}} + result = rule.invoke(cfmodel=CFModel(), extras=extras) + assert result.valid + + +def test_stack_name_from_extras(): + rule = StackNameMatchesRegexRule(Config(stack_name="some-valid-stack-name", rules=["StackNameMatchesRegexRule"])) + extras = {"stack": {"tags": [{"key": "project", "value": "some_project"}]}, "stack_name": "some_invalid_name"} + result = rule.invoke(cfmodel=CFModel(), extras=extras) + assert result.valid + + +def test_failure_is_added_for_invalid_stack_name(): + rule = StackNameMatchesRegexRule(Config(stack_name="some_invalid_stack_name", rules=["StackNameMatchesRegexRule"])) + result = rule.invoke(cfmodel=CFModel()) + assert result.failures + assert ( + result.failures[0].reason + == "The stack name some_invalid_stack_name does not follow the naming convention, reason: Only alphanumerical " + "characters and hyphens allowed." + ) + + +def test_failure_is_added_for_invalid_stack_name_from_extras(): + rule = StackNameMatchesRegexRule(Config(rules=["StackNameMatchesRegexRule"])) + extras = {"stack": {"tags": [{"key": "project", "value": "some_project"}]}, "stack_name": "some_invalid_stack_name"} + result = rule.invoke(cfmodel=CFModel(), extras=extras) + assert result.failures + assert ( + result.failures[0].reason + == "The stack name some_invalid_stack_name does not follow the naming convention, reason: Only alphanumerical " + "characters and hyphens allowed." + ) From d7848ba9d66a96cfa3c90705ab802052c7d74654 Mon Sep 17 00:00:00 2001 From: Max-Huneshagen <145039806+Max-Huneshagen@users.noreply.github.com> Date: Thu, 16 Nov 2023 09:34:38 +0100 Subject: [PATCH 05/63] Create kms example rule (#248) * Create new stack name rule. * remove unused import * review comments * lint error * add new db encryption rule * remove changes from other pr * Update lint-and-test.yml (#247) * Update lint-and-test.yml * Update pyyaml dependency * Update README.md (#246) * Update README.md * Add license badge * rebase * rebase onto master * rebase * make lint * remove duplicate test * update changelog * add comment as for stack name rule * make format * rule not invoked for aurora * make templates valid cloud formations (except for aurora one) * make templates valid cloud formations * Update tests/rules/test_StorageEncryptedRule.py Co-authored-by: Ignacio Bolonio * add aurora comment --------- Co-authored-by: Jordi Soucheiron Co-authored-by: Ignacio Bolonio --- CHANGELOG.md | 5 ++ cfripper/rules/__init__.py | 2 + cfripper/rules/storage_encrypted_rule.py | 40 +++++++++ tests/rules/test_StorageEncryptedRule.py | 88 +++++++++++++++++++ .../aurora_engine_used.yml | 15 ++++ .../encrypted_db_resource.yml | 18 ++++ .../missing_storage_encrypted_flag.yml | 17 ++++ .../StorageEncryptedRule/no_db_resource.yml | 16 ++++ .../two_resources_not_encrypted.yml | 35 ++++++++ 9 files changed, 236 insertions(+) create mode 100644 cfripper/rules/storage_encrypted_rule.py create mode 100644 tests/rules/test_StorageEncryptedRule.py create mode 100644 tests/test_templates/rules/StorageEncryptedRule/aurora_engine_used.yml create mode 100644 tests/test_templates/rules/StorageEncryptedRule/encrypted_db_resource.yml create mode 100644 tests/test_templates/rules/StorageEncryptedRule/missing_storage_encrypted_flag.yml create mode 100644 tests/test_templates/rules/StorageEncryptedRule/no_db_resource.yml create mode 100644 tests/test_templates/rules/StorageEncryptedRule/two_resources_not_encrypted.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 34dd0e8f..0e0fd091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.15.0] +### Additions +- New rules: `StackNameMatchesRegexRule` and `StorageEncryptedRule` +- New regex: `REGEX_ALPHANUMERICAL_OR_HYPHEN` to check if stack name only consists of alphanumerical characters and hyphens. + ## [1.14.0] ### Additions - `Config` includes a metrics logger, and it is called to register when a filter is used diff --git a/cfripper/rules/__init__.py b/cfripper/rules/__init__.py index 23970fad..46e4d5d2 100644 --- a/cfripper/rules/__init__.py +++ b/cfripper/rules/__init__.py @@ -39,6 +39,7 @@ SQSQueuePolicyPublicRule, ) from cfripper.rules.stack_name_matches_regex import StackNameMatchesRegexRule +from cfripper.rules.storage_encrypted_rule import StorageEncryptedRule from cfripper.rules.wildcard_policies import ( GenericResourceWildcardPolicyRule, S3BucketPolicyWildcardActionRule, @@ -88,6 +89,7 @@ S3BucketPublicReadAclRule, S3CrossAccountTrustRule, S3ObjectVersioningRule, + StorageEncryptedRule, SNSTopicDangerousPolicyActionsRule, SNSTopicPolicyNotPrincipalRule, SNSTopicPolicyWildcardActionRule, diff --git a/cfripper/rules/storage_encrypted_rule.py b/cfripper/rules/storage_encrypted_rule.py new file mode 100644 index 00000000..6864f191 --- /dev/null +++ b/cfripper/rules/storage_encrypted_rule.py @@ -0,0 +1,40 @@ +from typing import Dict, Optional + +from pycfmodel.model.cf_model import CFModel + +from cfripper.model.enums import RuleGranularity, RuleMode, RuleRisk +from cfripper.model.result import Result +from cfripper.rules.base_rules import Rule + + +class StorageEncryptedRule(Rule): + RULE_MODE = RuleMode.DEBUG # for demonstration purposes + RISK_VALUE = RuleRisk.LOW + REASON = ( + "The database {} does not seem to be encrypted. Database resources should be encrypted and have the property " + "StorageEncrypted set to True." + ) + GRANULARITY = RuleGranularity.RESOURCE + + def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: + result = Result() + + for resource in cfmodel.Resources.values(): + is_encrypted = getattr(resource.Properties, "StorageEncrypted", False) + db_name = getattr(resource.Properties, "DBName", "(could not get DB name)") + if ( + resource.Type == "AWS::RDS::DBInstance" + and not is_encrypted + and not getattr(resource.Properties, "Engine", "").startswith( + "aurora" + ) # not applicable for aurora since the encryption for DB instances is managed by the DB cluster + ): + + self.add_failure_to_result( + result, + self.REASON.format(db_name), + context={"config": self._config, "extras": extras}, + resource_types={resource.Type}, + ) + + return result diff --git a/tests/rules/test_StorageEncryptedRule.py b/tests/rules/test_StorageEncryptedRule.py new file mode 100644 index 00000000..2e79ede1 --- /dev/null +++ b/tests/rules/test_StorageEncryptedRule.py @@ -0,0 +1,88 @@ +import pytest + +from cfripper.model.enums import RuleGranularity, RuleMode, RuleRisk +from cfripper.model.result import Failure +from cfripper.rules.storage_encrypted_rule import StorageEncryptedRule +from tests.utils import get_cfmodel_from + + +def test_storage_encrypted_rule_valid_results(): + rule = StorageEncryptedRule(None) + model = get_cfmodel_from("rules/StorageEncryptedRule/encrypted_db_resource.yml") + resolved_model = model.resolve() + result = rule.invoke(resolved_model) + + assert result.valid + assert result.failures == [] + + +def test_rule_not_failing_for_aurora(): + rule = StorageEncryptedRule(None) + model = get_cfmodel_from("rules/StorageEncryptedRule/aurora_engine_used.yml") + resolved_model = model.resolve() + result = rule.invoke(resolved_model) + + assert result.valid + assert result.failures == [] + + +@pytest.mark.parametrize( + "template, failures", + [ + ( + "rules/StorageEncryptedRule/missing_storage_encrypted_flag.yml", + [ + Failure( + granularity=RuleGranularity.RESOURCE, + reason="The database some-name does not seem to be encrypted. Database resources should be " + "encrypted and have the property StorageEncrypted set to True.", + risk_value=RuleRisk.LOW, + rule="StorageEncryptedRule", + rule_mode=RuleMode.DEBUG, + actions=None, + resource_ids=None, + resource_types={"AWS::RDS::DBInstance"}, + ) + ], + ), + ( + "rules/StorageEncryptedRule/two_resources_not_encrypted.yml", + [ + Failure( + granularity=RuleGranularity.RESOURCE, + reason="The database some-name does not seem to be encrypted. Database resources should be " + "encrypted and have the property StorageEncrypted set to True.", + risk_value=RuleRisk.LOW, + rule="StorageEncryptedRule", + rule_mode=RuleMode.DEBUG, + actions=None, + resource_ids=None, + resource_types={"AWS::RDS::DBInstance"}, + ), + Failure( + granularity=RuleGranularity.RESOURCE, + reason="The database some-name-backup does not seem to be encrypted. Database resources should be " + "encrypted and have the property StorageEncrypted set to True.", + risk_value=RuleRisk.LOW, + rule="StorageEncryptedRule", + rule_mode=RuleMode.DEBUG, + actions=None, + resource_ids=None, + resource_types={"AWS::RDS::DBInstance"}, + ), + ], + ), + ( + "rules/StorageEncryptedRule/no_db_resource.yml", + [], + ), + ], +) +def test_add_failure_if_db_resource_not_encrypted(template, failures): + rule = StorageEncryptedRule(None) + model = get_cfmodel_from(template) + resolved_model = model.resolve() + result = rule.invoke(resolved_model) + + assert result.valid + assert result.failures == failures diff --git a/tests/test_templates/rules/StorageEncryptedRule/aurora_engine_used.yml b/tests/test_templates/rules/StorageEncryptedRule/aurora_engine_used.yml new file mode 100644 index 00000000..cab515cb --- /dev/null +++ b/tests/test_templates/rules/StorageEncryptedRule/aurora_engine_used.yml @@ -0,0 +1,15 @@ +Resources: + DBMaster: + Type: AWS::RDS::DBInstance + Properties: + AllowMajorVersionUpgrade: false + AutoMinorVersionUpgrade: true + DBInstanceIdentifier: !Sub ${AWS::StackName}-master + DBName: "some-name" + Engine: aurora-postgresql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + MultiAZ: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-master \ No newline at end of file diff --git a/tests/test_templates/rules/StorageEncryptedRule/encrypted_db_resource.yml b/tests/test_templates/rules/StorageEncryptedRule/encrypted_db_resource.yml new file mode 100644 index 00000000..8efac523 --- /dev/null +++ b/tests/test_templates/rules/StorageEncryptedRule/encrypted_db_resource.yml @@ -0,0 +1,18 @@ +Resources: + DBMaster: + Type: AWS::RDS::DBInstance + Properties: + AllocatedStorage: "100" + AllowMajorVersionUpgrade: false + AutoMinorVersionUpgrade: true + BackupRetentionPeriod: 14 + DBInstanceIdentifier: !Sub ${AWS::StackName}-master + DBName: "some-name" + Engine: mysql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + MultiAZ: true + StorageEncrypted: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-master \ No newline at end of file diff --git a/tests/test_templates/rules/StorageEncryptedRule/missing_storage_encrypted_flag.yml b/tests/test_templates/rules/StorageEncryptedRule/missing_storage_encrypted_flag.yml new file mode 100644 index 00000000..850e1c09 --- /dev/null +++ b/tests/test_templates/rules/StorageEncryptedRule/missing_storage_encrypted_flag.yml @@ -0,0 +1,17 @@ +Resources: + DBMaster: + Type: AWS::RDS::DBInstance + Properties: + AllocatedStorage: "100" + AllowMajorVersionUpgrade: false + AutoMinorVersionUpgrade: true + BackupRetentionPeriod: 14 + DBInstanceIdentifier: !Sub ${AWS::StackName}-master + DBName: "some-name" + Engine: mysql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + MultiAZ: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-master \ No newline at end of file diff --git a/tests/test_templates/rules/StorageEncryptedRule/no_db_resource.yml b/tests/test_templates/rules/StorageEncryptedRule/no_db_resource.yml new file mode 100644 index 00000000..2055a06e --- /dev/null +++ b/tests/test_templates/rules/StorageEncryptedRule/no_db_resource.yml @@ -0,0 +1,16 @@ +Resources: + SomeResource: + Type: AWS::RDS::DBCluster + Properties: + AllocatedStorage: "100" + AutoMinorVersionUpgrade: true + BackupRetentionPeriod: 14 + DBClusterIdentifier: !Sub ${AWS::StackName}-master + DatabaseName: "some-name" + Engine: mysql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + StorageEncrypted: false + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-master \ No newline at end of file diff --git a/tests/test_templates/rules/StorageEncryptedRule/two_resources_not_encrypted.yml b/tests/test_templates/rules/StorageEncryptedRule/two_resources_not_encrypted.yml new file mode 100644 index 00000000..a9b4eea1 --- /dev/null +++ b/tests/test_templates/rules/StorageEncryptedRule/two_resources_not_encrypted.yml @@ -0,0 +1,35 @@ +Resources: + DBMaster: + Type: AWS::RDS::DBInstance + Properties: + AllocatedStorage: "100" + AllowMajorVersionUpgrade: false + AutoMinorVersionUpgrade: true + BackupRetentionPeriod: 14 + DBInstanceIdentifier: !Sub ${AWS::StackName}-master + DBName: "some-name" + Engine: mysql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + MultiAZ: true + StorageEncrypted: false + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-master + DBBackup: + Type: AWS::RDS::DBInstance + Properties: + AllocatedStorage: "100" + AllowMajorVersionUpgrade: true + AutoMinorVersionUpgrade: false + BackupRetentionPeriod: 7 + DBInstanceIdentifier: !Sub ${AWS::StackName}-backup + DBName: "some-name-backup" + Engine: mysql + EngineVersion: "13.2" + KmsKeyId: "some-kms-key" + MultiAZ: true + StorageEncrypted: false + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-backup \ No newline at end of file From 5d5704768dd3ba2844c28a80e7b7f7dab27e0239 Mon Sep 17 00:00:00 2001 From: Max-Huneshagen <145039806+Max-Huneshagen@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:04:09 +0100 Subject: [PATCH 06/63] Create new ELB checker rule (#249) * create new rule * create new rule * refactor tests * Create kms example rule (#248) * Create new stack name rule. * remove unused import * review comments * lint error * add new db encryption rule * remove changes from other pr * Update lint-and-test.yml (#247) * Update lint-and-test.yml * Update pyyaml dependency * Update README.md (#246) * Update README.md * Add license badge * rebase * rebase onto master * rebase * make lint * remove duplicate test * update changelog * add comment as for stack name rule * make format * rule not invoked for aurora * make templates valid cloud formations (except for aurora one) * make templates valid cloud formations * Update tests/rules/test_StorageEncryptedRule.py Co-authored-by: Ignacio Bolonio * add aurora comment --------- Co-authored-by: Jordi Soucheiron Co-authored-by: Ignacio Bolonio * update changelog --------- Co-authored-by: Jordi Soucheiron Co-authored-by: Ignacio Bolonio --- CHANGELOG.md | 2 +- cfripper/rules/__init__.py | 2 + cfripper/rules/public_elb_checker_rule.py | 41 +++++++++++++ tests/rules/test_PublicELBCheckerRule.py | 58 +++++++++++++++++++ .../private_elb_instance.yml | 32 ++++++++++ .../private_elb_v2_instance.yml | 34 +++++++++++ .../public_facing_elb_instance.yml | 32 ++++++++++ .../public_facing_elb_v2_instance.yml | 34 +++++++++++ 8 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 cfripper/rules/public_elb_checker_rule.py create mode 100644 tests/rules/test_PublicELBCheckerRule.py create mode 100644 tests/test_templates/rules/PublicELBCheckerRule/private_elb_instance.yml create mode 100644 tests/test_templates/rules/PublicELBCheckerRule/private_elb_v2_instance.yml create mode 100644 tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_instance.yml create mode 100644 tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_v2_instance.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e0fd091..f8844012 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. ## [1.15.0] ### Additions -- New rules: `StackNameMatchesRegexRule` and `StorageEncryptedRule` +- New rules: `PublicELBCheckerRule`, `StackNameMatchesRegexRule`, and `StorageEncryptedRule` - New regex: `REGEX_ALPHANUMERICAL_OR_HYPHEN` to check if stack name only consists of alphanumerical characters and hyphens. ## [1.14.0] diff --git a/cfripper/rules/__init__.py b/cfripper/rules/__init__.py index 46e4d5d2..6e0d0894 100644 --- a/cfripper/rules/__init__.py +++ b/cfripper/rules/__init__.py @@ -23,6 +23,7 @@ from cfripper.rules.managed_policy_on_user import ManagedPolicyOnUserRule from cfripper.rules.policy_on_user import PolicyOnUserRule from cfripper.rules.privilege_escalation import PrivilegeEscalationRule +from cfripper.rules.public_elb_checker_rule import PublicELBCheckerRule from cfripper.rules.rds_security_group import RDSSecurityGroupIngressOpenToWorldRule from cfripper.rules.s3_bucket_policy import S3BucketPolicyPrincipalRule from cfripper.rules.s3_lifecycle_configuration import S3LifecycleConfigurationRule @@ -80,6 +81,7 @@ PartialWildcardPrincipalRule, PolicyOnUserRule, PrivilegeEscalationRule, + PublicELBCheckerRule, RDSSecurityGroupIngressOpenToWorldRule, S3BucketPolicyPrincipalRule, S3LifecycleConfigurationRule, diff --git a/cfripper/rules/public_elb_checker_rule.py b/cfripper/rules/public_elb_checker_rule.py new file mode 100644 index 00000000..4f8a159d --- /dev/null +++ b/cfripper/rules/public_elb_checker_rule.py @@ -0,0 +1,41 @@ +from typing import Dict, Optional + +from pycfmodel.model.resources.generic_resource import GenericResource + +from cfripper.model.enums import RuleGranularity, RuleMode, RuleRisk +from cfripper.model.result import Result +from cfripper.rules.base_rules import ResourceSpecificRule + + +class PublicELBCheckerRule(ResourceSpecificRule): + """ + Rule to check if a public facing ELB is being created. + """ + + RESOURCE_TYPES = (GenericResource,) + ELB_RESOURCE_TYPES = ["AWS::ElasticLoadBalancing::LoadBalancer", "AWS::ElasticLoadBalancingV2::LoadBalancer"] + RISK_VALUE = RuleRisk.LOW + RULE_MODE = RuleMode.BLOCKING + REASON = "Creation of public facing ELBs is restricted. LogicalId: {}" + + def resource_invoke(self, resource: GenericResource, logical_id: str, extras: Optional[Dict] = None) -> Result: + result = Result() + if resource.Type in self.ELB_RESOURCE_TYPES: + elb_scheme = getattr(resource.Properties, "Scheme", "internal") + + if elb_scheme == "internet-facing": + self.add_failure_to_result( + result=result, + reason=self.REASON.format(logical_id), + resource_ids={logical_id}, + resource_types={resource.Type}, + context={ + "config": self._config, + "extras": extras, + "logical_id": logical_id, + "resource": resource, + }, + granularity=RuleGranularity.RESOURCE, + ) + + return result diff --git a/tests/rules/test_PublicELBCheckerRule.py b/tests/rules/test_PublicELBCheckerRule.py new file mode 100644 index 00000000..5b195251 --- /dev/null +++ b/tests/rules/test_PublicELBCheckerRule.py @@ -0,0 +1,58 @@ +import pytest + +from cfripper.model.result import Failure +from cfripper.rules.public_elb_checker_rule import PublicELBCheckerRule +from tests.utils import get_cfmodel_from + + +@pytest.mark.parametrize( + "template", + [ + "rules/PublicELBCheckerRule/private_elb_instance.yml", + "rules/PublicELBCheckerRule/private_elb_v2_instance.yml", + ], +) +def test_invoke_private_elbs_passes(template): + rule = PublicELBCheckerRule(None) + rule._config.stack_name = "stackname" + result = rule.invoke(cfmodel=get_cfmodel_from(template).resolve()) + + assert result.valid + assert result.failures == [] + + +@pytest.mark.parametrize( + "template, logical_id, resource_type, reason", + [ + ( + "rules/PublicELBCheckerRule/public_facing_elb_instance.yml", + "PublicLoadBalancer", + "AWS::ElasticLoadBalancing::LoadBalancer", + "Creation of public facing ELBs is restricted. LogicalId: PublicLoadBalancer", + ), + ( + "rules/PublicELBCheckerRule/public_facing_elb_v2_instance.yml", + "PublicV2LoadBalancer", + "AWS::ElasticLoadBalancingV2::LoadBalancer", + "Creation of public facing ELBs is restricted. LogicalId: PublicV2LoadBalancer", + ), + ], +) +def test_invoke_public_elbs_fail(template, logical_id, resource_type, reason): + rule = PublicELBCheckerRule(None) + rule._config.stack_name = "stackname" + result = rule.invoke(cfmodel=get_cfmodel_from(template).resolve()) + + assert result.valid is False + assert result.failures == [ + Failure( + granularity="RESOURCE", + reason=reason, + risk_value="LOW", + rule="PublicELBCheckerRule", + rule_mode="BLOCKING", + actions=None, + resource_ids={logical_id}, + resource_types={resource_type}, + ) + ] diff --git a/tests/test_templates/rules/PublicELBCheckerRule/private_elb_instance.yml b/tests/test_templates/rules/PublicELBCheckerRule/private_elb_instance.yml new file mode 100644 index 00000000..5f8afe07 --- /dev/null +++ b/tests/test_templates/rules/PublicELBCheckerRule/private_elb_instance.yml @@ -0,0 +1,32 @@ +Resources: + PublicLoadBalancer: + Type: 'AWS::ElasticLoadBalancing::LoadBalancer' + Properties: + Name: 'AWS::StackName-extlb' + Scheme: internal + SecurityGroups: + - !GetAtt + - LoadBalancerHttpsSG + - GroupId + Subnets: !If + - ExtLoadBalancer + - - !ImportValue PublicSubnetA + - !ImportValue PublicSubnetB + - !ImportValue PublicSubnetC + - - !ImportValue PrivateSubnetA + - !ImportValue PrivateSubnetB + - !ImportValue PrivateSubnetC + ConnectionSettings: + - IdleTimeout: 3600 + Tags: + - Key: Name + Value: !Join + - '-' + - - !Ref 'AWS::StackName' + - LoadBalancerv2 + - Key: Project + Value: !Ref ProjectName + - Key: Contact + Value: !Ref ContactEmail + - Key: StackName + Value: !Ref 'AWS::StackName' \ No newline at end of file diff --git a/tests/test_templates/rules/PublicELBCheckerRule/private_elb_v2_instance.yml b/tests/test_templates/rules/PublicELBCheckerRule/private_elb_v2_instance.yml new file mode 100644 index 00000000..6c6da07c --- /dev/null +++ b/tests/test_templates/rules/PublicELBCheckerRule/private_elb_v2_instance.yml @@ -0,0 +1,34 @@ +Resources: + PublicV2LoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + Properties: + Name: 'AWS::StackName-extlb' + Scheme: internal + SecurityGroups: + - !GetAtt + - LoadBalancerHttpsSG + - GroupId + Subnets: !If + - ExtLoadBalancer + - - !ImportValue PublicSubnetA + - !ImportValue PublicSubnetB + - !ImportValue PublicSubnetC + - - !ImportValue PrivateSubnetA + - !ImportValue PrivateSubnetB + - !ImportValue PrivateSubnetC + Type: application + LoadBalancerAttributes: + - Key: idle_timeout.timeout_seconds + Value: '3600' + Tags: + - Key: Name + Value: !Join + - '-' + - - !Ref 'AWS::StackName' + - LoadBalancerv2 + - Key: Project + Value: !Ref ProjectName + - Key: Contact + Value: !Ref ContactEmail + - Key: StackName + Value: !Ref 'AWS::StackName' \ No newline at end of file diff --git a/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_instance.yml b/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_instance.yml new file mode 100644 index 00000000..5818b3ee --- /dev/null +++ b/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_instance.yml @@ -0,0 +1,32 @@ +Resources: + PublicLoadBalancer: + Type: 'AWS::ElasticLoadBalancing::LoadBalancer' + Properties: + Name: 'AWS::StackName-extlb' + Scheme: internet-facing + SecurityGroups: + - !GetAtt + - LoadBalancerHttpsSG + - GroupId + Subnets: !If + - ExtLoadBalancer + - - !ImportValue PublicSubnetA + - !ImportValue PublicSubnetB + - !ImportValue PublicSubnetC + - - !ImportValue PrivateSubnetA + - !ImportValue PrivateSubnetB + - !ImportValue PrivateSubnetC + ConnectionSettings: + - IdleTimeout: 3600 + Tags: + - Key: Name + Value: !Join + - '-' + - - !Ref 'AWS::StackName' + - LoadBalancerv2 + - Key: Project + Value: !Ref ProjectName + - Key: Contact + Value: !Ref ContactEmail + - Key: StackName + Value: !Ref 'AWS::StackName' \ No newline at end of file diff --git a/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_v2_instance.yml b/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_v2_instance.yml new file mode 100644 index 00000000..6bef83ac --- /dev/null +++ b/tests/test_templates/rules/PublicELBCheckerRule/public_facing_elb_v2_instance.yml @@ -0,0 +1,34 @@ +Resources: + PublicV2LoadBalancer: + Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' + Properties: + Name: 'AWS::StackName-extlb' + Scheme: internet-facing + SecurityGroups: + - !GetAtt + - LoadBalancerHttpsSG + - GroupId + Subnets: !If + - ExtLoadBalancer + - - !ImportValue PublicSubnetA + - !ImportValue PublicSubnetB + - !ImportValue PublicSubnetC + - - !ImportValue PrivateSubnetA + - !ImportValue PrivateSubnetB + - !ImportValue PrivateSubnetC + Type: application + LoadBalancerAttributes: + - Key: idle_timeout.timeout_seconds + Value: '3600' + Tags: + - Key: Name + Value: !Join + - '-' + - - !Ref 'AWS::StackName' + - LoadBalancerv2 + - Key: Project + Value: !Ref ProjectName + - Key: Contact + Value: !Ref ContactEmail + - Key: StackName + Value: !Ref 'AWS::StackName' \ No newline at end of file From c4ba653c4a8fc0e125f56abbbf4ebba9a43217b7 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 20 Nov 2023 12:57:06 +0100 Subject: [PATCH 07/63] Refactor filter methods (#251) * Improve filter handling code * Update changelog * Bump version, update changelog --- CHANGELOG.md | 1 + cfripper/__version__.py | 2 +- cfripper/config/config.py | 58 +++++++++++++++++++++++---------------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8844012..01a66daa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Additions - New rules: `PublicELBCheckerRule`, `StackNameMatchesRegexRule`, and `StorageEncryptedRule` - New regex: `REGEX_ALPHANUMERICAL_OR_HYPHEN` to check if stack name only consists of alphanumerical characters and hyphens. +- Config has a few extra methods that should make handling Filters easier ## [1.14.0] ### Additions diff --git a/cfripper/__version__.py b/cfripper/__version__.py index ae85267d..ae0e2c35 100644 --- a/cfripper/__version__.py +++ b/cfripper/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 14, 0) +VERSION = (1, 15, 0) __version__ = ".".join(map(str, VERSION)) diff --git a/cfripper/config/config.py b/cfripper/config/config.py index 8bb811fa..61c4fa0c 100644 --- a/cfripper/config/config.py +++ b/cfripper/config/config.py @@ -3,6 +3,7 @@ import logging import sys from collections import defaultdict +from importlib.util import module_from_spec, spec_from_file_location from io import TextIOWrapper from pathlib import Path from typing import DefaultDict, Dict, List @@ -117,6 +118,8 @@ class Config: "directconnect:", "trustedadvisor:", ] + RULES_CONFIG_MODULE_NAME = "__rules_config__" + FILTER_CONFIG_MODULE_NAME = "__filter_config__" def __init__( self, @@ -189,7 +192,7 @@ def load_rules_config_file(self, rules_config_file: TextIOWrapper): try: ext = Path(filename).suffix - module_name = "__rules_config__" + module_name = self.RULES_CONFIG_MODULE_NAME if ext not in [".py", ".pyc"]: raise RuntimeError("Configuration file should have a valid Python extension.") spec = importlib.util.spec_from_file_location(module_name, filename) @@ -205,32 +208,41 @@ def load_rules_config_file(self, rules_config_file: TextIOWrapper): raise def add_filters_from_dir(self, path: str): + self.add_filters(filters=self.get_filters_from_dir(path)) + + @classmethod + def get_filters_from_dir(cls, path: str) -> List[Filter]: + filters = [] + for filename in cls.get_filenames_from_dir(path): + try: + filters.extend(cls.get_filters_from_filename_path(filename)) + except Exception: + logger.exception(f"Failed to read files in path: {path} ({filename})") + raise + return filters + + @classmethod + def get_filenames_from_dir(cls, path: str) -> List[Path]: if not Path(path).is_dir(): raise RuntimeError(f"{path} doesn't exist") - - try: - module_name = "__rules_config__" - filenames = sorted(itertools.chain(Path(path).glob("*.py"), Path(path).glob("*.pyc"))) - for filename in filenames: - spec = importlib.util.spec_from_file_location(module_name, filename.absolute()) - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) - filters = vars(module).get("FILTERS") - if not filters: - continue - # Validate filters format - RulesFiltersMapping(__root__=filters) - self.add_filters(filters=filters) - logger.debug(f"{filename} loaded") - except Exception: - logger.exception(f"Failed to read files in path: {path}") - raise + filenames = sorted(itertools.chain(Path(path).glob("*.py"), Path(path).glob("*.pyc"))) + return filenames + + @classmethod + def get_filters_from_filename_path(cls, filename: Path) -> List[Filter]: + spec = spec_from_file_location(cls.FILTER_CONFIG_MODULE_NAME, filename.absolute()) + module = module_from_spec(spec) + sys.modules[cls.FILTER_CONFIG_MODULE_NAME] = module + spec.loader.exec_module(module) + filters = vars(module).get("FILTERS") or [] + # Validate filters format + RulesFiltersMapping(__root__=filters) + return filters def add_filters(self, filters: List[Filter]): - for filter in filters: - for rule in filter.rules: - self.rules_filters[rule].append(filter) + for rule_filter in filters: + for rule in rule_filter.rules: + self.rules_filters[rule].append(rule_filter) class RulesConfigMapping(BaseModel): From 8be960b2012f98f070942de20ab73b9959912cc9 Mon Sep 17 00:00:00 2001 From: Max-Huneshagen <145039806+Max-Huneshagen@users.noreply.github.com> Date: Tue, 21 Nov 2023 09:55:36 +0100 Subject: [PATCH 08/63] Update __version__.py (#250) Bump the version to 1.15.0 From 8c58ee3901e5b5f601f6be52a903efd01d9b3413 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Tue, 21 Nov 2023 16:05:18 +0100 Subject: [PATCH 09/63] Update .readthedocs.yaml (#255) --- .readthedocs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 69eb36d7..3ffe960f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,8 +5,12 @@ mkdocs: formats: all +build: + os: ubuntu-22.04 + tools: + python: "3.12" + python: - version: 3.7 install: - method: pip path: . From 379c6c8d01ef8cd754302d2ff66c0e6fc3ba8786 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Tue, 21 Nov 2023 16:08:21 +0100 Subject: [PATCH 10/63] Bump actions (#252) --- .github/workflows/lint-and-test.yml | 4 ++-- .github/workflows/pypi-release.yml | 4 ++-- .github/workflows/test-docs.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 8677fe47..2ad775c4 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -14,10 +14,10 @@ jobs: name: Python ${{ matrix.python-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 69ebb89f..986ca3f3 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.7' diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index d139947e..a1213a91 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -9,10 +9,10 @@ jobs: name: Test Docs steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.9 From 4c7da42f34d9ac29fe963023659bfb1beba0f054 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Tue, 21 Nov 2023 16:26:40 +0100 Subject: [PATCH 11/63] Update .readthedocs.yaml (#256) --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 3ffe960f..74790827 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ formats: all build: os: ubuntu-22.04 tools: - python: "3.12" + python: "3.7" python: install: From 8dd5c2c4dc52c2f0a33e713d0e8d3ea0eff913c6 Mon Sep 17 00:00:00 2001 From: Max-Huneshagen <145039806+Max-Huneshagen@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:28:37 +0100 Subject: [PATCH 12/63] Bump version to 1.15.1 (#254) * update changelog * update changelog --- CHANGELOG.md | 4 ++++ cfripper/__version__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a66daa..c48614a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.15.1] +### Fixes +- Fix documentation. + ## [1.15.0] ### Additions - New rules: `PublicELBCheckerRule`, `StackNameMatchesRegexRule`, and `StorageEncryptedRule` diff --git a/cfripper/__version__.py b/cfripper/__version__.py index ae0e2c35..ed46a0fb 100644 --- a/cfripper/__version__.py +++ b/cfripper/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 15, 0) +VERSION = (1, 15, 1) __version__ = ".".join(map(str, VERSION)) From 6ffe59637df3617de55907d95e2f64c55998c09b Mon Sep 17 00:00:00 2001 From: Ramon Date: Thu, 23 Nov 2023 16:09:26 +0100 Subject: [PATCH 13/63] Add Homebrew badge (#258) * add homebrew badge * update html for logo image * revert align --------- Co-authored-by: Ramon --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8658527..19cfc1ac 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@

- +cfripper logo

# CFRipper ![Build Status](https://github.com/Skyscanner/cfripper/workflows/PyPI%20release/badge.svg) [![PyPI version](https://badge.fury.io/py/cfripper.svg)](https://badge.fury.io/py/cfripper) +[![homebrew version](https://img.shields.io/homebrew/v/cfripper)](https://formulae.brew.sh/formula/cfripper) ![License](https://img.shields.io/github/license/skyscanner/cfripper) CFRipper is a Library and CLI security analyzer for AWS CloudFormation templates. You can use CFRipper to prevent deploying insecure AWS resources into your Cloud environment. You can write your own compliance checks by adding new custom plugins. From 5b50aa7801d17123697fa7280b63bce357db6a7a Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 4 Dec 2023 14:22:04 +0100 Subject: [PATCH 14/63] Update stack_name_matches_regex.py (#261) * Update stack_name_matches_regex.py * Update changelog and version --- CHANGELOG.md | 8 ++++++++ cfripper/__version__.py | 2 +- cfripper/rules/stack_name_matches_regex.py | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c48614a7..4508c8e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. ### Fixes - Fix documentation. +## [1.15.2] +### Fixes +- Fixes https://github.com/Skyscanner/cfripper/issues/260 + +## [1.15.1] +### Fixes +- Fix docs generation + ## [1.15.0] ### Additions - New rules: `PublicELBCheckerRule`, `StackNameMatchesRegexRule`, and `StorageEncryptedRule` diff --git a/cfripper/__version__.py b/cfripper/__version__.py index ed46a0fb..1afd7edb 100644 --- a/cfripper/__version__.py +++ b/cfripper/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 15, 1) +VERSION = (1, 15, 2) __version__ = ".".join(map(str, VERSION)) diff --git a/cfripper/rules/stack_name_matches_regex.py b/cfripper/rules/stack_name_matches_regex.py index ca2c8e8f..9307082b 100644 --- a/cfripper/rules/stack_name_matches_regex.py +++ b/cfripper/rules/stack_name_matches_regex.py @@ -28,11 +28,11 @@ def _stack_name_matches_regex(self, stack_name: str) -> bool: def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: result = Result() + if not extras: + extras = {} stack_name = self._config.stack_name or extras.get("stack_name", "") if not stack_name: return result - if not extras: - extras = {} if not self._stack_name_matches_regex(stack_name): self.add_failure_to_result( From da57d86786c019f7ce1803ff20b97576f1f30933 Mon Sep 17 00:00:00 2001 From: Ramon Pinuaga <129771135+rpinuaga-sky@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:02:33 +0100 Subject: [PATCH 15/63] Update invalid_role_inline_policy_fn_if.json (#263) --- .../invalid_role_inline_policy_fn_if.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_templates/rules/IAMRolesOverprivilegedRule/invalid_role_inline_policy_fn_if.json b/tests/test_templates/rules/IAMRolesOverprivilegedRule/invalid_role_inline_policy_fn_if.json index c1e25866..644828c3 100644 --- a/tests/test_templates/rules/IAMRolesOverprivilegedRule/invalid_role_inline_policy_fn_if.json +++ b/tests/test_templates/rules/IAMRolesOverprivilegedRule/invalid_role_inline_policy_fn_if.json @@ -35,7 +35,7 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": "arn:aws:iam::325714046698:role/sandbox-secrets-access" + "Resource": "arn:aws:iam::123456789012:role/test-role" } ], "Version": "2012-10-17" @@ -65,4 +65,4 @@ } } } -} \ No newline at end of file +} From 6a37acafa0117acb92ab458d04dc66ef761a8627 Mon Sep 17 00:00:00 2001 From: Ramon Date: Thu, 28 Dec 2023 13:02:27 +0100 Subject: [PATCH 16/63] remove duplicated section in changelog (#262) Co-authored-by: Ramon --- CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4508c8e8..433e9844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,6 @@ # Changelog All notable changes to this project will be documented in this file. -## [1.15.1] -### Fixes -- Fix documentation. - ## [1.15.2] ### Fixes - Fixes https://github.com/Skyscanner/cfripper/issues/260 From fc89834179279cea00113986b6aefe45f19fd510 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio Date: Tue, 16 Jan 2024 10:48:10 +0100 Subject: [PATCH 17/63] Improve logging for the exception when applying rule filters (#264) * Improve logging * Add data --------- Co-authored-by: Ignacio Bolonio <> --- cfripper/rules/base_rules.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cfripper/rules/base_rules.py b/cfripper/rules/base_rules.py index 2c23f065..48de5148 100644 --- a/cfripper/rules/base_rules.py +++ b/cfripper/rules/base_rules.py @@ -66,7 +66,12 @@ def add_failure_to_result( if self._config.metrics_logger: self._config.metrics_logger(rule=self.__class__.__name__, filter_reason=rule_filter.reason) except Exception: - logger.exception(f"Exception raised while evaluating filter for `{rule_filter.reason}`", extra=context) + logger.exception( + f"Exception raised while evaluating rule {self.__class__.__name__} " + f"with filter for `{rule_filter.reason}`. " + f"Stack: {self._config.stack_name} Account: {self._config.aws_account_id}", + extra=context, + ) if rule_mode != RuleMode.ALLOWED: result.add_failure( From 30a93f06a8fc2c5ad79e7f604a096e8b75d19ce9 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 16 Jan 2024 11:06:51 +0100 Subject: [PATCH 18/63] Add release drafter template --- .github/workflows/release-drafter.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000..fb3da367 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,17 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch +template: | + ## Changes \ No newline at end of file From 6f30b6942ad6bf55575f0bf4574923ee08efe71a Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 16 Jan 2024 11:10:05 +0100 Subject: [PATCH 19/63] Move template --- .github/{workflows => }/release-drafter.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => }/release-drafter.yml (100%) diff --git a/.github/workflows/release-drafter.yml b/.github/release-drafter.yml similarity index 100% rename from .github/workflows/release-drafter.yml rename to .github/release-drafter.yml From d78a46ec6d7763e4767aa2e0647bceddd8378cbf Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio Date: Tue, 16 Jan 2024 11:51:48 +0100 Subject: [PATCH 20/63] Add release drafter template (#265) * Add release drafter template * Move template --------- Co-authored-by: Ignacio Bolonio <> --- .github/release-drafter.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..fb3da367 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,17 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch +template: | + ## Changes \ No newline at end of file From 5596ec8f9f32e21d56fd9317bbab19874c1429f9 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 16 Jan 2024 11:52:53 +0100 Subject: [PATCH 21/63] Add release drafter workflow --- .github/workflows/release-drafter.yml | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000..56eaca4b --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,32 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - master + # pull_request event is required only for autolabeler + pull_request: + # Only following types are handled by the action, but one can default to all as well + types: [opened, reopened, synchronize] + # pull_request_target event is required for autolabeler to support PRs from forks + pull_request_target: + types: [opened, reopened, synchronize] + +permissions: + contents: read + +jobs: + update_release_draft: + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 9f2f78f5ffc9475d27755b8fd8931f729fca8e50 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 16 Jan 2024 12:15:54 +0100 Subject: [PATCH 22/63] HOTFIX Update version file --- cfripper/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfripper/__version__.py b/cfripper/__version__.py index 1afd7edb..df6a2f7f 100644 --- a/cfripper/__version__.py +++ b/cfripper/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 15, 2) +VERSION = (1, 15, 3) __version__ = ".".join(map(str, VERSION)) From 9f73c76b92d27e72e00366cc4b6dd0f52a09f999 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 16 Jan 2024 12:17:30 +0100 Subject: [PATCH 23/63] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 433e9844..11e63309 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.15.3] +## Changes +- Update invalid_role_inline_policy_fn_if.json +- Improve logging for the exception when applying rule filters +- Add release drafter + ## [1.15.2] ### Fixes - Fixes https://github.com/Skyscanner/cfripper/issues/260 From e92938c3082af9bdebaca062fd1bff97584c9360 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Mon, 12 Feb 2024 12:48:35 +0100 Subject: [PATCH 24/63] Bump pycfmodel and fix rule --- cfripper/__version__.py | 2 +- cfripper/rules/kms_key_wildcard_principal.py | 45 ++++++------ requirements.txt | 2 +- setup.py | 2 +- tests/rules/test_CrossAccountTrustRule.py | 8 +++ tests/rules/test_KMSKeyWildcardPrincipal.py | 71 +++++++++++++------ tests/rules/test_WildcardResourceRule.py | 46 +++++++++++- .../kms_key_without_policy.yml | 9 +++ .../kms_key_with_wildcard_resource.json | 2 +- .../kms_key_without_policy.yml | 9 +++ 10 files changed, 147 insertions(+), 49 deletions(-) create mode 100644 tests/test_templates/rules/CrossAccountTrustRule/kms_key_without_policy.yml rename tests/test_templates/rules/{WildcardResourceRule => KMSKeyWildcardPrincipalRule}/kms_key_with_wildcard_resource.json (96%) create mode 100644 tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_without_policy.yml diff --git a/cfripper/__version__.py b/cfripper/__version__.py index df6a2f7f..ba2922a6 100644 --- a/cfripper/__version__.py +++ b/cfripper/__version__.py @@ -1,3 +1,3 @@ -VERSION = (1, 15, 3) +VERSION = (1, 15, 4) __version__ = ".".join(map(str, VERSION)) diff --git a/cfripper/rules/kms_key_wildcard_principal.py b/cfripper/rules/kms_key_wildcard_principal.py index 3934cadf..4f7cc2f9 100644 --- a/cfripper/rules/kms_key_wildcard_principal.py +++ b/cfripper/rules/kms_key_wildcard_principal.py @@ -37,26 +37,27 @@ def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: result = Result() for logical_id, resource in cfmodel.Resources.items(): if isinstance(resource, KMSKey): - for statement in resource.Properties.KeyPolicy._statement_as_list(): - filtered_principals = statement.principals_with(self.CONTAINS_WILDCARD_PATTERN) - if statement.Effect == "Allow" and filtered_principals: - for principal in filtered_principals: - if statement.Condition and statement.Condition.dict(): - # Ignoring condition checks since they will get reviewed in other - # rules and future improvements - pass - else: - self.add_failure_to_result( - result, - self.REASON.format(logical_id), - resource_ids={logical_id}, - context={ - "config": self._config, - "extras": extras, - "logical_id": logical_id, - "resource": resource, - "statement": statement, - "principal": principal, - }, - ) + if resource.Properties.KeyPolicy: + for statement in resource.Properties.KeyPolicy._statement_as_list(): + filtered_principals = statement.principals_with(self.CONTAINS_WILDCARD_PATTERN) + if statement.Effect == "Allow" and filtered_principals: + for principal in filtered_principals: + if statement.Condition and statement.Condition.dict(): + # Ignoring condition checks since they will get reviewed in other + # rules and future improvements + pass + else: + self.add_failure_to_result( + result, + self.REASON.format(logical_id), + resource_ids={logical_id}, + context={ + "config": self._config, + "extras": extras, + "logical_id": logical_id, + "resource": resource, + "statement": statement, + "principal": principal, + }, + ) return result diff --git a/requirements.txt b/requirements.txt index fa70e777..5639dc25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ cfn-flip==1.3.0 click==8.1.2 jmespath==1.0.0 pluggy==0.13.1 -pycfmodel==0.20.0 +pycfmodel==0.22.0 pydantic==1.9.0 pydash==6.0.0 python-dateutil==2.8.2 diff --git a/setup.py b/setup.py index cf2c6a66..aa613d04 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ "cfn_flip>=1.2.0", "click>=8.0.0", "pluggy~=0.13.1", - "pycfmodel>=0.20.0", + "pycfmodel>=0.22.0", "pydash>=4.7.6", "PyYAML>=4.2b1", ] diff --git a/tests/rules/test_CrossAccountTrustRule.py b/tests/rules/test_CrossAccountTrustRule.py index a34fee61..bb7bb890 100644 --- a/tests/rules/test_CrossAccountTrustRule.py +++ b/tests/rules/test_CrossAccountTrustRule.py @@ -301,6 +301,14 @@ def test_kms_key_cross_account_sts(template, is_valid, failures): assert compare_lists_of_failures(result.failures, failures) +def test_kms_key__without_policy(): + rule = KMSKeyCrossAccountTrustRule(Config(aws_account_id="123456789", aws_principals=["999999999"])) + model = get_cfmodel_from("rules/CrossAccountTrustRule/kms_key_without_policy.yml") + result = rule.invoke(model) + assert result.valid + assert compare_lists_of_failures(result.failures, []) + + @pytest.mark.parametrize( "principal", [ diff --git a/tests/rules/test_KMSKeyWildcardPrincipal.py b/tests/rules/test_KMSKeyWildcardPrincipal.py index 72f81953..34d30cfa 100644 --- a/tests/rules/test_KMSKeyWildcardPrincipal.py +++ b/tests/rules/test_KMSKeyWildcardPrincipal.py @@ -1,22 +1,49 @@ -# import pytest -# -# from cfripper.rules.KMSKeyWildcardPrincipal import KMSKeyWildcardPrincipal -# from cfripper.model.result import Result -# from tests.utils import get_cfmodel_from - -# TODO Implement check if this is needed as GenericWildcardPrincipal rule seems to include this one -# @pytest.fixture() -# def abcdef(): -# return get_cfmodel_from("rules/KMSKeyWildcardPrincipal/abcdef.json").resolve() -# -# -# def test_abcdef(abcdef): -# result = Result() -# rule = KMSKeyWildcardPrincipal(None, result) -# rule.invoke(abcdef) -# -# assert not result.valid -# assert len(result.failed_rules) == 1 -# assert len(result.failed_monitored_rules) == 0 -# assert result.failed_rules[0].rule == "KMSKeyWildcardPrincipal" -# assert result.failed_rules[0].reason == "KMS Key policy {} should not allow wildcard principals" +import pytest + +from cfripper.model.result import Failure +from cfripper.rules import KMSKeyWildcardPrincipalRule +from tests.utils import compare_lists_of_failures, get_cfmodel_from + + +@pytest.fixture() +def kms_key_with_wildcard_policy(): + return get_cfmodel_from("rules/KMSKeyWildcardPrincipalRule/kms_key_with_wildcard_resource.json").resolve() + + +@pytest.fixture() +def kms_key_without_policy(): + return get_cfmodel_from("rules/KMSKeyWildcardPrincipalRule/kms_key_without_policy.yml").resolve() + + +def test_kms_key_with_wildcard_resource_not_allowed_is_flagged(kms_key_with_wildcard_policy): + rule = KMSKeyWildcardPrincipalRule(None) + rule._config.stack_name = "stack3" + rule.all_cf_actions = set() + result = rule.invoke(kms_key_with_wildcard_policy) + + assert result.valid is False + assert compare_lists_of_failures( + result.failures, + [ + Failure( + granularity="RESOURCE", + reason="KMS Key policy myKey should not allow wildcard principals", + risk_value="MEDIUM", + rule="KMSKeyWildcardPrincipalRule", + rule_mode="BLOCKING", + actions=None, + resource_ids={"myKey"}, + resource_types=None, + ) + ], + ) + + +def test_kms_key_without_policy_is_not_flagged(kms_key_without_policy): + rule = KMSKeyWildcardPrincipalRule(None) + rule._config.stack_name = "stack3" + rule.all_cf_actions = set() + result = rule.invoke(kms_key_without_policy) + + assert result.valid + assert compare_lists_of_failures(result.failures, []) diff --git a/tests/rules/test_WildcardResourceRule.py b/tests/rules/test_WildcardResourceRule.py index 14541df0..21c3fc42 100644 --- a/tests/rules/test_WildcardResourceRule.py +++ b/tests/rules/test_WildcardResourceRule.py @@ -17,7 +17,7 @@ def user_with_wildcard_resource(): @pytest.fixture() def kms_key_with_wildcard_policy(): - return get_cfmodel_from("rules/WildcardResourceRule/kms_key_with_wildcard_resource.json").resolve() + return get_cfmodel_from("rules/KMSKeyWildcardPrincipalRule/kms_key_with_wildcard_resource.json").resolve() @pytest.fixture() @@ -434,6 +434,28 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy resource_ids={"RolePolicy"}, resource_types={"AWS::IAM::Policy"}, ), + Failure( + granularity="ACTION", + reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:GetResourcePolicy"', + risk_value="MEDIUM", + rule="WildcardResourceRule", + rule_mode="BLOCKING", + actions={ + "dynamodb:CreateTable", + "dynamodb:BatchGet*", + "dynamodb:Scan", + "dynamodb:Update*", + "dynamodb:Query", + "dynamodb:Delete*", + "dynamodb:PutItem", + "dynamodb:DescribeStream", + "dynamodb:DescribeTable", + "dynamodb:BatchWrite*", + "dynamodb:Get*", + }, + resource_ids={"RolePolicy"}, + resource_types={"AWS::IAM::Policy"}, + ), Failure( granularity="ACTION", reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:GetShardIterator"', @@ -610,6 +632,28 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy resource_ids={"RolePolicy"}, resource_types={"AWS::IAM::Policy"}, ), + Failure( + granularity="ACTION", + reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:UpdateGlobalTableVersion"', + risk_value="MEDIUM", + rule="WildcardResourceRule", + rule_mode="BLOCKING", + actions={ + "dynamodb:CreateTable", + "dynamodb:BatchGet*", + "dynamodb:Scan", + "dynamodb:Update*", + "dynamodb:Query", + "dynamodb:Delete*", + "dynamodb:PutItem", + "dynamodb:DescribeStream", + "dynamodb:DescribeTable", + "dynamodb:BatchWrite*", + "dynamodb:Get*", + }, + resource_ids={"RolePolicy"}, + resource_types={"AWS::IAM::Policy"}, + ), Failure( granularity="ACTION", reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:UpdateItem"', diff --git a/tests/test_templates/rules/CrossAccountTrustRule/kms_key_without_policy.yml b/tests/test_templates/rules/CrossAccountTrustRule/kms_key_without_policy.yml new file mode 100644 index 00000000..b3400c53 --- /dev/null +++ b/tests/test_templates/rules/CrossAccountTrustRule/kms_key_without_policy.yml @@ -0,0 +1,9 @@ +--- +AWSTemplateFormatVersion: "2010-09-09" + +Resources: + MyKey: + Type: "AWS::KMS::Key" + Properties: + EnableKeyRotation: true + Enabled: true diff --git a/tests/test_templates/rules/WildcardResourceRule/kms_key_with_wildcard_resource.json b/tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_with_wildcard_resource.json similarity index 96% rename from tests/test_templates/rules/WildcardResourceRule/kms_key_with_wildcard_resource.json rename to tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_with_wildcard_resource.json index 45d5691a..1599b66b 100644 --- a/tests/test_templates/rules/WildcardResourceRule/kms_key_with_wildcard_resource.json +++ b/tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_with_wildcard_resource.json @@ -12,7 +12,7 @@ "Sid": "Enable IAM User Permissions", "Effect": "Allow", "Principal": { - "AWS": "arn:aws:iam::111122223333:root" + "AWS": "*" }, "Action": "kms:*", "Resource": "*" diff --git a/tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_without_policy.yml b/tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_without_policy.yml new file mode 100644 index 00000000..b3400c53 --- /dev/null +++ b/tests/test_templates/rules/KMSKeyWildcardPrincipalRule/kms_key_without_policy.yml @@ -0,0 +1,9 @@ +--- +AWSTemplateFormatVersion: "2010-09-09" + +Resources: + MyKey: + Type: "AWS::KMS::Key" + Properties: + EnableKeyRotation: true + Enabled: true From 1bd1de51ef365962bdd882c6b262ac829b62c934 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Mon, 12 Feb 2024 12:50:38 +0100 Subject: [PATCH 25/63] Fix release drafter template --- .github/release-drafter.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index fb3da367..1318f25c 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -14,4 +14,6 @@ version-resolver: - 'patch' default: patch template: | - ## Changes \ No newline at end of file + ## Changes + + $CHANGES \ No newline at end of file From 54e901114669917050273ce3997485b157da8c7d Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 13 Feb 2024 09:55:18 +0100 Subject: [PATCH 26/63] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e63309..53477741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.15.4] +## Fixes +- Fix `KMSKeyWildcardPrincipalRule` to work without a KMS policy +- Fix release drafter template to show PR titles +### Updates +- Bumped minimum `pycfmodel` version to `0.22.0` + ## [1.15.3] ## Changes - Update invalid_role_inline_policy_fn_if.json From 2eb117943faf590a4e65a90d0206cddeaeb2bba8 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 21:43:14 +0100 Subject: [PATCH 27/63] Testing pyproject setup --- .github/workflows/pypi-release.yml | 28 +++--- Makefile | 34 +++++-- cfripper/__version__.py | 3 - cfripper/rules/storage_encrypted_rule.py | 1 - pyproject.toml | 115 +++++++++++++++++++++++ requirements-dev.txt | 89 ++++++++++++++++++ requirements-docs.txt | 107 +++++++++++++++++++++ requirements.txt | 26 +++-- setup.py | 75 --------------- tests/test_boto3_client.py | 10 +- 10 files changed, 364 insertions(+), 124 deletions(-) delete mode 100644 cfripper/__version__.py create mode 100644 requirements-dev.txt create mode 100644 requirements-docs.txt delete mode 100644 setup.py diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 986ca3f3..eafb511f 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -5,33 +5,31 @@ on: types: [published] jobs: - build: + pypi-publish: + name: Upload release to PyPI runs-on: ubuntu-latest - + environment: + name: pypi + url: https://pypi.org/p/cfripper + permissions: + id-token: write steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - name: Setup python uses: actions/setup-python@v4 with: python-version: '3.7' - - run: pip install setuptools wheel - - - run: make install + - name: Install dependencies + run: | + python -m pip install -U pip + python -m pip install -U twine build - name: Build a binary wheel run: python setup.py sdist bdist_wheel -# This doesn't add any value. It mostly passes, and if a release fails in the non-test PyPi -# this step then needs to be skipped. -# Leaving it commented until we find a cause to keep it that adds value to the project. -# - name: Publish distribution 📦 to Test PyPI -# uses: pypa/gh-action-pypi-publish@master -# with: -# password: ${{ secrets.test_pypi_password }} -# repository_url: https://test.pypi.org/legacy/ - - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/Makefile b/Makefile index fdd84caf..69735178 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,13 @@ SOURCE_FILES = setup.py SOURCE_ALL = $(SOURCE_DIRS) $(SOURCE_FILES) install: - pip install -r requirements.txt + uv pip install -r requirements.txt install-dev: install - pip install -e ".[dev]" + uv pip install -r requirements.txt -r requirements-dev.txt install-docs: - pip install -e ".[dev,docs]" + uv pip install -r requirements.txt -r requirements-docs.txt format: isort --recursive $(SOURCE_ALL) @@ -40,10 +40,24 @@ test: lint unit test-docs: mkdocs build --strict -freeze: - CUSTOM_COMPILE_COMMAND="make freeze" pip-compile --no-emit-index-url --no-annotate --output-file requirements.txt setup.py - -freeze-upgrade: - CUSTOM_COMPILE_COMMAND="make freeze" pip-compile --no-emit-index-url --upgrade --no-annotate --output-file requirements.txt setup.py - -.PHONY: install install-dev install-docs format lint isort-lint black-lint flake8-lint unit coverage test freeze freeze-upgrade +FREEZE_COMMAND = CUSTOM_COMPILE_COMMAND="make freeze" uv pip compile +FREEZE_OPTIONS = --no-emit-index-url --no-annotate -v +freeze-base: pyproject.toml + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --output-file requirements.txt +freeze-dev: pyproject.toml + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --extra dev --output-file requirements-dev.txt +freeze-docs: pyproject.toml + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --extra dev --extra docs --output-file requirements-docs.txt +freeze: freeze-base freeze-dev freeze-docs + +freeze-upgrade-base: + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --upgrade --output-file requirements.txt +freeze-upgrade-dev: + $(FREEZE_COMMAND) pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt +freeze-upgrade-docs: + $(FREEZE_COMMAND) pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt +freeze-upgrade: freeze-upgrade-base freeze-upgrade-dev freeze-upgrade-docs + + +.PHONY: install install-dev install-docs format lint isort-lint black-lint flake8-lint unit coverage test freeze freeze-upgrade\ + freeze-base freeze-dev freeze-docs freeze-upgrade-base freeze-upgrade-dev freeze-upgrade-docs diff --git a/cfripper/__version__.py b/cfripper/__version__.py deleted file mode 100644 index ba2922a6..00000000 --- a/cfripper/__version__.py +++ /dev/null @@ -1,3 +0,0 @@ -VERSION = (1, 15, 4) - -__version__ = ".".join(map(str, VERSION)) diff --git a/cfripper/rules/storage_encrypted_rule.py b/cfripper/rules/storage_encrypted_rule.py index 6864f191..814daebf 100644 --- a/cfripper/rules/storage_encrypted_rule.py +++ b/cfripper/rules/storage_encrypted_rule.py @@ -29,7 +29,6 @@ def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result: "aurora" ) # not applicable for aurora since the encryption for DB instances is managed by the DB cluster ): - self.add_failure_to_result( result, self.REASON.format(db_name), diff --git a/pyproject.toml b/pyproject.toml index b937b719..8ec6c010 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,62 @@ +[build-system] +requires = ["setuptools>=64", "setuptools_scm>=8"] +build-backend = "setuptools.build_meta" + +[project] +name = "cfripper" +description="Library and CLI tool for analysing CloudFormation templates and check them for security compliance." +readme = "README.md" +requires-python = ">=3.7.0" +dynamic = ["version"] +license = { text = "Apache-2.0" } +authors = [ + { name = "Skyscanner Security", email = "security@skyscanner.net" } +] +keywords = [ + "security", + "cloudformation", + "aws", + "cli" +] + +classifiers = [ + "Framework :: Django", + "Programming Language :: Python :: 3", +] + +dependencies = [ + "boto3>=1.4.7,<2", + "cfn_flip>=1.2.0", + "click>=8.0.0", + "pluggy~=0.13.1", + "pycfmodel>=0.22.0", + "pydash>=4.7.6", + "PyYAML>=4.2b1" +] + +[project.urls] +documentation = "https://cfripper.readthedocs.io/" +repository = "https://github.com/Skyscanner/cfripper" + +[project.scripts] +cfripper = "cfripper.cli:cli" + +[project.optional-dependencies] +dev = [ + "moto[all]>=5", + "pytest-cov>=2.5.1", + "pytest>=3.6", + "ruff", + "uv", +] +docs = [ + "mkdocs==1.3.0", + "mkdocs-macros-plugin==0.7.0", + "mkdocs-material==8.2.8", + "mkdocs-material-extensions==1.0.3", + "mkdocs-minify-plugin==0.5.0", +] + [tool.black] line-length = 120 exclude = ''' @@ -6,3 +65,59 @@ exclude = ''' | venv )/ ''' + +[tool.isort] +multi_line_output = 3 +include_trailing_comma = true +force_grid_wrap = 0 +combine_as_imports = true +line_length = 120 +skip = [".eggs", ".venv", "venv", "build", "site"] + +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".eggs", + ".git", + ".git-rewrite", + ".pyenv", + ".pytest_cache", + ".ruff_cache", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "build", + "dist", + "node_modules", + "site", + "site-packages", + "venv", +] +line-length = 120 +indent-width = 4 + +# Assume Python 3.7 +target-version = "py37" + +[tool.pytest.ini_options] +asyncio_mode = "auto" +log_cli = true +log_level = "INFO" + +[tool.coverage.report] +show_missing = true +skip_covered = true + +[tool.coverage.run] +branch = true +source = ["cfripper"] + +[tool.setuptools] +include-package-data = false + +[tool.setuptools.packages.find] +# needed only because we did not adopt src layout yet +include = ["cfripper*"] + +[tool.setuptools_scm] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..4074b896 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,89 @@ +# This file was autogenerated by uv v0.1.2 via the following command: +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --output-file requirements-dev.txt +attrs==23.2.0 +aws-sam-translator==1.85.0 +aws-xray-sdk==2.12.1 +black==22.3.0 +boto3==1.34.43 +botocore==1.34.43 +build==1.0.3 +certifi==2024.2.2 +cffi==1.16.0 +cfn-flip==1.3.0 +cfn-lint==0.85.1 +charset-normalizer==3.3.2 +click==8.1.7 +coverage==7.4.1 +cryptography==42.0.3 +docker==7.0.0 +ecdsa==0.18.0 +flake8==7.0.0 +graphql-core==3.2.3 +idna==3.6 +iniconfig==2.0.0 +isort==4.3.21 +jinja2==3.1.3 +jmespath==1.0.1 +jschema-to-python==1.2.3 +jsondiff==2.0.0 +jsonpatch==1.33 +jsonpickle==3.0.2 +jsonpointer==2.4 +jsonschema==4.21.1 +jsonschema-path==0.3.2 +jsonschema-specifications==2023.12.1 +junit-xml==1.9 +lazy-object-proxy==1.10.0 +markupsafe==2.1.5 +mccabe==0.7.0 +moto==5.0.1 +mpmath==1.3.0 +multipart==0.2.4 +mypy-extensions==1.0.0 +networkx==3.2.1 +openapi-schema-validator==0.6.2 +openapi-spec-validator==0.7.1 +packaging==23.2 +pathable==0.4.3 +pathspec==0.12.1 +pbr==6.0.0 +pip==24.0 +pip-tools==7.3.0 +platformdirs==4.2.0 +pluggy==0.13.1 +py-partiql-parser==0.5.1 +pyasn1==0.5.1 +pycfmodel==0.22.0 +pycodestyle==2.11.1 +pycparser==2.21 +pydantic==1.10.14 +pydash==7.0.7 +pyflakes==3.2.0 +pyparsing==3.1.1 +pyproject-hooks==1.0.0 +pytest==7.4.4 +pytest-cov==4.1.0 +python-dateutil==2.8.2 +python-jose==3.3.0 +pyyaml==6.0.1 +referencing==0.31.1 +regex==2023.12.25 +requests==2.31.0 +responses==0.25.0 +rfc3339-validator==0.1.4 +rpds-py==0.18.0 +rsa==4.9 +ruff==0.2.1 +s3transfer==0.10.0 +sarif-om==1.0.4 +setuptools==69.1.0 +six==1.16.0 +sshpubkeys==3.3.1 +sympy==1.12 +typing-extensions==4.9.0 +urllib3==2.0.7 +uv==0.1.2 +werkzeug==3.0.1 +wheel==0.42.0 +wrapt==1.16.0 +xmltodict==0.13.0 diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 00000000..3e1e3081 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,107 @@ +# This file was autogenerated by uv v0.1.2 via the following command: +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --extra docs --output-file requirements-docs.txt +attrs==23.2.0 +aws-sam-translator==1.85.0 +aws-xray-sdk==2.12.1 +black==22.3.0 +boto3==1.34.43 +botocore==1.34.43 +build==1.0.3 +certifi==2024.2.2 +cffi==1.16.0 +cfn-flip==1.3.0 +cfn-lint==0.85.1 +charset-normalizer==3.3.2 +click==8.1.7 +coverage==7.4.1 +cryptography==42.0.3 +csscompressor==0.9.5 +docker==7.0.0 +ecdsa==0.18.0 +flake8==7.0.0 +ghp-import==2.1.0 +graphql-core==3.2.3 +htmlmin==0.1.12 +idna==3.6 +importlib-metadata==7.0.1 +iniconfig==2.0.0 +isort==4.3.21 +jinja2==3.1.3 +jmespath==1.0.1 +jschema-to-python==1.2.3 +jsmin==3.0.1 +jsondiff==2.0.0 +jsonpatch==1.33 +jsonpickle==3.0.2 +jsonpointer==2.4 +jsonschema==4.21.1 +jsonschema-path==0.3.2 +jsonschema-specifications==2023.12.1 +junit-xml==1.9 +lazy-object-proxy==1.10.0 +markdown==3.5.2 +markupsafe==2.1.5 +mccabe==0.7.0 +mergedeep==1.3.4 +mkdocs==1.3.0 +mkdocs-macros-plugin==0.7.0 +mkdocs-material==8.2.8 +mkdocs-material-extensions==1.0.3 +mkdocs-minify-plugin==0.5.0 +moto==5.0.1 +mpmath==1.3.0 +multipart==0.2.4 +mypy-extensions==1.0.0 +networkx==3.2.1 +openapi-schema-validator==0.6.2 +openapi-spec-validator==0.7.1 +packaging==23.2 +pathable==0.4.3 +pathspec==0.12.1 +pbr==6.0.0 +pip==24.0 +pip-tools==7.3.0 +platformdirs==4.2.0 +pluggy==0.13.1 +py-partiql-parser==0.5.1 +pyasn1==0.5.1 +pycfmodel==0.22.0 +pycodestyle==2.11.1 +pycparser==2.21 +pydantic==1.10.14 +pydash==7.0.7 +pyflakes==3.2.0 +pygments==2.17.2 +pymdown-extensions==10.7 +pyparsing==3.1.1 +pyproject-hooks==1.0.0 +pytest==7.4.4 +pytest-cov==4.1.0 +python-dateutil==2.8.2 +python-jose==3.3.0 +pyyaml==6.0.1 +pyyaml-env-tag==0.1 +referencing==0.31.1 +regex==2023.12.25 +requests==2.31.0 +responses==0.25.0 +rfc3339-validator==0.1.4 +rpds-py==0.18.0 +rsa==4.9 +ruff==0.2.1 +s3transfer==0.10.0 +sarif-om==1.0.4 +setuptools==69.1.0 +six==1.16.0 +sshpubkeys==3.3.1 +sympy==1.12 +termcolor==2.4.0 +typing-extensions==4.9.0 +urllib3==2.0.7 +uv==0.1.2 +watchdog==4.0.0 +werkzeug==3.0.1 +wheel==0.42.0 +wrapt==1.16.0 +xmltodict==0.13.0 +zipp==3.17.0 diff --git a/requirements.txt b/requirements.txt index 5639dc25..a30fdfd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,17 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# make freeze -# -boto3==1.21.31 -botocore==1.24.31 +# This file was autogenerated by uv v0.1.2 via the following command: +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --output-file requirements.txt +boto3==1.34.43 +botocore==1.34.43 cfn-flip==1.3.0 -click==8.1.2 -jmespath==1.0.0 +click==8.1.7 +jmespath==1.0.1 pluggy==0.13.1 pycfmodel==0.22.0 -pydantic==1.9.0 -pydash==6.0.0 +pydantic==1.10.14 +pydash==7.0.7 python-dateutil==2.8.2 pyyaml==6.0.1 -s3transfer==0.5.2 +s3transfer==0.10.0 six==1.16.0 -typing-extensions==4.1.1 -urllib3==1.26.18 +typing-extensions==4.9.0 +urllib3==2.0.7 diff --git a/setup.py b/setup.py deleted file mode 100644 index aa613d04..00000000 --- a/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -from pathlib import Path - -from setuptools import find_packages, setup - -from cfripper.__version__ import __version__ - -project_root_path = Path(__file__).parent - -install_requires = [ - "boto3>=1.4.7,<2", - "cfn_flip>=1.2.0", - "click>=8.0.0", - "pluggy~=0.13.1", - "pycfmodel>=0.22.0", - "pydash>=4.7.6", - "PyYAML>=4.2b1", -] - -dev_requires = [ - "black==22.3.0", - "flake8>=3.3.0", - "isort==4.3.21", - "pytest>=3.6", - "pytest-cov>=2.5.1", - "pip-tools>=5.3.1", - "moto[cloudformation,s3]==3.1.9", # coverage fails for 3.1.10, issue is https://github.com/spulec/moto/issues/5162 -] - -docs_requires = [ - "click==8.1.2", - "csscompressor==0.9.5", - "ghp-import==2.0.2", - "htmlmin==0.1.12", - "importlib-metadata==4.11.3", - "Jinja2==3.1.1", - "jsmin==3.0.1", - "Markdown==3.3.6", - "MarkupSafe==2.1.1", - "mergedeep==1.3.4", - "mkdocs==1.3.0", - "mkdocs-exclude==1.0.2", - "mkdocs-macros-plugin==0.7.0", - "mkdocs-material==8.2.8", - "mkdocs-material-extensions==1.0.3", - "mkdocs-minify-plugin==0.5.0", - "packaging==21.3", - "Pygments==2.11.2", - "pymdown-extensions==9.3", - "pyparsing==3.0.7", - "python-dateutil==2.8.2", - "PyYAML==6.0", - "pyyaml_env_tag==0.1", - "six==1.16.0", - "termcolor==1.1.0", - "watchdog==2.1.7", - "zipp==3.8.0", -] - -setup( - name="cfripper", - version=__version__, - author="Skyscanner Product Security", - author_email="security@skyscanner.net", - entry_points={"console_scripts": ["cfripper=cfripper.cli:cli"]}, - long_description=(project_root_path / "README.md").read_text(), - long_description_content_type="text/markdown", - url="https://github.com/Skyscanner/cfripper", - description="Library and CLI tool for analysing CloudFormation templates and check them for security compliance.", - packages=find_packages(exclude=("docs", "tests")), - platforms="any", - python_requires=">=3.7", - install_requires=install_requires, - tests_require=dev_requires, - extras_require={"dev": dev_requires, "docs": docs_requires}, -) diff --git a/tests/test_boto3_client.py b/tests/test_boto3_client.py index 2f1c0d2d..639f4df7 100644 --- a/tests/test_boto3_client.py +++ b/tests/test_boto3_client.py @@ -4,7 +4,7 @@ import boto3 import pytest from botocore.exceptions import ClientError -from moto import mock_cloudformation, mock_s3, mock_sts +from moto import mock_aws from cfripper.boto3_client import Boto3Client from cfripper.model.utils import InvalidURLException, convert_json_or_yaml_to_dict @@ -19,7 +19,7 @@ @pytest.fixture def s3_bucket(default_aws_region): - with mock_s3(): + with mock_aws(): boto3.client("s3").create_bucket( Bucket=TEST_BUCKET_NAME, CreateBucketConfiguration={"LocationConstraint": default_aws_region} ) @@ -28,7 +28,7 @@ def s3_bucket(default_aws_region): @pytest.fixture def boto3_client(default_aws_region): - with mock_sts(): + with mock_aws(): yield Boto3Client("123456789", default_aws_region, "stack-id") @@ -301,7 +301,7 @@ def test_get_exports( assert patched_exceptions.mock_calls == mocked_exceptions -@mock_cloudformation +@mock_aws def test_export_values(boto3_client: Boto3Client): cf_client = boto3_client.session.client("cloudformation", "eu-west-1") cf_client.create_stack( @@ -324,4 +324,4 @@ def test_export_values(boto3_client: Boto3Client): # actual suffix changes between tests export_values = boto3_client.get_exports() assert len(export_values) == 1 - assert "arn:aws:sqs:eu-west-1:123456789012:Test-Stack-MyQueue-" in export_values["MainQueue"] + assert "arn:aws:sqs:eu-west-1:123456789:Test-Stack-MyQueue-" in export_values["MainQueue"] From 695ed164b6d7cac8f129ea3e2117f018df2472b9 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 21:45:49 +0100 Subject: [PATCH 28/63] Add uv --- .github/workflows/lint-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 2ad775c4..40611e25 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -21,6 +21,8 @@ jobs: with: python-version: ${{ matrix.python-version }} + - run: python -m pip install uv + - run: make install-dev - run: make lint From 1e370007dccf71a5abcb45602dac2e618adb90f6 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 21:47:13 +0100 Subject: [PATCH 29/63] Drop python 3.7 support --- .github/workflows/lint-and-test.yml | 2 +- pyproject.toml | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 40611e25..82d8cac4 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] name: Python ${{ matrix.python-version }} diff --git a/pyproject.toml b/pyproject.toml index 8ec6c010..6a37b177 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "cfripper" description="Library and CLI tool for analysing CloudFormation templates and check them for security compliance." readme = "README.md" -requires-python = ">=3.7.0" +requires-python = ">=3.8.0" dynamic = ["version"] license = { text = "Apache-2.0" } authors = [ @@ -96,9 +96,7 @@ exclude = [ ] line-length = 120 indent-width = 4 - -# Assume Python 3.7 -target-version = "py37" +target-version = "py38" [tool.pytest.ini_options] asyncio_mode = "auto" From ea06c9bb4959f434917881695a859708c28fbb67 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 21:50:46 +0100 Subject: [PATCH 30/63] Use normal pip for make install commands --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 69735178..4f87cb74 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,15 @@ SOURCE_DIRS = cfripper tests docs SOURCE_FILES = setup.py SOURCE_ALL = $(SOURCE_DIRS) $(SOURCE_FILES) +PIP_COMMAND = pip install: - uv pip install -r requirements.txt + $(PIP_COMMAND) install -r requirements.txt install-dev: install - uv pip install -r requirements.txt -r requirements-dev.txt + $(PIP_COMMAND) install -r requirements.txt -r requirements-dev.txt install-docs: - uv pip install -r requirements.txt -r requirements-docs.txt + $(PIP_COMMAND) install -r requirements.txt -r requirements-docs.txt format: isort --recursive $(SOURCE_ALL) From df22fee35b4da217a83e95f584c07ac46a355df6 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 21:51:09 +0100 Subject: [PATCH 31/63] Uv install not required for now --- .github/workflows/lint-and-test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 82d8cac4..f004ec15 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -21,8 +21,6 @@ jobs: with: python-version: ${{ matrix.python-version }} - - run: python -m pip install uv - - run: make install-dev - run: make lint From 93b2a4215380563109fec876d28b466be1be7040 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:04:07 +0100 Subject: [PATCH 32/63] Remove isort and black, use ruff --- Makefile | 25 +++++++------------------ pyproject.toml | 20 +------------------- requirements-dev.txt | 22 ++++------------------ requirements-docs.txt | 22 ++++------------------ requirements.txt | 6 +++--- 5 files changed, 19 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index 4f87cb74..38200ef3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,4 @@ -SOURCE_DIRS = cfripper tests docs -SOURCE_FILES = setup.py -SOURCE_ALL = $(SOURCE_DIRS) $(SOURCE_FILES) +SOURCES = cfripper tests docs PIP_COMMAND = pip install: @@ -13,19 +11,10 @@ install-docs: $(PIP_COMMAND) install -r requirements.txt -r requirements-docs.txt format: - isort --recursive $(SOURCE_ALL) - black $(SOURCE_ALL) + ruff format $(SOURCES) -lint: isort-lint black-lint flake8-lint - -isort-lint: - isort --check-only --recursive $(SOURCE_ALL) - -black-lint: - black --check $(SOURCE_ALL) - -flake8-lint: - flake8 $(SOURCE_ALL) +lint: + ruff check $(SOURCES) unit: pytest -svvv tests @@ -54,11 +43,11 @@ freeze: freeze-base freeze-dev freeze-docs freeze-upgrade-base: $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --upgrade --output-file requirements.txt freeze-upgrade-dev: - $(FREEZE_COMMAND) pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt freeze-upgrade-docs: - $(FREEZE_COMMAND) pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt + $(FREEZE_COMMAND) $(FREEZE_OPTIONS) pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt freeze-upgrade: freeze-upgrade-base freeze-upgrade-dev freeze-upgrade-docs -.PHONY: install install-dev install-docs format lint isort-lint black-lint flake8-lint unit coverage test freeze freeze-upgrade\ +.PHONY: install install-dev install-docs format lint unit coverage test freeze freeze-upgrade\ freeze-base freeze-dev freeze-docs freeze-upgrade-base freeze-upgrade-dev freeze-upgrade-docs diff --git a/pyproject.toml b/pyproject.toml index 6a37b177..917a732a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,23 +57,6 @@ docs = [ "mkdocs-minify-plugin==0.5.0", ] -[tool.black] -line-length = 120 -exclude = ''' -/( - | \.venv - | venv -)/ -''' - -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -combine_as_imports = true -line_length = 120 -skip = [".eggs", ".venv", "venv", "build", "site"] - [tool.ruff] # Exclude a variety of commonly ignored directories. exclude = [ @@ -99,13 +82,12 @@ indent-width = 4 target-version = "py38" [tool.pytest.ini_options] -asyncio_mode = "auto" log_cli = true log_level = "INFO" [tool.coverage.report] show_missing = true -skip_covered = true +skip_covered = false [tool.coverage.run] branch = true diff --git a/requirements-dev.txt b/requirements-dev.txt index 4074b896..70d24565 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,27 +1,23 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --output-file requirements-dev.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt attrs==23.2.0 aws-sam-translator==1.85.0 aws-xray-sdk==2.12.1 -black==22.3.0 -boto3==1.34.43 -botocore==1.34.43 -build==1.0.3 +boto3==1.34.44 +botocore==1.34.44 certifi==2024.2.2 cffi==1.16.0 cfn-flip==1.3.0 -cfn-lint==0.85.1 +cfn-lint==0.85.2 charset-normalizer==3.3.2 click==8.1.7 coverage==7.4.1 cryptography==42.0.3 docker==7.0.0 ecdsa==0.18.0 -flake8==7.0.0 graphql-core==3.2.3 idna==3.6 iniconfig==2.0.0 -isort==4.3.21 jinja2==3.1.3 jmespath==1.0.1 jschema-to-python==1.2.3 @@ -35,32 +31,23 @@ jsonschema-specifications==2023.12.1 junit-xml==1.9 lazy-object-proxy==1.10.0 markupsafe==2.1.5 -mccabe==0.7.0 moto==5.0.1 mpmath==1.3.0 multipart==0.2.4 -mypy-extensions==1.0.0 networkx==3.2.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==23.2 pathable==0.4.3 -pathspec==0.12.1 pbr==6.0.0 -pip==24.0 -pip-tools==7.3.0 -platformdirs==4.2.0 pluggy==0.13.1 py-partiql-parser==0.5.1 pyasn1==0.5.1 pycfmodel==0.22.0 -pycodestyle==2.11.1 pycparser==2.21 pydantic==1.10.14 pydash==7.0.7 -pyflakes==3.2.0 pyparsing==3.1.1 -pyproject-hooks==1.0.0 pytest==7.4.4 pytest-cov==4.1.0 python-dateutil==2.8.2 @@ -84,6 +71,5 @@ typing-extensions==4.9.0 urllib3==2.0.7 uv==0.1.2 werkzeug==3.0.1 -wheel==0.42.0 wrapt==1.16.0 xmltodict==0.13.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index 3e1e3081..9926ae6e 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,16 +1,14 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --extra docs --output-file requirements-docs.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt attrs==23.2.0 aws-sam-translator==1.85.0 aws-xray-sdk==2.12.1 -black==22.3.0 -boto3==1.34.43 -botocore==1.34.43 -build==1.0.3 +boto3==1.34.44 +botocore==1.34.44 certifi==2024.2.2 cffi==1.16.0 cfn-flip==1.3.0 -cfn-lint==0.85.1 +cfn-lint==0.85.2 charset-normalizer==3.3.2 click==8.1.7 coverage==7.4.1 @@ -18,14 +16,12 @@ cryptography==42.0.3 csscompressor==0.9.5 docker==7.0.0 ecdsa==0.18.0 -flake8==7.0.0 ghp-import==2.1.0 graphql-core==3.2.3 htmlmin==0.1.12 idna==3.6 importlib-metadata==7.0.1 iniconfig==2.0.0 -isort==4.3.21 jinja2==3.1.3 jmespath==1.0.1 jschema-to-python==1.2.3 @@ -41,7 +37,6 @@ junit-xml==1.9 lazy-object-proxy==1.10.0 markdown==3.5.2 markupsafe==2.1.5 -mccabe==0.7.0 mergedeep==1.3.4 mkdocs==1.3.0 mkdocs-macros-plugin==0.7.0 @@ -51,30 +46,22 @@ mkdocs-minify-plugin==0.5.0 moto==5.0.1 mpmath==1.3.0 multipart==0.2.4 -mypy-extensions==1.0.0 networkx==3.2.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==23.2 pathable==0.4.3 -pathspec==0.12.1 pbr==6.0.0 -pip==24.0 -pip-tools==7.3.0 -platformdirs==4.2.0 pluggy==0.13.1 py-partiql-parser==0.5.1 pyasn1==0.5.1 pycfmodel==0.22.0 -pycodestyle==2.11.1 pycparser==2.21 pydantic==1.10.14 pydash==7.0.7 -pyflakes==3.2.0 pygments==2.17.2 pymdown-extensions==10.7 pyparsing==3.1.1 -pyproject-hooks==1.0.0 pytest==7.4.4 pytest-cov==4.1.0 python-dateutil==2.8.2 @@ -101,7 +88,6 @@ urllib3==2.0.7 uv==0.1.2 watchdog==4.0.0 werkzeug==3.0.1 -wheel==0.42.0 wrapt==1.16.0 xmltodict==0.13.0 zipp==3.17.0 diff --git a/requirements.txt b/requirements.txt index a30fdfd5..34a1a4d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --output-file requirements.txt -boto3==1.34.43 -botocore==1.34.43 +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --output-file requirements.txt +boto3==1.34.44 +botocore==1.34.44 cfn-flip==1.3.0 click==8.1.7 jmespath==1.0.1 From 2b3eaeb73cf5a4703794f96bab029207447b729e Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:25:32 +0100 Subject: [PATCH 33/63] Improve ruff config --- cfripper/cli.py | 5 +++-- pyproject.toml | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cfripper/cli.py b/cfripper/cli.py index 32cf2710..2c92f27e 100644 --- a/cfripper/cli.py +++ b/cfripper/cli.py @@ -1,6 +1,7 @@ import logging import re import sys +from importlib.metadata import PackageNotFoundError, version from io import TextIOWrapper from pathlib import Path from typing import Dict, List, Optional, Tuple @@ -9,7 +10,6 @@ import pycfmodel from pycfmodel.model.cf_model import CFModel -from cfripper.__version__ import __version__ from cfripper.config.config import Config from cfripper.config.pluggy.utils import get_all_rules from cfripper.exceptions import FileEmptyException @@ -18,6 +18,7 @@ from cfripper.model.utils import convert_json_or_yaml_to_dict from cfripper.rule_processor import RuleProcessor + LOGGING_LEVELS = { "ERROR": logging.ERROR, "WARNING": logging.WARNING, @@ -145,7 +146,7 @@ def validate_aws_principals(ctx: click.Context, param: str, value: str) -> Optio @click.command() -@click.version_option(prog_name="cfripper", version=__version__) +@click.version_option(prog_name="cfripper", version=version("package-name")) @click.argument("templates", type=click.File("r"), nargs=-1) @click.option( "--resolve/--no-resolve", diff --git a/pyproject.toml b/pyproject.toml index 917a732a..1199adfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,25 @@ line-length = 120 indent-width = 4 target-version = "py38" +[tool.ruff.lint] +select = ["E", "F", "W", "A", "PLC", "PLE", "PLW", "I"] +ignore = ["A002", "E501"] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" +docstring-code-format = false +docstring-code-line-length = "dynamic" + [tool.pytest.ini_options] log_cli = true log_level = "INFO" From b0ae9ad27a16cd3434a7d6fc5b5881161b7fdca7 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:32:54 +0100 Subject: [PATCH 34/63] Fix linter issues --- cfripper/cli.py | 3 +-- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- requirements.txt | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cfripper/cli.py b/cfripper/cli.py index 2c92f27e..e6209019 100644 --- a/cfripper/cli.py +++ b/cfripper/cli.py @@ -1,7 +1,7 @@ import logging import re import sys -from importlib.metadata import PackageNotFoundError, version +from importlib.metadata import version from io import TextIOWrapper from pathlib import Path from typing import Dict, List, Optional, Tuple @@ -18,7 +18,6 @@ from cfripper.model.utils import convert_json_or_yaml_to_dict from cfripper.rule_processor import RuleProcessor - LOGGING_LEVELS = { "ERROR": logging.ERROR, "WARNING": logging.WARNING, diff --git a/requirements-dev.txt b/requirements-dev.txt index 70d24565..9172cc5a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --output-file requirements-dev.txt attrs==23.2.0 aws-sam-translator==1.85.0 aws-xray-sdk==2.12.1 diff --git a/requirements-docs.txt b/requirements-docs.txt index 9926ae6e..a3dab6c5 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --extra docs --output-file requirements-docs.txt attrs==23.2.0 aws-sam-translator==1.85.0 aws-xray-sdk==2.12.1 diff --git a/requirements.txt b/requirements.txt index 34a1a4d3..34acd56f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --output-file requirements.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --output-file requirements.txt boto3==1.34.44 botocore==1.34.44 cfn-flip==1.3.0 From a12bc50ce6e7742f14789a02d95de27f0ad46816 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:36:11 +0100 Subject: [PATCH 35/63] Upgrade requirements to work in 3.8 --- cfripper/cli.py | 2 +- requirements-dev.txt | 9 +++++++-- requirements-docs.txt | 8 ++++++-- requirements.txt | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cfripper/cli.py b/cfripper/cli.py index e6209019..e1739711 100644 --- a/cfripper/cli.py +++ b/cfripper/cli.py @@ -145,7 +145,7 @@ def validate_aws_principals(ctx: click.Context, param: str, value: str) -> Optio @click.command() -@click.version_option(prog_name="cfripper", version=version("package-name")) +@click.version_option(prog_name="cfripper", version=version("cfripper")) @click.argument("templates", type=click.File("r"), nargs=-1) @click.option( "--resolve/--no-resolve", diff --git a/requirements-dev.txt b/requirements-dev.txt index 9172cc5a..7d6df272 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -15,8 +15,10 @@ coverage==7.4.1 cryptography==42.0.3 docker==7.0.0 ecdsa==0.18.0 +exceptiongroup==1.2.0 graphql-core==3.2.3 idna==3.6 +importlib-resources==6.1.1 iniconfig==2.0.0 jinja2==3.1.3 jmespath==1.0.1 @@ -34,12 +36,13 @@ markupsafe==2.1.5 moto==5.0.1 mpmath==1.3.0 multipart==0.2.4 -networkx==3.2.1 +networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==23.2 pathable==0.4.3 pbr==6.0.0 +pkgutil-resolve-name==1.3.10 pluggy==0.13.1 py-partiql-parser==0.5.1 pyasn1==0.5.1 @@ -67,9 +70,11 @@ setuptools==69.1.0 six==1.16.0 sshpubkeys==3.3.1 sympy==1.12 +tomli==2.0.1 typing-extensions==4.9.0 -urllib3==2.0.7 +urllib3==1.26.18 uv==0.1.2 werkzeug==3.0.1 wrapt==1.16.0 xmltodict==0.13.0 +zipp==3.17.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index a3dab6c5..153d7686 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -16,11 +16,13 @@ cryptography==42.0.3 csscompressor==0.9.5 docker==7.0.0 ecdsa==0.18.0 +exceptiongroup==1.2.0 ghp-import==2.1.0 graphql-core==3.2.3 htmlmin==0.1.12 idna==3.6 importlib-metadata==7.0.1 +importlib-resources==6.1.1 iniconfig==2.0.0 jinja2==3.1.3 jmespath==1.0.1 @@ -46,12 +48,13 @@ mkdocs-minify-plugin==0.5.0 moto==5.0.1 mpmath==1.3.0 multipart==0.2.4 -networkx==3.2.1 +networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==23.2 pathable==0.4.3 pbr==6.0.0 +pkgutil-resolve-name==1.3.10 pluggy==0.13.1 py-partiql-parser==0.5.1 pyasn1==0.5.1 @@ -83,8 +86,9 @@ six==1.16.0 sshpubkeys==3.3.1 sympy==1.12 termcolor==2.4.0 +tomli==2.0.1 typing-extensions==4.9.0 -urllib3==2.0.7 +urllib3==1.26.18 uv==0.1.2 watchdog==4.0.0 werkzeug==3.0.1 diff --git a/requirements.txt b/requirements.txt index 34acd56f..15c460e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,4 @@ pyyaml==6.0.1 s3transfer==0.10.0 six==1.16.0 typing-extensions==4.9.0 -urllib3==2.0.7 +urllib3==1.26.18 From 082a9db7227de6c22f28dc6d6b0ff29207251572 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:43:21 +0100 Subject: [PATCH 36/63] Install cfripper package as part of the dev requirements --- Makefile | 4 ++-- setup.cfg | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 setup.cfg diff --git a/Makefile b/Makefile index 38200ef3..12cec519 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ PIP_COMMAND = pip install: $(PIP_COMMAND) install -r requirements.txt -install-dev: install - $(PIP_COMMAND) install -r requirements.txt -r requirements-dev.txt +install-dev: + $(PIP_COMMAND) install -r requirements.txt -r requirements-dev.txt . install-docs: $(PIP_COMMAND) install -r requirements.txt -r requirements-docs.txt diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 551f0cd8..00000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[isort] -multi_line_output = 3 -include_trailing_comma = True -force_grid_wrap = 0 -combine_as_imports = True -line_length = 120 -skip = .venv,venv From 62e08bdf393f513578cc4dce1bc0718291d7ee54 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:45:12 +0100 Subject: [PATCH 37/63] Install cfripper package as part of the docs requirements --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 12cec519..5a9a67aa 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ install-dev: $(PIP_COMMAND) install -r requirements.txt -r requirements-dev.txt . install-docs: - $(PIP_COMMAND) install -r requirements.txt -r requirements-docs.txt + $(PIP_COMMAND) install -r requirements.txt -r requirements-docs.txt . format: ruff format $(SOURCES) From 451e63488b84cc301a8636fd8757dfcf4b980361 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:53:55 +0100 Subject: [PATCH 38/63] Test new build --- .github/workflows/pypi-release.yml | 30 ++++++++++++++++++------------ Makefile | 5 +---- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index eafb511f..3b3fc3d7 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -1,8 +1,10 @@ name: PyPI release -on: - release: - types: [published] +#on: +# release: +# types: [published] + +on: push jobs: pypi-publish: @@ -20,18 +22,22 @@ jobs: - name: Setup python uses: actions/setup-python@v4 with: - python-version: '3.7' + python-version: '3.8' - name: Install dependencies run: | python -m pip install -U pip - python -m pip install -U twine build + python -m pip install -U twine build setuptools-scm + + - name: Build package + run: | + python -m setuptools_scm + python -m build + twine check --strict dist/* - - name: Build a binary wheel - run: python setup.py sdist bdist_wheel - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} +# - name: Publish distribution 📦 to PyPI +# uses: pypa/gh-action-pypi-publish@release/v1 +# with: +# user: __token__ +# password: ${{ secrets.PYPI_TOKEN }} diff --git a/Makefile b/Makefile index 5a9a67aa..ebfda966 100644 --- a/Makefile +++ b/Makefile @@ -20,10 +20,7 @@ unit: pytest -svvv tests coverage: - coverage run --source=cfripper --branch -m pytest tests/ --junitxml=build/test.xml -v - coverage report - coverage xml -i -o build/coverage.xml - coverage html + pytest --cov cfripper test: lint unit From 1d1ddd942f1a56bc7000dd57c12c386a63f48259 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 22:56:43 +0100 Subject: [PATCH 39/63] Upgrade setuptools --- .github/workflows/pypi-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 3b3fc3d7..e8d9443c 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | - python -m pip install -U pip + python -m pip install -U pip setuptools python -m pip install -U twine build setuptools-scm - name: Build package @@ -35,7 +35,6 @@ jobs: python -m build twine check --strict dist/* - # - name: Publish distribution 📦 to PyPI # uses: pypa/gh-action-pypi-publish@release/v1 # with: From ba8548fbead86771763ac82edb01f84d22af277e Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 23:00:24 +0100 Subject: [PATCH 40/63] Prepare for release --- .github/workflows/pypi-release.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index e8d9443c..bf2255eb 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -1,10 +1,8 @@ name: PyPI release -#on: -# release: -# types: [published] - -on: push +on: + release: + types: [published] jobs: pypi-publish: @@ -35,8 +33,8 @@ jobs: python -m build twine check --strict dist/* -# - name: Publish distribution 📦 to PyPI -# uses: pypa/gh-action-pypi-publish@release/v1 -# with: -# user: __token__ -# password: ${{ secrets.PYPI_TOKEN }} + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} From 58d99b1a5c15be7753eac64475920c0a2d36b2c8 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 23:08:12 +0100 Subject: [PATCH 41/63] Improve classifiers --- pyproject.toml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1199adfa..882dee49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,8 +20,18 @@ keywords = [ ] classifiers = [ - "Framework :: Django", + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Security" ] dependencies = [ From 1b91b0a6ee65907290cb6e02803b058c9b310b2b Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Fri, 16 Feb 2024 23:09:20 +0100 Subject: [PATCH 42/63] Update license metadata --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 882dee49..a7171db5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description="Library and CLI tool for analysing CloudFormation templates and che readme = "README.md" requires-python = ">=3.8.0" dynamic = ["version"] -license = { text = "Apache-2.0" } +license = { file = "LICENSE.md" } authors = [ { name = "Skyscanner Security", email = "security@skyscanner.net" } ] From 69ba38540d23f71a55926cf7f974b72b3cfcd9a5 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Sat, 17 Feb 2024 15:16:48 +0100 Subject: [PATCH 43/63] Remove flake config file --- .flake8 | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index dc1e5391..00000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-line-length=120 -# E203 and E501 are ours, the others are the default from flake -ignore = E121,E123,E126,E226,E24,E704,W503,W504,E203,E501 \ No newline at end of file From 2b9e05c22f10d701f7246c55f5d5eab5dae91cca Mon Sep 17 00:00:00 2001 From: Ramon Date: Thu, 22 Feb 2024 10:32:59 +0100 Subject: [PATCH 44/63] add dependabot config (#257) Co-authored-by: Ramon --- .github/dependabot.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2e396efa --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" + open-pull-requests-limit: 1 + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + open-pull-requests-limit: 1 From d8fd34e9d86da0602101154af9089eb8e4ff5092 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 4 Mar 2024 12:24:10 +0100 Subject: [PATCH 45/63] Update .readthedocs.yaml (#275) * Update .readthedocs.yaml Use python 3.8 * Update .readthedocs.yaml Use python 3.9 --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 74790827..d209ee51 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ formats: all build: os: ubuntu-22.04 tools: - python: "3.7" + python: "3.9" python: install: From 6746d2817309ff88aab7aadd85d20bce5109fd35 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio Date: Mon, 4 Mar 2024 12:25:44 +0100 Subject: [PATCH 46/63] Fix logo in pypi (#274) Co-authored-by: Ignacio Bolonio <> Co-authored-by: Ramon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19cfc1ac..90135173 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

-cfripper logo +cfripper logo

# CFRipper From b518aa1d7e620f163e48c43a55ffcdefc00739a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:29:07 +0100 Subject: [PATCH 47/63] Bump cryptography from 42.0.3 to 42.0.4 (#272) Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.3 to 42.0.4. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/42.0.3...42.0.4) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ramon --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 7d6df272..a8df70dc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,7 +12,7 @@ cfn-lint==0.85.2 charset-normalizer==3.3.2 click==8.1.7 coverage==7.4.1 -cryptography==42.0.3 +cryptography==42.0.4 docker==7.0.0 ecdsa==0.18.0 exceptiongroup==1.2.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index 153d7686..365eb305 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -12,7 +12,7 @@ cfn-lint==0.85.2 charset-normalizer==3.3.2 click==8.1.7 coverage==7.4.1 -cryptography==42.0.3 +cryptography==42.0.4 csscompressor==0.9.5 docker==7.0.0 ecdsa==0.18.0 From 9ac8f7d7b0d925776b03143615e29239094956f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:33:04 +0100 Subject: [PATCH 48/63] Bump actions/setup-python from 4 to 5 (#270) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ramon --- .github/workflows/lint-and-test.yml | 2 +- .github/workflows/pypi-release.yml | 2 +- .github/workflows/test-docs.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index f004ec15..ecdbf111 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index bf2255eb..2b3f77b3 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.8' diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index a1213a91..0ecf0089 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 - name: Setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 From 0c198d53ed0a3cde3ce00bb42256354b23e30248 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:57:20 +0200 Subject: [PATCH 49/63] Bump idna from 3.6 to 3.7 (#282) Bumps [idna](https://github.com/kjd/idna) from 3.6 to 3.7. - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v3.6...v3.7) --- updated-dependencies: - dependency-name: idna dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index a8df70dc..d3c3c977 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -17,7 +17,7 @@ docker==7.0.0 ecdsa==0.18.0 exceptiongroup==1.2.0 graphql-core==3.2.3 -idna==3.6 +idna==3.7 importlib-resources==6.1.1 iniconfig==2.0.0 jinja2==3.1.3 diff --git a/requirements-docs.txt b/requirements-docs.txt index 365eb305..339aa3eb 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -20,7 +20,7 @@ exceptiongroup==1.2.0 ghp-import==2.1.0 graphql-core==3.2.3 htmlmin==0.1.12 -idna==3.6 +idna==3.7 importlib-metadata==7.0.1 importlib-resources==6.1.1 iniconfig==2.0.0 From 0911af0e547d00a3e7e207956db649a0b95f5d56 Mon Sep 17 00:00:00 2001 From: Oscar Blanco Date: Tue, 11 Jun 2024 17:32:50 +0200 Subject: [PATCH 50/63] Upgrade to pydantic v2 (#286) * wip * wip * Add changelog and bump pycfmodel * Trigger build --------- Co-authored-by: Ignacio Bolonio <> --- CHANGELOG.md | 15 + cfripper/config/config.py | 14 +- cfripper/config/filter.py | 7 +- cfripper/model/result.py | 9 +- pyproject.toml | 2 +- requirements-dev.txt | 90 +++-- requirements-docs.txt | 101 +++--- requirements.txt | 22 +- .../test_S3LifecycleConfigurationRule.py | 1 - tests/rules/test_WildcardResourceRule.py | 336 ++++++++++-------- ...ed_template_malformed_lifecycle_rules.yaml | 10 - 11 files changed, 324 insertions(+), 283 deletions(-) delete mode 100644 tests/test_templates/rules/S3LifecycleConfiguration/allowed_template_malformed_lifecycle_rules.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 53477741..c88e4332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.15.7] +### Updates +- Bumped pycfmodel to use pydantic v2 + +## [1.15.6] +## Fixes +- Fix logo displayed in pypi +### Updates +- Bumped python used in readthedocs to 3.9 + +## [1.15.5] +### Changes +- Add dependabot config +- Migrate to `pyproject.toml` + ## [1.15.4] ## Fixes - Fix `KMSKeyWildcardPrincipalRule` to work without a KMS policy diff --git a/cfripper/config/config.py b/cfripper/config/config.py index 61c4fa0c..7490c06f 100644 --- a/cfripper/config/config.py +++ b/cfripper/config/config.py @@ -8,7 +8,7 @@ from pathlib import Path from typing import DefaultDict, Dict, List -from pydantic import BaseModel +from pydantic import RootModel from cfripper.config.constants import ( AWS_CLOUDTRAIL_ACCOUNT_IDS, @@ -201,7 +201,7 @@ def load_rules_config_file(self, rules_config_file: TextIOWrapper): spec.loader.exec_module(module) rules_config = vars(module).get("RULES_CONFIG") # Validate rules_config format - RulesConfigMapping(__root__=rules_config) + RulesConfigMapping.model_validate(rules_config) self.rules_config = rules_config except Exception: logger.exception(f"Failed to read config file: {filename}") @@ -236,7 +236,7 @@ def get_filters_from_filename_path(cls, filename: Path) -> List[Filter]: spec.loader.exec_module(module) filters = vars(module).get("FILTERS") or [] # Validate filters format - RulesFiltersMapping(__root__=filters) + RulesFiltersMapping.model_validate(filters) return filters def add_filters(self, filters: List[Filter]): @@ -245,9 +245,5 @@ def add_filters(self, filters: List[Filter]): self.rules_filters[rule].append(rule_filter) -class RulesConfigMapping(BaseModel): - __root__: Dict[str, RuleConfig] - - -class RulesFiltersMapping(BaseModel): - __root__: List[Filter] +RulesConfigMapping = RootModel[Dict[str, RuleConfig]] +RulesFiltersMapping = RootModel[List[Filter]] diff --git a/cfripper/config/filter.py b/cfripper/config/filter.py index 3f7c5870..40a4a2b1 100644 --- a/cfripper/config/filter.py +++ b/cfripper/config/filter.py @@ -2,7 +2,7 @@ import re from typing import Any, Callable, Dict, List, Optional, Set, Union -from pydantic import BaseModel, validator +from pydantic import BaseModel, field_validator from pydash.objects import get from cfripper.model.enums import RuleMode, RuleRisk @@ -83,9 +83,10 @@ class Filter(BaseModel): risk_value: Optional[RuleRisk] = None rules: Set[str] = None - @validator("eval", pre=True) + @field_validator("eval", mode="before") + @classmethod def set_eval(cls, eval, values): - return build_evaluator(eval, values["debug"]) + return build_evaluator(eval, values.data["debug"]) def __call__(self, **kwargs): if self.debug: diff --git a/cfripper/model/result.py b/cfripper/model/result.py index 1c1e51f6..7426f938 100644 --- a/cfripper/model/result.py +++ b/cfripper/model/result.py @@ -1,6 +1,6 @@ from typing import Collection, List, Optional -from pydantic import BaseModel, Extra +from pydantic import BaseModel, ConfigDict from cfripper.model.enums import RuleGranularity, RuleMode, RuleRisk @@ -15,8 +15,7 @@ class Failure(BaseModel): resource_ids: Optional[set] = set() resource_types: Optional[set] = set() - class Config(BaseModel.Config): - extra = Extra.forbid + model_config = ConfigDict(extra="forbid") def serializable(self): return { @@ -32,9 +31,7 @@ def serializable(self): class Result(BaseModel): - class Config(BaseModel.Config): - extra = Extra.forbid - arbitrary_types_allowed = True + model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True) exceptions: List[Exception] = [] failures: List[Failure] = [] diff --git a/pyproject.toml b/pyproject.toml index a7171db5..6f33a24d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "cfn_flip>=1.2.0", "click>=8.0.0", "pluggy~=0.13.1", - "pycfmodel>=0.22.0", + "pycfmodel>=1.0.0", "pydash>=4.7.6", "PyYAML>=4.2b1" ] diff --git a/requirements-dev.txt b/requirements-dev.txt index d3c3c977..ed2e71d7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,80 +1,78 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --output-file requirements-dev.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt +annotated-types==0.7.0 +antlr4-python3-runtime==4.13.1 attrs==23.2.0 -aws-sam-translator==1.85.0 -aws-xray-sdk==2.12.1 -boto3==1.34.44 -botocore==1.34.44 -certifi==2024.2.2 +aws-sam-translator==1.89.0 +aws-xray-sdk==2.14.0 +boto3==1.34.123 +botocore==1.34.123 +certifi==2024.6.2 cffi==1.16.0 cfn-flip==1.3.0 -cfn-lint==0.85.2 +cfn-lint==0.87.5 charset-normalizer==3.3.2 click==8.1.7 -coverage==7.4.1 -cryptography==42.0.4 -docker==7.0.0 -ecdsa==0.18.0 -exceptiongroup==1.2.0 +coverage==7.5.3 +cryptography==42.0.8 +docker==7.1.0 +exceptiongroup==1.2.1 graphql-core==3.2.3 idna==3.7 -importlib-resources==6.1.1 iniconfig==2.0.0 -jinja2==3.1.3 +jinja2==3.1.4 jmespath==1.0.1 +joserfc==0.11.1 jschema-to-python==1.2.3 jsondiff==2.0.0 jsonpatch==1.33 -jsonpickle==3.0.2 -jsonpointer==2.4 -jsonschema==4.21.1 +jsonpath-ng==1.6.1 +jsonpickle==3.2.1 +jsonpointer==3.0.0 +jsonschema==4.22.0 jsonschema-path==0.3.2 jsonschema-specifications==2023.12.1 junit-xml==1.9 lazy-object-proxy==1.10.0 markupsafe==2.1.5 -moto==5.0.1 +moto==5.0.9 mpmath==1.3.0 multipart==0.2.4 -networkx==3.1 +networkx==3.2.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 -packaging==23.2 +packaging==24.1 pathable==0.4.3 pbr==6.0.0 -pkgutil-resolve-name==1.3.10 pluggy==0.13.1 -py-partiql-parser==0.5.1 -pyasn1==0.5.1 -pycfmodel==0.22.0 -pycparser==2.21 -pydantic==1.10.14 -pydash==7.0.7 -pyparsing==3.1.1 +ply==3.11 +py-partiql-parser==0.5.5 +pycfmodel==1.0.0 +pycparser==2.22 +pydantic==2.7.3 +pydantic-core==2.18.4 +pydash==8.0.1 +pyparsing==3.1.2 pytest==7.4.4 -pytest-cov==4.1.0 -python-dateutil==2.8.2 -python-jose==3.3.0 -pyyaml==6.0.1 +pytest-cov==5.0.0 +python-dateutil==2.9.0.post0 +pyyaml==6.0.2rc1 referencing==0.31.1 -regex==2023.12.25 -requests==2.31.0 -responses==0.25.0 +regex==2024.5.15 +requests==2.32.3 +responses==0.25.2 rfc3339-validator==0.1.4 -rpds-py==0.18.0 -rsa==4.9 -ruff==0.2.1 -s3transfer==0.10.0 +rpds-py==0.18.1 +ruff==0.4.8 +s3transfer==0.10.1 sarif-om==1.0.4 -setuptools==69.1.0 +setuptools==70.0.0 six==1.16.0 -sshpubkeys==3.3.1 -sympy==1.12 +sympy==1.12.1 tomli==2.0.1 -typing-extensions==4.9.0 +typing-extensions==4.12.2 urllib3==1.26.18 -uv==0.1.2 -werkzeug==3.0.1 +uv==0.2.10 +werkzeug==3.0.3 wrapt==1.16.0 xmltodict==0.13.0 -zipp==3.17.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index 339aa3eb..29e77499 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,43 +1,45 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --extra dev --extra docs --output-file requirements-docs.txt +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt +annotated-types==0.7.0 +antlr4-python3-runtime==4.13.1 attrs==23.2.0 -aws-sam-translator==1.85.0 -aws-xray-sdk==2.12.1 -boto3==1.34.44 -botocore==1.34.44 -certifi==2024.2.2 +aws-sam-translator==1.89.0 +aws-xray-sdk==2.14.0 +boto3==1.34.123 +botocore==1.34.123 +certifi==2024.6.2 cffi==1.16.0 cfn-flip==1.3.0 -cfn-lint==0.85.2 +cfn-lint==0.87.5 charset-normalizer==3.3.2 click==8.1.7 -coverage==7.4.1 -cryptography==42.0.4 +coverage==7.5.3 +cryptography==42.0.8 csscompressor==0.9.5 -docker==7.0.0 -ecdsa==0.18.0 -exceptiongroup==1.2.0 +docker==7.1.0 +exceptiongroup==1.2.1 ghp-import==2.1.0 graphql-core==3.2.3 htmlmin==0.1.12 idna==3.7 -importlib-metadata==7.0.1 -importlib-resources==6.1.1 +importlib-metadata==7.1.0 iniconfig==2.0.0 -jinja2==3.1.3 +jinja2==3.1.4 jmespath==1.0.1 +joserfc==0.11.1 jschema-to-python==1.2.3 jsmin==3.0.1 jsondiff==2.0.0 jsonpatch==1.33 -jsonpickle==3.0.2 -jsonpointer==2.4 -jsonschema==4.21.1 +jsonpath-ng==1.6.1 +jsonpickle==3.2.1 +jsonpointer==3.0.0 +jsonschema==4.22.0 jsonschema-path==0.3.2 jsonschema-specifications==2023.12.1 junit-xml==1.9 lazy-object-proxy==1.10.0 -markdown==3.5.2 +markdown==3.6 markupsafe==2.1.5 mergedeep==1.3.4 mkdocs==1.3.0 @@ -45,53 +47,50 @@ mkdocs-macros-plugin==0.7.0 mkdocs-material==8.2.8 mkdocs-material-extensions==1.0.3 mkdocs-minify-plugin==0.5.0 -moto==5.0.1 +moto==5.0.9 mpmath==1.3.0 multipart==0.2.4 -networkx==3.1 +networkx==3.2.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 -packaging==23.2 +packaging==24.1 pathable==0.4.3 pbr==6.0.0 -pkgutil-resolve-name==1.3.10 pluggy==0.13.1 -py-partiql-parser==0.5.1 -pyasn1==0.5.1 -pycfmodel==0.22.0 -pycparser==2.21 -pydantic==1.10.14 -pydash==7.0.7 -pygments==2.17.2 -pymdown-extensions==10.7 -pyparsing==3.1.1 +ply==3.11 +py-partiql-parser==0.5.5 +pycfmodel==1.0.0 +pycparser==2.22 +pydantic==2.7.3 +pydantic-core==2.18.4 +pydash==8.0.1 +pygments==2.18.0 +pymdown-extensions==10.8.1 +pyparsing==3.1.2 pytest==7.4.4 -pytest-cov==4.1.0 -python-dateutil==2.8.2 -python-jose==3.3.0 -pyyaml==6.0.1 +pytest-cov==5.0.0 +python-dateutil==2.9.0.post0 +pyyaml==6.0.2rc1 pyyaml-env-tag==0.1 referencing==0.31.1 -regex==2023.12.25 -requests==2.31.0 -responses==0.25.0 +regex==2024.5.15 +requests==2.32.3 +responses==0.25.2 rfc3339-validator==0.1.4 -rpds-py==0.18.0 -rsa==4.9 -ruff==0.2.1 -s3transfer==0.10.0 +rpds-py==0.18.1 +ruff==0.4.8 +s3transfer==0.10.1 sarif-om==1.0.4 -setuptools==69.1.0 +setuptools==70.0.0 six==1.16.0 -sshpubkeys==3.3.1 -sympy==1.12 +sympy==1.12.1 termcolor==2.4.0 tomli==2.0.1 -typing-extensions==4.9.0 +typing-extensions==4.12.2 urllib3==1.26.18 -uv==0.1.2 -watchdog==4.0.0 -werkzeug==3.0.1 +uv==0.2.10 +watchdog==4.0.1 +werkzeug==3.0.3 wrapt==1.16.0 xmltodict==0.13.0 -zipp==3.17.0 +zipp==3.19.2 diff --git a/requirements.txt b/requirements.txt index 15c460e6..1051c38a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,19 @@ # This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --output-file requirements.txt -boto3==1.34.44 -botocore==1.34.44 +# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --output-file requirements.txt +annotated-types==0.7.0 +boto3==1.34.123 +botocore==1.34.123 cfn-flip==1.3.0 click==8.1.7 jmespath==1.0.1 pluggy==0.13.1 -pycfmodel==0.22.0 -pydantic==1.10.14 -pydash==7.0.7 -python-dateutil==2.8.2 -pyyaml==6.0.1 -s3transfer==0.10.0 +pycfmodel==1.0.0 +pydantic==2.7.3 +pydantic-core==2.18.4 +pydash==8.0.1 +python-dateutil==2.9.0.post0 +pyyaml==6.0.2rc1 +s3transfer==0.10.1 six==1.16.0 -typing-extensions==4.9.0 +typing-extensions==4.12.2 urllib3==1.26.18 diff --git a/tests/rules/test_S3LifecycleConfigurationRule.py b/tests/rules/test_S3LifecycleConfigurationRule.py index 4d7f5751..0c1ef036 100644 --- a/tests/rules/test_S3LifecycleConfigurationRule.py +++ b/tests/rules/test_S3LifecycleConfigurationRule.py @@ -17,7 +17,6 @@ def bad_template_no_configuration(): "template_path", [ "rules/S3LifecycleConfiguration/good_template.yaml", - "rules/S3LifecycleConfiguration/allowed_template_malformed_lifecycle_rules.yaml", ], ) def test_no_failures_are_raised(template_path): diff --git a/tests/rules/test_WildcardResourceRule.py b/tests/rules/test_WildcardResourceRule.py index 21c3fc42..b4b7df15 100644 --- a/tests/rules/test_WildcardResourceRule.py +++ b/tests/rules/test_WildcardResourceRule.py @@ -199,16 +199,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -221,16 +221,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -243,16 +243,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -265,16 +265,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -287,16 +287,38 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", + "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", "dynamodb:PutItem", + "dynamodb:Get*", + }, + resource_ids={"RolePolicy"}, + resource_types={"AWS::IAM::Policy"}, + ), + Failure( + granularity="ACTION", + reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:DeleteResourcePolicy"', + risk_value="MEDIUM", + rule="WildcardResourceRule", + rule_mode="BLOCKING", + actions={ + "dynamodb:Update*", "dynamodb:DescribeStream", - "dynamodb:DescribeTable", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", + "dynamodb:Query", + "dynamodb:Delete*", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -309,16 +331,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -331,16 +353,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -353,16 +375,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -375,16 +397,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -397,16 +419,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -419,16 +441,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -441,16 +463,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -463,16 +485,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -485,16 +507,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -507,16 +529,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -529,16 +551,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -551,16 +573,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -573,16 +595,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -595,16 +617,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -617,16 +639,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -639,16 +661,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -661,16 +683,38 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", + "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", "dynamodb:PutItem", + "dynamodb:Get*", + }, + resource_ids={"RolePolicy"}, + resource_types={"AWS::IAM::Policy"}, + ), + Failure( + granularity="ACTION", + reason='"RolePolicy" is using a wildcard resource in "TheExtremePolicy" for "dynamodb:UpdateKinesisStreamingDestination"', + risk_value="MEDIUM", + rule="WildcardResourceRule", + rule_mode="BLOCKING", + actions={ + "dynamodb:Update*", "dynamodb:DescribeStream", - "dynamodb:DescribeTable", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", + "dynamodb:Query", + "dynamodb:Delete*", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -683,16 +727,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -705,16 +749,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, @@ -727,16 +771,16 @@ def test_multiple_resources_with_wildcard_resources_are_detected(user_and_policy rule="WildcardResourceRule", rule_mode="BLOCKING", actions={ - "dynamodb:CreateTable", - "dynamodb:BatchGet*", - "dynamodb:Scan", "dynamodb:Update*", + "dynamodb:DescribeStream", + "dynamodb:BatchGet*", + "dynamodb:CreateTable", "dynamodb:Query", "dynamodb:Delete*", - "dynamodb:PutItem", - "dynamodb:DescribeStream", - "dynamodb:DescribeTable", "dynamodb:BatchWrite*", + "dynamodb:DescribeTable", + "dynamodb:Scan", + "dynamodb:PutItem", "dynamodb:Get*", }, resource_ids={"RolePolicy"}, diff --git a/tests/test_templates/rules/S3LifecycleConfiguration/allowed_template_malformed_lifecycle_rules.yaml b/tests/test_templates/rules/S3LifecycleConfiguration/allowed_template_malformed_lifecycle_rules.yaml deleted file mode 100644 index e7d158fe..00000000 --- a/tests/test_templates/rules/S3LifecycleConfiguration/allowed_template_malformed_lifecycle_rules.yaml +++ /dev/null @@ -1,10 +0,0 @@ -Resources: - OutputBucket: - Type: AWS::S3::Bucket - Properties: - BucketName: "foo" - AccessControl: BucketOwnerFullControl - LifecycleConfiguration: - # This is not valid for LifecycleConfiguration, but CFRipper will not parse it right now. - - aa - - bb From c1a26ef5c2ce781accf87100157ce98094109d50 Mon Sep 17 00:00:00 2001 From: Ignacio Bolonio <> Date: Tue, 11 Jun 2024 17:14:17 +0200 Subject: [PATCH 51/63] Fix Python 3.8 compatibility --- requirements-dev.txt | 9 ++++++--- requirements-docs.txt | 8 +++++--- requirements.txt | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ed2e71d7..cd492e3e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ -# This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra dev --output-file requirements-dev.txt +# This file was autogenerated by uv via the following command: +# uv pip compile --no-emit-index-url --no-annotate pyproject.toml --extra dev --output-file requirements-dev.txt annotated-types==0.7.0 antlr4-python3-runtime==4.13.1 attrs==23.2.0 @@ -19,6 +19,7 @@ docker==7.1.0 exceptiongroup==1.2.1 graphql-core==3.2.3 idna==3.7 +importlib-resources==6.4.0 iniconfig==2.0.0 jinja2==3.1.4 jmespath==1.0.1 @@ -38,12 +39,13 @@ markupsafe==2.1.5 moto==5.0.9 mpmath==1.3.0 multipart==0.2.4 -networkx==3.2.1 +networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==24.1 pathable==0.4.3 pbr==6.0.0 +pkgutil-resolve-name==1.3.10 pluggy==0.13.1 ply==3.11 py-partiql-parser==0.5.5 @@ -76,3 +78,4 @@ uv==0.2.10 werkzeug==3.0.3 wrapt==1.16.0 xmltodict==0.13.0 +zipp==3.19.2 diff --git a/requirements-docs.txt b/requirements-docs.txt index 29e77499..756af11f 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,5 +1,5 @@ -# This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --extra docs --extra dev --output-file requirements-docs.txt +# This file was autogenerated by uv via the following command: +# uv pip compile --no-emit-index-url --no-annotate pyproject.toml --extra docs --extra dev --output-file requirements-docs.txt annotated-types==0.7.0 antlr4-python3-runtime==4.13.1 attrs==23.2.0 @@ -23,6 +23,7 @@ graphql-core==3.2.3 htmlmin==0.1.12 idna==3.7 importlib-metadata==7.1.0 +importlib-resources==6.4.0 iniconfig==2.0.0 jinja2==3.1.4 jmespath==1.0.1 @@ -50,12 +51,13 @@ mkdocs-minify-plugin==0.5.0 moto==5.0.9 mpmath==1.3.0 multipart==0.2.4 -networkx==3.2.1 +networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==24.1 pathable==0.4.3 pbr==6.0.0 +pkgutil-resolve-name==1.3.10 pluggy==0.13.1 ply==3.11 py-partiql-parser==0.5.5 diff --git a/requirements.txt b/requirements.txt index 1051c38a..628f6b05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -# This file was autogenerated by uv v0.1.2 via the following command: -# uv pip compile --no-emit-index-url --no-annotate -v pyproject.toml --upgrade --output-file requirements.txt +# This file was autogenerated by uv via the following command: +# uv pip compile --no-emit-index-url --no-annotate pyproject.toml --output-file requirements.txt annotated-types==0.7.0 boto3==1.34.123 botocore==1.34.123 From 568c5ae3ec573c904977a95885a951371dd127bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:47:00 +0200 Subject: [PATCH 52/63] Bump jinja2 from 3.1.3 to 3.1.4 (#285) Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/3.1.3...3.1.4) --- updated-dependencies: - dependency-name: jinja2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 3b87b62e62af3232d7ee14b15bfb55f41cf49fbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:57:19 +0000 Subject: [PATCH 53/63] Bump release-drafter/release-drafter from 5 to 6 (#280) --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 56eaca4b..6da732b3 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -27,6 +27,6 @@ jobs: runs-on: ubuntu-latest steps: # Drafts your next Release notes as Pull Requests are merged into "master" - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 4813855090a45159bf690f06e7d9f3856d847aeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:09:19 +0200 Subject: [PATCH 54/63] Bump urllib3 from 1.26.18 to 1.26.19 (#291) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.18 to 1.26.19. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/1.26.19/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.18...1.26.19) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index cd492e3e..5ba0cdfe 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -73,7 +73,7 @@ six==1.16.0 sympy==1.12.1 tomli==2.0.1 typing-extensions==4.12.2 -urllib3==1.26.18 +urllib3==1.26.19 uv==0.2.10 werkzeug==3.0.3 wrapt==1.16.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index 756af11f..f1bd3258 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -89,7 +89,7 @@ sympy==1.12.1 termcolor==2.4.0 tomli==2.0.1 typing-extensions==4.12.2 -urllib3==1.26.18 +urllib3==1.26.19 uv==0.2.10 watchdog==4.0.1 werkzeug==3.0.3 diff --git a/requirements.txt b/requirements.txt index 628f6b05..e6b164f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,4 @@ pyyaml==6.0.2rc1 s3transfer==0.10.1 six==1.16.0 typing-extensions==4.12.2 -urllib3==1.26.18 +urllib3==1.26.19 From 0e18dcea7e757c69a6e8cb0d0459683430516e73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:11:45 +0200 Subject: [PATCH 55/63] Bump certifi from 2024.6.2 to 2024.7.4 (#293) Bumps [certifi](https://github.com/certifi/python-certifi) from 2024.6.2 to 2024.7.4. - [Commits](https://github.com/certifi/python-certifi/compare/2024.06.02...2024.07.04) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: marcsantamaria-sky <137813156+marcsantamaria-sky@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 5ba0cdfe..73bac70e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ aws-sam-translator==1.89.0 aws-xray-sdk==2.14.0 boto3==1.34.123 botocore==1.34.123 -certifi==2024.6.2 +certifi==2024.7.4 cffi==1.16.0 cfn-flip==1.3.0 cfn-lint==0.87.5 diff --git a/requirements-docs.txt b/requirements-docs.txt index f1bd3258..08b875a9 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -7,7 +7,7 @@ aws-sam-translator==1.89.0 aws-xray-sdk==2.14.0 boto3==1.34.123 botocore==1.34.123 -certifi==2024.6.2 +certifi==2024.7.4 cffi==1.16.0 cfn-flip==1.3.0 cfn-lint==0.87.5 From e6858077b0aa66fd832e845149609a29c10de893 Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Wed, 17 Jul 2024 10:54:16 +0200 Subject: [PATCH 56/63] Adding set and sort filter functions (#294) * Initial failing implementation * Remove sorted tests * Add more tests * Add a wrapper for single-arg methods * Add new functions to docs * Update changelog --------- Co-authored-by: marcsantamaria-sky <137813156+marcsantamaria-sky@users.noreply.github.com> --- CHANGELOG.md | 5 ++++ cfripper/config/filter.py | 53 ++++++++++++++++++++++----------- docs/rule_config_and_filters.md | 4 ++- tests/config/test_filter.py | 27 ++++++++++++++--- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c88e4332..5c3be170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.16.0] +### Additions +- Added 2 new filter functions: `set` and `sorted` + + ## [1.15.7] ### Updates - Bumped pycfmodel to use pydantic v2 diff --git a/cfripper/config/filter.py b/cfripper/config/filter.py index 40a4a2b1..b47e0963 100644 --- a/cfripper/config/filter.py +++ b/cfripper/config/filter.py @@ -7,23 +7,25 @@ from cfripper.model.enums import RuleMode, RuleRisk -VALID_FUNCTIONS = [ +VALID_FUNCTIONS = { + "and", + "empty", "eq", - "ne", - "lt", + "exists", + "ge", "gt", + "in", "le", - "ge", + "lt", + "ne", "not", "or", - "and", - "in", + "ref", "regex", "regex:ignorecase", - "exists", - "empty", - "ref", -] + "set", + "sorted", +} logger = logging.getLogger(__file__) @@ -39,22 +41,37 @@ def wrap(*args, **kwargs): return wrap + def single_param_resolver(f): + def wrap(*args, **kwargs): + calculated_parameters = [arg(kwargs) for arg in args] + if len(calculated_parameters) == 1 and isinstance(calculated_parameters[0], (dict, set)): + result = f(*calculated_parameters, **kwargs) + else: + result = f(calculated_parameters, **kwargs) + if debug: + logger.debug(f"{function_name}({', '.join(str(x) for x in calculated_parameters)}) -> {result}") + return result + + return wrap + implemented_filter_functions = { + "and": lambda *args, **kwargs: all(arg(kwargs) for arg in args), + "empty": param_resolver(lambda *args, **kwargs: len(args) == 0), "eq": param_resolver(lambda a, b, **kwargs: a == b), - "ne": param_resolver(lambda a, b, **kwargs: a != b), - "lt": param_resolver(lambda a, b, **kwargs: a < b), + "exists": param_resolver(lambda a, **kwargs: a is not None), + "ge": param_resolver(lambda a, b, **kwargs: a >= b), "gt": param_resolver(lambda a, b, **kwargs: a > b), + "in": param_resolver(lambda a, b, **kwargs: a in b), "le": param_resolver(lambda a, b, **kwargs: a <= b), - "ge": param_resolver(lambda a, b, **kwargs: a >= b), + "lt": param_resolver(lambda a, b, **kwargs: a < b), + "ne": param_resolver(lambda a, b, **kwargs: a != b), "not": param_resolver(lambda a, **kwargs: not a), "or": lambda *args, **kwargs: any(arg(kwargs) for arg in args), - "and": lambda *args, **kwargs: all(arg(kwargs) for arg in args), - "in": param_resolver(lambda a, b, **kwargs: a in b), + "ref": param_resolver(lambda param_name, **kwargs: get(kwargs, param_name)), "regex": param_resolver(lambda *args, **kwargs: bool(re.match(*args))), "regex:ignorecase": param_resolver(lambda *args, **kwargs: bool(re.match(*args, re.IGNORECASE))), - "exists": param_resolver(lambda a, **kwargs: a is not None), - "empty": param_resolver(lambda *args, **kwargs: len(args) == 0), - "ref": param_resolver(lambda param_name, **kwargs: get(kwargs, param_name)), + "set": single_param_resolver(lambda *args, **kwargs: set(*args)), + "sorted": single_param_resolver(lambda *args, **kwargs: sorted(*args)), } return implemented_filter_functions[function_name] diff --git a/docs/rule_config_and_filters.md b/docs/rule_config_and_filters.md index 78e6186c..3a412f37 100644 --- a/docs/rule_config_and_filters.md +++ b/docs/rule_config_and_filters.md @@ -29,7 +29,7 @@ When loading filters from a folder the order is alphabetical. ### Implemented filter functions | Function | Description | Example | -| :----------------: | :-------------------------------------------------------------------------: | :-------------------------------------: | +|:------------------:|:---------------------------------------------------------------------------:|:---------------------------------------:| | `eq` | Same as a == b | `{"eq": ["string", "string"]}` | | `ne` | Same as a != b | `{"ne": ["string", "not_that_string"]}` | | `lt` | Same as a < b | `{"lt": [0, 1]}` | @@ -45,6 +45,8 @@ When loading filters from a folder the order is alphabetical. | `exists` | True if a is not None | `{"exists": None}` | | `empty` | True if len(a) equals 0 | `{"empty": []}` | | `ref` | Get the value at any depth of the context based on the path described by a. | `{"ref": "param_a.param_b"}` | +| `set` | Turns the input into a set | `{"set": [80, 443]}` | +| `sorted` | Return the sorted input as a list | `{"sorted": [80, 443]}` | ### Examples diff --git a/tests/config/test_filter.py b/tests/config/test_filter.py index fe2f11ee..87b87200 100644 --- a/tests/config/test_filter.py +++ b/tests/config/test_filter.py @@ -29,7 +29,7 @@ def template_security_group_firehose_ips(): @pytest.mark.parametrize( - "filter, args, expected_result", + "filter_name, args, expected_result", [ (Filter(eval={"eq": ["string", "string"]}), {}, True), (Filter(eval={"eq": [1, 1]}), {}, True), @@ -219,7 +219,26 @@ def template_security_group_firehose_ips(): (Filter(eval={"ref": "param_a.param_b.param_c"}), {"param_a": {"param_b": {"param_c": [1]}}}, [1]), (Filter(eval={"ref": "param_a.param_b.param_c"}), {"param_a": {"param_b": {"param_c": [-1]}}}, [-1]), (Filter(eval={"ref": "param_a.param_b.param_c"}), {"param_a": {"param_b": {"param_c": [1.0]}}}, [1.0]), - (Filter(eval={"ref": "param_a.param_b.param_c"}), {"param_a": {"param_b": {"param_c": [-1.0]}}}, [-1.0]), + (Filter(eval={"set": []}), {}, set()), + (Filter(eval={"set": {}}), {}, set()), + (Filter(eval={"set": set()}), {}, set()), + (Filter(eval={"set": {"80"}}), {}, {"80"}), + (Filter(eval={"set": ["80"]}), {}, {"80"}), + (Filter(eval={"set": {"80": 100}}), {}, {"80"}), + (Filter(eval={"set": {"80": 100, "90": 100}}), {}, {"80", "90"}), + (Filter(eval={"set": ["80", "443"]}), {}, {"80", "443"}), + (Filter(eval={"set": {"80", "443"}}), {}, {"80", "443"}), + (Filter(eval={"set": ["80", "443", "8080"]}), {}, {"80", "443", "8080"}), + (Filter(eval={"sorted": []}), {}, []), + (Filter(eval={"sorted": {}}), {}, []), + (Filter(eval={"sorted": set()}), {}, []), + (Filter(eval={"sorted": {"80"}}), {}, ["80"]), + (Filter(eval={"sorted": ["80"]}), {}, ["80"]), + (Filter(eval={"sorted": {"80": 100}}), {}, ["80"]), + (Filter(eval={"sorted": {"80": 100, "90": 100}}), {}, ["80", "90"]), + (Filter(eval={"sorted": ["80", "443"]}), {}, ["443", "80"]), + (Filter(eval={"sorted": {"80", "443"}}), {}, ["443", "80"]), + (Filter(eval={"sorted": ["80", "443", "8080"]}), {}, ["443", "80", "8080"]), # Composed (Filter(eval={"eq": [{"ref": "param_a"}, "a"]}), {"param_a": "a"}, True), (Filter(eval={"eq": ["a", {"ref": "param_a"}]}), {"param_a": "a"}, True), @@ -242,8 +261,8 @@ def template_security_group_firehose_ips(): ), ], ) -def test_filter(filter, args, expected_result): - assert filter(**args) == expected_result +def test_filter(filter_name, args, expected_result): + assert filter_name(**args) == expected_result def test_exist_function_and_property_does_not_exist(template_cross_account_role_no_name): From e3bf66e4e90e0e651d483a21b2172d01c249de25 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 17 Jul 2024 10:55:33 +0200 Subject: [PATCH 57/63] Update CHANGELOG.md with missing releases and add PR template (#279) * update changelog with missing releases and add PR template * update changelog for next release --------- Co-authored-by: Ramon --- .github/pull_request_template.md | 7 +++++++ CHANGELOG.md | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..7f7c791c --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,7 @@ +# Description + + + +## Checklist + +- [ ] I have updated the CHANGELOG.md file accordingly diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3be170..6bdefbbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,27 +9,32 @@ All notable changes to this project will be documented in this file. ## [1.15.7] ### Updates - Bumped pycfmodel to use pydantic v2 +### Other updates +- Add PR template @w0rmr1d3r (#279) ## [1.15.6] -## Fixes -- Fix logo displayed in pypi +### Fixes +- Fix logo in pypi @ignaciobolonio (#274) ### Updates -- Bumped python used in readthedocs to 3.9 +- Update .readthedocs.yaml @jsoucheiron (#275) +### Bumps +- Bump actions/setup-python from 4 to 5 (#270) +- Bump cryptography from 42.0.3 to 42.0.4 (#272) ## [1.15.5] ### Changes -- Add dependabot config -- Migrate to `pyproject.toml` +- Migrate to pyproject.toml @jsoucheiron (#269) +- Add dependabot config @w0rmr1d3r (#257) ## [1.15.4] -## Fixes +### Fixes - Fix `KMSKeyWildcardPrincipalRule` to work without a KMS policy - Fix release drafter template to show PR titles ### Updates - Bumped minimum `pycfmodel` version to `0.22.0` ## [1.15.3] -## Changes +### Changes - Update invalid_role_inline_policy_fn_if.json - Improve logging for the exception when applying rule filters - Add release drafter From 7383c7d4bb3975e5f07fcd46f85b81bab737cd05 Mon Sep 17 00:00:00 2001 From: Keira Crafts Date: Thu, 22 Aug 2024 11:14:29 +0100 Subject: [PATCH 58/63] removed user and password from pypi-release.yml --- .github/workflows/pypi-release.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 2b3f77b3..646cd0db 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -34,7 +34,4 @@ jobs: twine check --strict dist/* - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file From db51acc08766c3eb69c51c4b8d11acab4be69aff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:53:42 +0200 Subject: [PATCH 59/63] Bump cryptography from 42.0.8 to 43.0.1 (#301) Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.8 to 43.0.1. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/42.0.8...43.0.1) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 73bac70e..205d379e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,7 +14,7 @@ cfn-lint==0.87.5 charset-normalizer==3.3.2 click==8.1.7 coverage==7.5.3 -cryptography==42.0.8 +cryptography==43.0.1 docker==7.1.0 exceptiongroup==1.2.1 graphql-core==3.2.3 diff --git a/requirements-docs.txt b/requirements-docs.txt index 08b875a9..802671f4 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -14,7 +14,7 @@ cfn-lint==0.87.5 charset-normalizer==3.3.2 click==8.1.7 coverage==7.5.3 -cryptography==42.0.8 +cryptography==43.0.1 csscompressor==0.9.5 docker==7.1.0 exceptiongroup==1.2.1 From 378b7734cf286c5dc2e71701a5761362366c250d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:01:46 +0100 Subject: [PATCH 60/63] Bump moto from 5.0.9 to 5.0.16 (#302) Bumps [moto](https://github.com/getmoto/moto) from 5.0.9 to 5.0.16. - [Release notes](https://github.com/getmoto/moto/releases) - [Changelog](https://github.com/getmoto/moto/blob/master/CHANGELOG.md) - [Commits](https://github.com/getmoto/moto/compare/5.0.9...5.0.16) --- updated-dependencies: - dependency-name: moto dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 205d379e..d5ffc945 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -36,7 +36,7 @@ jsonschema-specifications==2023.12.1 junit-xml==1.9 lazy-object-proxy==1.10.0 markupsafe==2.1.5 -moto==5.0.9 +moto==5.0.16 mpmath==1.3.0 multipart==0.2.4 networkx==3.1 diff --git a/requirements-docs.txt b/requirements-docs.txt index 802671f4..2c68ab09 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -48,7 +48,7 @@ mkdocs-macros-plugin==0.7.0 mkdocs-material==8.2.8 mkdocs-material-extensions==1.0.3 mkdocs-minify-plugin==0.5.0 -moto==5.0.9 +moto==5.0.16 mpmath==1.3.0 multipart==0.2.4 networkx==3.1 From b579bca8e39983c0d97075e7b36cd62a2178a0dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 19:33:45 +0100 Subject: [PATCH 61/63] Bump werkzeug from 3.0.3 to 3.0.6 (#303) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.3 to 3.0.6. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.0.3...3.0.6) --- updated-dependencies: - dependency-name: werkzeug dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jordi Soucheiron --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index d5ffc945..8102f828 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -75,7 +75,7 @@ tomli==2.0.1 typing-extensions==4.12.2 urllib3==1.26.19 uv==0.2.10 -werkzeug==3.0.3 +werkzeug==3.0.6 wrapt==1.16.0 xmltodict==0.13.0 zipp==3.19.2 diff --git a/requirements-docs.txt b/requirements-docs.txt index 2c68ab09..20bbca34 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -92,7 +92,7 @@ typing-extensions==4.12.2 urllib3==1.26.19 uv==0.2.10 watchdog==4.0.1 -werkzeug==3.0.3 +werkzeug==3.0.6 wrapt==1.16.0 xmltodict==0.13.0 zipp==3.19.2 From b49c3b690dc043f06f2665ac1d1a6674b1d97ecd Mon Sep 17 00:00:00 2001 From: Jordi Soucheiron Date: Mon, 4 Nov 2024 18:11:41 +0100 Subject: [PATCH 62/63] Remove 3.8 support add 3.13 support (#305) * Remove 3.8 support add 3.13 support * Update changelog * Bump dependencies --- .github/workflows/lint-and-test.yml | 2 +- .github/workflows/pypi-release.yml | 2 +- CHANGELOG.md | 7 ++- pyproject.toml | 4 +- requirements-dev.txt | 87 +++++++++++++------------- requirements-docs.txt | 95 ++++++++++++++--------------- requirements.txt | 16 ++--- 7 files changed, 104 insertions(+), 109 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index ecdbf111..ac1aa702 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] name: Python ${{ matrix.python-version }} diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 646cd0db..7e36ce6a 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -20,7 +20,7 @@ jobs: - name: Setup python uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.9' - name: Install dependencies run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bdefbbe..07668c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,16 @@ # Changelog All notable changes to this project will be documented in this file. +## [1.17.0] +### Additions +- Add support for python 3.13 +### Removals +- Remove support for python 3.8 + ## [1.16.0] ### Additions - Added 2 new filter functions: `set` and `sorted` - ## [1.15.7] ### Updates - Bumped pycfmodel to use pydantic v2 diff --git a/pyproject.toml b/pyproject.toml index 6f33a24d..fa85dcb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "cfripper" description="Library and CLI tool for analysing CloudFormation templates and check them for security compliance." readme = "README.md" -requires-python = ">=3.8.0" +requires-python = ">=3.9.0" dynamic = ["version"] license = { file = "LICENSE.md" } authors = [ @@ -26,11 +26,11 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Security" ] diff --git a/requirements-dev.txt b/requirements-dev.txt index 8102f828..6762ea2c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,81 +1,76 @@ # This file was autogenerated by uv via the following command: # uv pip compile --no-emit-index-url --no-annotate pyproject.toml --extra dev --output-file requirements-dev.txt annotated-types==0.7.0 -antlr4-python3-runtime==4.13.1 -attrs==23.2.0 -aws-sam-translator==1.89.0 +antlr4-python3-runtime==4.13.2 +attrs==24.2.0 +aws-sam-translator==1.91.0 aws-xray-sdk==2.14.0 -boto3==1.34.123 -botocore==1.34.123 -certifi==2024.7.4 -cffi==1.16.0 +boto3==1.35.54 +botocore==1.35.54 +certifi==2024.8.30 +cffi==1.17.1 cfn-flip==1.3.0 -cfn-lint==0.87.5 -charset-normalizer==3.3.2 +cfn-lint==1.18.3 +charset-normalizer==3.4.0 click==8.1.7 -coverage==7.5.3 -cryptography==43.0.1 +coverage==7.6.1 +cryptography==43.0.3 docker==7.1.0 -exceptiongroup==1.2.1 -graphql-core==3.2.3 -idna==3.7 -importlib-resources==6.4.0 +exceptiongroup==1.2.2 +graphql-core==3.2.5 +idna==3.10 +importlib-resources==6.4.5 iniconfig==2.0.0 jinja2==3.1.4 jmespath==1.0.1 -joserfc==0.11.1 -jschema-to-python==1.2.3 -jsondiff==2.0.0 +joserfc==1.0.0 +jsondiff==2.2.1 jsonpatch==1.33 -jsonpath-ng==1.6.1 -jsonpickle==3.2.1 +jsonpath-ng==1.7.0 jsonpointer==3.0.0 -jsonschema==4.22.0 -jsonschema-path==0.3.2 +jsonschema==4.23.0 +jsonschema-path==0.3.3 jsonschema-specifications==2023.12.1 -junit-xml==1.9 lazy-object-proxy==1.10.0 markupsafe==2.1.5 -moto==5.0.16 +moto==5.0.18 mpmath==1.3.0 -multipart==0.2.4 +multipart==1.1.0 networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==24.1 pathable==0.4.3 -pbr==6.0.0 pkgutil-resolve-name==1.3.10 pluggy==0.13.1 ply==3.11 -py-partiql-parser==0.5.5 +py-partiql-parser==0.5.6 pycfmodel==1.0.0 pycparser==2.22 -pydantic==2.7.3 -pydantic-core==2.18.4 -pydash==8.0.1 -pyparsing==3.1.2 +pydantic==2.9.2 +pydantic-core==2.23.4 +pydash==8.0.3 +pyparsing==3.1.4 pytest==7.4.4 pytest-cov==5.0.0 python-dateutil==2.9.0.post0 -pyyaml==6.0.2rc1 -referencing==0.31.1 -regex==2024.5.15 +pyyaml==6.0.2 +referencing==0.35.1 +regex==2024.9.11 requests==2.32.3 -responses==0.25.2 +responses==0.25.3 rfc3339-validator==0.1.4 -rpds-py==0.18.1 -ruff==0.4.8 -s3transfer==0.10.1 -sarif-om==1.0.4 -setuptools==70.0.0 +rpds-py==0.20.1 +ruff==0.7.2 +s3transfer==0.10.3 +setuptools==75.3.0 six==1.16.0 -sympy==1.12.1 -tomli==2.0.1 +sympy==1.13.3 +tomli==2.0.2 typing-extensions==4.12.2 -urllib3==1.26.19 -uv==0.2.10 +urllib3==1.26.20 +uv==0.4.29 werkzeug==3.0.6 wrapt==1.16.0 -xmltodict==0.13.0 -zipp==3.19.2 +xmltodict==0.14.2 +zipp==3.20.2 diff --git a/requirements-docs.txt b/requirements-docs.txt index 20bbca34..a65ff0fd 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,46 +1,43 @@ # This file was autogenerated by uv via the following command: # uv pip compile --no-emit-index-url --no-annotate pyproject.toml --extra docs --extra dev --output-file requirements-docs.txt annotated-types==0.7.0 -antlr4-python3-runtime==4.13.1 -attrs==23.2.0 -aws-sam-translator==1.89.0 +antlr4-python3-runtime==4.13.2 +attrs==24.2.0 +aws-sam-translator==1.91.0 aws-xray-sdk==2.14.0 -boto3==1.34.123 -botocore==1.34.123 -certifi==2024.7.4 -cffi==1.16.0 +boto3==1.35.54 +botocore==1.35.54 +certifi==2024.8.30 +cffi==1.17.1 cfn-flip==1.3.0 -cfn-lint==0.87.5 -charset-normalizer==3.3.2 +cfn-lint==1.18.3 +charset-normalizer==3.4.0 click==8.1.7 -coverage==7.5.3 -cryptography==43.0.1 +coverage==7.6.1 +cryptography==43.0.3 csscompressor==0.9.5 docker==7.1.0 -exceptiongroup==1.2.1 +exceptiongroup==1.2.2 ghp-import==2.1.0 -graphql-core==3.2.3 +graphql-core==3.2.5 htmlmin==0.1.12 -idna==3.7 -importlib-metadata==7.1.0 -importlib-resources==6.4.0 +idna==3.10 +importlib-metadata==8.5.0 +importlib-resources==6.4.5 iniconfig==2.0.0 jinja2==3.1.4 jmespath==1.0.1 -joserfc==0.11.1 -jschema-to-python==1.2.3 +joserfc==1.0.0 jsmin==3.0.1 -jsondiff==2.0.0 +jsondiff==2.2.1 jsonpatch==1.33 -jsonpath-ng==1.6.1 -jsonpickle==3.2.1 +jsonpath-ng==1.7.0 jsonpointer==3.0.0 -jsonschema==4.22.0 -jsonschema-path==0.3.2 +jsonschema==4.23.0 +jsonschema-path==0.3.3 jsonschema-specifications==2023.12.1 -junit-xml==1.9 lazy-object-proxy==1.10.0 -markdown==3.6 +markdown==3.7 markupsafe==2.1.5 mergedeep==1.3.4 mkdocs==1.3.0 @@ -48,51 +45,49 @@ mkdocs-macros-plugin==0.7.0 mkdocs-material==8.2.8 mkdocs-material-extensions==1.0.3 mkdocs-minify-plugin==0.5.0 -moto==5.0.16 +moto==5.0.18 mpmath==1.3.0 -multipart==0.2.4 +multipart==1.1.0 networkx==3.1 openapi-schema-validator==0.6.2 openapi-spec-validator==0.7.1 packaging==24.1 pathable==0.4.3 -pbr==6.0.0 pkgutil-resolve-name==1.3.10 pluggy==0.13.1 ply==3.11 -py-partiql-parser==0.5.5 +py-partiql-parser==0.5.6 pycfmodel==1.0.0 pycparser==2.22 -pydantic==2.7.3 -pydantic-core==2.18.4 -pydash==8.0.1 +pydantic==2.9.2 +pydantic-core==2.23.4 +pydash==8.0.3 pygments==2.18.0 -pymdown-extensions==10.8.1 -pyparsing==3.1.2 +pymdown-extensions==10.12 +pyparsing==3.1.4 pytest==7.4.4 pytest-cov==5.0.0 python-dateutil==2.9.0.post0 -pyyaml==6.0.2rc1 +pyyaml==6.0.2 pyyaml-env-tag==0.1 -referencing==0.31.1 -regex==2024.5.15 +referencing==0.35.1 +regex==2024.9.11 requests==2.32.3 -responses==0.25.2 +responses==0.25.3 rfc3339-validator==0.1.4 -rpds-py==0.18.1 -ruff==0.4.8 -s3transfer==0.10.1 -sarif-om==1.0.4 -setuptools==70.0.0 +rpds-py==0.20.1 +ruff==0.7.2 +s3transfer==0.10.3 +setuptools==75.3.0 six==1.16.0 -sympy==1.12.1 +sympy==1.13.3 termcolor==2.4.0 -tomli==2.0.1 +tomli==2.0.2 typing-extensions==4.12.2 -urllib3==1.26.19 -uv==0.2.10 -watchdog==4.0.1 +urllib3==1.26.20 +uv==0.4.29 +watchdog==4.0.2 werkzeug==3.0.6 wrapt==1.16.0 -xmltodict==0.13.0 -zipp==3.19.2 +xmltodict==0.14.2 +zipp==3.20.2 diff --git a/requirements.txt b/requirements.txt index e6b164f8..83d494ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,19 @@ # This file was autogenerated by uv via the following command: # uv pip compile --no-emit-index-url --no-annotate pyproject.toml --output-file requirements.txt annotated-types==0.7.0 -boto3==1.34.123 -botocore==1.34.123 +boto3==1.35.54 +botocore==1.35.54 cfn-flip==1.3.0 click==8.1.7 jmespath==1.0.1 pluggy==0.13.1 pycfmodel==1.0.0 -pydantic==2.7.3 -pydantic-core==2.18.4 -pydash==8.0.1 +pydantic==2.9.2 +pydantic-core==2.23.4 +pydash==8.0.3 python-dateutil==2.9.0.post0 -pyyaml==6.0.2rc1 -s3transfer==0.10.1 +pyyaml==6.0.2 +s3transfer==0.10.3 six==1.16.0 typing-extensions==4.12.2 -urllib3==1.26.19 +urllib3==1.26.20 From 85dbf6cbf93a86af01cdf1781794990a441ff902 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:58:18 +0100 Subject: [PATCH 63/63] Bump werkzeug from 3.0.3 to 3.1.1 (#304) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.3 to 3.1.1. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.0.3...3.1.1) --- updated-dependencies: - dependency-name: werkzeug dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- requirements-docs.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6762ea2c..b4134c79 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -70,7 +70,7 @@ tomli==2.0.2 typing-extensions==4.12.2 urllib3==1.26.20 uv==0.4.29 -werkzeug==3.0.6 +werkzeug==3.1.1 wrapt==1.16.0 xmltodict==0.14.2 zipp==3.20.2 diff --git a/requirements-docs.txt b/requirements-docs.txt index a65ff0fd..acd5f5c6 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -87,7 +87,7 @@ typing-extensions==4.12.2 urllib3==1.26.20 uv==0.4.29 watchdog==4.0.2 -werkzeug==3.0.6 +werkzeug==3.1.1 wrapt==1.16.0 xmltodict==0.14.2 zipp==3.20.2