From c0318bf923dc95620c0bcf74d7bae822604f7d53 Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 00:01:59 +1000 Subject: [PATCH 1/8] Revert "[pre-commit.ci] pre-commit autoupdate (#1467)" This reverts commit 906005d36c9b773894c075203b898f42988e229f. --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4390a8d96..08ae2373d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: hooks: - id: yamllint - repo: https://github.com/awslabs/cfn-python-lint - rev: v1.2.5a9 + rev: v0.86.4 hooks: - id: cfn-python-lint args: @@ -47,7 +47,7 @@ repos: language_version: python3.10 args: ['--check'] - repo: https://github.com/sirosen/check-jsonschema - rev: 0.28.4 + rev: 0.28.2 hooks: - id: check-github-workflows - id: check-github-actions From d113809ca16bbb5a73e3e869bfb7e79a9adba8ea Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 15:59:45 +1000 Subject: [PATCH 2/8] [Resolve #1468] Cast parameters to strings In already-resolved and merged issue #1443 we implemented parameter validation. Subsequent discussion led to a consensus that it would be better to not only validate parameters, but also cast where applicable to string. This will lead to a cleaner user experience for most Sceptre users where parameters passed as ints, floats and bools in their YAML values files are cast to strings first and then sent to CloudFormation, since CloudFormation's API is unable to handle other types. This PR changes the behaviour of the `_ensure_parameters` method in the Stack class to handle casting to strings where applicable instead of only validating. --- sceptre/stack.py | 19 ++++++++++++++++--- tests/test_stack.py | 13 ++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sceptre/stack.py b/sceptre/stack.py index fa5639a8b..7c2967577 100644 --- a/sceptre/stack.py +++ b/sceptre/stack.py @@ -281,6 +281,17 @@ def _ensure_parameters( ) -> Dict[str, Union[str, List[Union[str, Resolver]], Resolver]]: """Ensure CloudFormation parameters are of valid types""" + def cast_value(value: Any) -> Union[str, List[Union[str, Resolver]], Resolver]: + if isinstance(value, bool): + return "true" if value else "false" + elif isinstance(value, (int, float)): + return str(value) + elif isinstance(value, list): + return [cast_value(item) for item in value] + elif isinstance(value, Resolver): + return value + return value + def is_valid(value: Any) -> bool: return ( isinstance(value, str) @@ -294,11 +305,13 @@ def is_valid(value: Any) -> bool: or isinstance(value, Resolver) ) - if not all(is_valid(value) for value in parameters.values()): + casted_parameters = {k: cast_value(v) for k, v in parameters.items()} + + if not all(is_valid(value) for value in casted_parameters.values()): raise InvalidConfigFileError( - f"{self.name}: Values for parameters must be strings, lists or resolvers, got {parameters}" + f"{self.name}: Values for parameters must be strings, lists or resolvers, got {casted_parameters}" ) - return parameters + return casted_parameters def __repr__(self): return ( diff --git a/tests/test_stack.py b/tests/test_stack.py index 6f67e08cd..33415f478 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -188,15 +188,7 @@ def test_init__non_boolean_obsolete_value__raises_invalid_config_file_error(self obsolete="true", ) - @pytest.mark.parametrize( - "parameters", - [ - {"someNum": 1}, - {"someBool": True}, - {"aBadList": [1, 2, 3]}, - {"aDict": {"foo": "bar"}}, - ], - ) + @pytest.mark.parametrize("parameters", [{"aDict": {"foo": "bar"}}]) def test_init__invalid_parameters_raise_invalid_config_file_error(self, parameters): with pytest.raises(InvalidConfigFileError): Stack( @@ -211,8 +203,11 @@ def test_init__invalid_parameters_raise_invalid_config_file_error(self, paramete "parameters", [ {"someNum": "1"}, + {"someNum": 1}, {"someBool": "true"}, + {"someOtherBool": True}, {"aList": ["aString", FakeResolver()]}, + {"anotherList": [1, 2, 3]}, {"aResolver": FakeResolver()}, ], ) From df5474b0f9a10830e4919095d053ad685312da1a Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 16:51:22 +1000 Subject: [PATCH 3/8] more --- tests/test_stack.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/test_stack.py b/tests/test_stack.py index 33415f478..eeddf7451 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -188,7 +188,10 @@ def test_init__non_boolean_obsolete_value__raises_invalid_config_file_error(self obsolete="true", ) - @pytest.mark.parametrize("parameters", [{"aDict": {"foo": "bar"}}]) + @pytest.mark.parametrize( + "parameters", + [{"Dict": {"foo": "bar"}}, {"List": ["of", "stuff", {"including": "aDict"}]}], + ) def test_init__invalid_parameters_raise_invalid_config_file_error(self, parameters): with pytest.raises(InvalidConfigFileError): Stack( @@ -202,13 +205,13 @@ def test_init__invalid_parameters_raise_invalid_config_file_error(self, paramete @pytest.mark.parametrize( "parameters", [ - {"someNum": "1"}, - {"someNum": 1}, - {"someBool": "true"}, - {"someOtherBool": True}, - {"aList": ["aString", FakeResolver()]}, - {"anotherList": [1, 2, 3]}, - {"aResolver": FakeResolver()}, + {"IntAsString": "1"}, + {"Int": 1}, + {"BoolAsString": "true"}, + {"Bool": True}, + {"List": ["aStringAndA", FakeResolver()]}, + {"ListOfInts": [1, 2, 3]}, + {"Resolver": FakeResolver()}, ], ) def test_init__valid_parameters_do_not_raise_invalid_config_file_error( From c52ddb21b7f7e61d90dbbb653de0d9bcdc141063 Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 18:26:34 +1000 Subject: [PATCH 4/8] Revert "Revert "[pre-commit.ci] pre-commit autoupdate (#1467)"" This reverts commit c0318bf923dc95620c0bcf74d7bae822604f7d53. --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08ae2373d..4390a8d96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: hooks: - id: yamllint - repo: https://github.com/awslabs/cfn-python-lint - rev: v0.86.4 + rev: v1.2.5a9 hooks: - id: cfn-python-lint args: @@ -47,7 +47,7 @@ repos: language_version: python3.10 args: ['--check'] - repo: https://github.com/sirosen/check-jsonschema - rev: 0.28.2 + rev: 0.28.4 hooks: - id: check-github-workflows - id: check-github-actions From 47f93758cd49e3db76434997ba4b7ef85190120e Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 18:26:45 +1000 Subject: [PATCH 5/8] more --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4390a8d96..5daa10ba4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,7 +28,7 @@ repos: exclude: | (?x)( ^integration-tests/sceptre-project/config/| - ^integration-tests/sceptre-project/templates/jinja/| + ^integration-tests/sceptre-project/templates/| ^tests/fixtures-vpc/config/| ^tests/fixtures/config/| ^temp/| From 91f3fd059db6753ca5804ab71ebd339fe12664bb Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 18:31:27 +1000 Subject: [PATCH 6/8] dummy --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f47630a17..a1b306c54 100644 --- a/README.md +++ b/README.md @@ -282,3 +282,4 @@ See our [Contributing Guide](CONTRIBUTING.md) [![GoDaddy](sponsors/godaddy_logo.png "GoDaddy")](https://www.godaddy.com) [![Cloudreach](sponsors/cloudreach_logo.png "Cloudreach")](https://www.cloudreach.com) + From 20dc475a8a6ea9b82367dc47543470835c94f949 Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sun, 2 Jun 2024 18:31:34 +1000 Subject: [PATCH 7/8] Revert "dummy" This reverts commit 91f3fd059db6753ca5804ab71ebd339fe12664bb. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index a1b306c54..f47630a17 100644 --- a/README.md +++ b/README.md @@ -282,4 +282,3 @@ See our [Contributing Guide](CONTRIBUTING.md) [![GoDaddy](sponsors/godaddy_logo.png "GoDaddy")](https://www.godaddy.com) [![Cloudreach](sponsors/cloudreach_logo.png "Cloudreach")](https://www.cloudreach.com) - From 4f0c7acf6698f9886348d25a5feaf60a9abcdc65 Mon Sep 17 00:00:00 2001 From: Alex Harvey Date: Sat, 29 Jun 2024 12:27:13 +1000 Subject: [PATCH 8/8] rename-method --- sceptre/stack.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sceptre/stack.py b/sceptre/stack.py index 7c2967577..f085ced7f 100644 --- a/sceptre/stack.py +++ b/sceptre/stack.py @@ -263,7 +263,7 @@ def __init__( ) self.s3_details = s3_details - self.parameters = self._ensure_parameters(parameters or {}) + self.parameters = self._cast_parameters(parameters or {}) self.sceptre_user_data = sceptre_user_data or {} self.notifications = notifications or [] @@ -276,10 +276,10 @@ def _ensure_boolean(self, config_name: str, value: Any) -> bool: ) return value - def _ensure_parameters( + def _cast_parameters( self, parameters: Dict[str, Any] ) -> Dict[str, Union[str, List[Union[str, Resolver]], Resolver]]: - """Ensure CloudFormation parameters are of valid types""" + """Cast CloudFormation parameters to valid types""" def cast_value(value: Any) -> Union[str, List[Union[str, Resolver]], Resolver]: if isinstance(value, bool): @@ -311,6 +311,7 @@ def is_valid(value: Any) -> bool: raise InvalidConfigFileError( f"{self.name}: Values for parameters must be strings, lists or resolvers, got {casted_parameters}" ) + return casted_parameters def __repr__(self):