Skip to content

Commit ad52544

Browse files
authored
Merge pull request #53 from awslabs/feat/cli-deploy-parameter-format
New feature: different formats for parameters
2 parents d617a8e + 9c49909 commit ad52544

File tree

8 files changed

+228
-23
lines changed

8 files changed

+228
-23
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Exits with a non-zero error code if any findings categorized as blocking are fou
7777
| --template-path | Yes | FILE_NAME | The path to the CloudFormation template. |
7878
| --region | Yes | REGION | The destination region the resources will be deployed to. |
7979
| --parameters | | KEY=VALUE [KEY=VALUE ...] | Keys and values for CloudFormation template parameters. Only parameters that are referenced by IAM policies in the template are required. |
80-
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values, a stack policy, and tags. Only parameters are used from this file. Everything else is ignored. Identical values passed in the --parameters flag override parameters in this file. See CloudFormation documentation for file format: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15
80+
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values. Identical values passed in the --parameters flag override parameters in this file. Supports three formats: the [CodePipeline template configuration file](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15) format (`{"Parameters": {"Key": "Value"}}`), the [CloudFormation parameter file](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy.html) format (`[{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]`), and a simple Key=Value string array (`["Key1=Value1", "Key2=Value2"]`).
8181
| --profile | | PROFILE | The named profile to use for AWS API calls. |
8282
| --enable-logging | | | Enables log output to stdout |
8383
| --ignore-finding | | FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE | Allow validation failures to be ignored. Specify as a comma separated list of findings to be ignored. Can be individual finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name (e.g. "MyResource"), or a combination of both separated by a period.(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE"). Names of finding codes may change in IAM Access Analyzer over time.
@@ -100,7 +100,7 @@ Parses IAM identity-based and resource-based policies from AWS CloudFormation te
100100
| --template-path | Yes | FILE_NAME | The path to the CloudFormation template. |
101101
| --region | Yes | REGION | The destination region the resources will be deployed to. |
102102
| --parameters | | KEY=VALUE [KEY=VALUE ...] | Keys and values for CloudFormation template parameters. Only parameters that are referenced by IAM policies in the template are required. |
103-
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values, a stack policy, and tags. Only parameters are used from this file. Everything else is ignored. Identical values passed in the --parameters flag override parameters in this file. See CloudFormation documentation for file format: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15
103+
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values. Identical values passed in the --parameters flag override parameters in this file. Supports three formats: the [CodePipeline template configuration file](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15) format (`{"Parameters": {"Key": "Value"}}`), the [CloudFormation parameter file](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy.html) format (`[{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]`), and a simple Key=Value string array (`["Key1=Value1", "Key2=Value2"]`).
104104
| --profile | | PROFILE | The named profile to use for AWS API calls. |
105105
| --enable-logging | | | Enables log output to stdout |
106106
| --ignore-finding | | FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE | Allow validation failures to be ignored. Specify as a comma separated list of findings to be ignored. Can be individual finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name (e.g. "MyResource"), or a combination of both separated by a period.(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE"). Names of finding codes may change in IAM Access Analyzer over time.
@@ -122,7 +122,7 @@ Parses IAM identity-based and resource-based policies from AWS CloudFormation te
122122
| --template-path | Yes | FILE_NAME | The path to the CloudFormation template. |
123123
| --region | Yes | REGION | The destination region the resources will be deployed to. |
124124
| --parameters | | KEY=VALUE [KEY=VALUE ...] | Keys and values for CloudFormation template parameters. Only parameters that are referenced by IAM policies in the template are required. |
125-
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values, a stack policy, and tags. Only parameters are used from this file. Everything else is ignored. Identical values passed in the --parameters flag override parameters in this file. See CloudFormation documentation for file format: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15
125+
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values. Identical values passed in the --parameters flag override parameters in this file. Supports three formats: the [CodePipeline template configuration file](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15) format (`{"Parameters": {"Key": "Value"}}`), the [CloudFormation parameter file](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy.html) format (`[{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]`), and a simple Key=Value string array (`["Key1=Value1", "Key2=Value2"]`).
126126
| --profile | | PROFILE | The named profile to use for AWS API calls. |
127127
| --enable-logging | | | Enables log output to stdout |
128128
| --ignore-finding | | FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE | Allow validation failures to be ignored. Specify as a comma separated list of findings to be ignored. Can be individual finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name (e.g. "MyResource"), or a combination of both separated by a period.(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE"). Names of finding codes may change in IAM Access Analyzer over time.
@@ -144,7 +144,7 @@ Parses resource-based policies from AWS CloudFormation templates. Then runs the
144144
| --template-path | Yes | FILE_NAME | The path to the CloudFormation template. |
145145
| --region | Yes | REGION | The destination region the resources will be deployed to. |
146146
| --parameters | | KEY=VALUE [KEY=VALUE ...] | Keys and values for CloudFormation template parameters. Only parameters that are referenced by IAM policies in the template are required. |
147-
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values, a stack policy, and tags. Only parameters are used from this file. Everything else is ignored. Identical values passed in the --parameters flag override parameters in this file. See CloudFormation documentation for file format: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15
147+
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values. Identical values passed in the --parameters flag override parameters in this file. Supports three formats: the [CodePipeline template configuration file](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15) format (`{"Parameters": {"Key": "Value"}}`), the [CloudFormation parameter file](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy.html) format (`[{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]`), and a simple Key=Value string array (`["Key1=Value1", "Key2=Value2"]`).
148148
| --profile | | PROFILE | The named profile to use for AWS API calls. |
149149
| --enable-logging | | | Enables log output to stdout |
150150
| --ignore-finding | | FINDING_CODE,RESOURCE_NAME,RESOURCE_NAME.FINDING_CODE | Allow validation failures to be ignored. Specify as a comma separated list of findings to be ignored. Can be individual finding codes (e.g. "PASS_ROLE_WITH_STAR_IN_RESOURCE"), a specific resource name (e.g. "MyResource"), or a combination of both separated by a period.(e.g. "MyResource.PASS_ROLE_WITH_STAR_IN_RESOURCE"). Names of finding codes may change in IAM Access Analyzer over time.
@@ -165,7 +165,7 @@ Parses IAM identity-based and resource-based policies from AWS CloudFormation te
165165
| --template-path | Yes | FILE_NAME | The path to the CloudFormation template. |
166166
| --region | Yes | REGION | The destination region the resources will be deployed to. |
167167
| --parameters | | KEY=VALUE [KEY=VALUE ...] | Keys and values for CloudFormation template parameters. Only parameters that are referenced by IAM policies in the template are required. |
168-
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values, a stack policy, and tags. Everything except for parameters are ignored from this file. Identical values passed in the --parameters flag override parameters in this file. See CloudFormation documentation for file format: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15
168+
| --template-configuration-file | | FILE_PATH.json | A JSON formatted file that specifies template parameter values. Identical values passed in the --parameters flag override parameters in this file. Supports three formats: the [CodePipeline template configuration file](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15) format (`{"Parameters": {"Key": "Value"}}`), the [CloudFormation parameter file](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy.html) format (`[{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]`), and a simple Key=Value string array (`["Key1=Value1", "Key2=Value2"]`).
169169
| --profile | | PROFILE | The named profile to use for AWS API calls. |
170170
| --enable-logging | | | Enables log output to stdout |
171171
| --allow-dynamic-ref-without-version | | | Override the default behavior and allow dynamic SSM references without version numbers. The version number ensures that the SSM parameter value that was validated is the one that is deployed. |

cfn_policy_validator/main.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,13 @@ def main(args=None):
111111
' that are referenced by IAM policies are required.', default={})
112112

113113
parent_parser.add_argument('--template-configuration-file', metavar='FILE_PATH.json', dest="template_configuration_file",
114-
help="A JSON formatted file that specifies template parameter values, a stack policy, and tags."
115-
"Everything but parameters are ignored from this file. Identical values passed in "
116-
"the --parameters flag override parameters in this file\n"
117-
"See CloudFormation documentation on format for this file: "
118-
"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15")
114+
help="A JSON formatted file that specifies template parameter values. "
115+
"Identical values passed in the --parameters flag override parameters in this file.\n"
116+
"Supports multiple formats:\n"
117+
" - CodePipeline configuration: {\"Parameters\": {\"Key\": \"Value\"}}\n"
118+
" - CloudFormation-style list: [{\"ParameterKey\": \"Key\", \"ParameterValue\": \"Value\"}, ...]\n"
119+
" - Key=Value string list: [\"Key1=Value1\", \"Key2=Value2\"]\n"
120+
"See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15")
119121

120122
parent_parser.add_argument('--profile', help='The named profile to use for AWS API calls.')
121123

cfn_policy_validator/parameters.py

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,9 @@ def merge(parameters, template_configuration_file_path):
2020
Merge parameters passed in via the parameters argument with parameters from the template configuration file.
2121
"""
2222

23-
template_configuration_file = {}
23+
parameters_from_config_file = {}
2424
if template_configuration_file_path is not None:
25-
template_configuration_file = _read_template_configuration_file(template_configuration_file_path)
26-
27-
parameters_from_config_file = template_configuration_file.get('Parameters', {})
28-
if not isinstance(parameters_from_config_file, dict):
29-
raise ApplicationError(f'The value for "Parameters" in the template configuration value must be a JSON object.\n'
30-
'See CloudFormation documentation on format for this file: '
31-
'"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15"')
25+
parameters_from_config_file = _read_parameters_from_file(template_configuration_file_path)
3226

3327
if parameters is None:
3428
parameters = {}
@@ -40,15 +34,100 @@ def merge(parameters, template_configuration_file_path):
4034
return parameters_from_config_file
4135

4236

43-
def _read_template_configuration_file(template_configuration_file_path):
37+
def _read_parameters_from_file(file_path):
38+
"""
39+
Read parameters from a configuration file. Supports multiple formats:
40+
41+
1. CodePipeline template configuration file (existing format):
42+
{"Parameters": {"Key1": "Value1", "Key2": "Value2"}}
43+
44+
2. CloudFormation-style parameter list:
45+
[{"ParameterKey": "Key1", "ParameterValue": "Value1"}, ...]
46+
47+
3. Key=Value string list (as used by AWS CLI deploy --parameter-overrides):
48+
["Key1=Value1", "Key2=Value2"]
49+
"""
50+
parsed = _read_json_file(file_path)
51+
return _normalize_parameters(parsed)
52+
53+
54+
def _read_json_file(file_path):
4455
try:
45-
with open(template_configuration_file_path, 'r') as stream:
56+
with open(file_path, 'r') as stream:
4657
raw_file = stream.read()
4758
return json.loads(raw_file)
4859
except FileNotFoundError:
49-
raise ApplicationError(f'Template configuration file not found: {template_configuration_file_path}')
60+
raise ApplicationError(f'Template configuration file not found: {file_path}')
5061
except JSONDecodeError:
51-
raise ApplicationError(f'Template configuration file contains invalid json: {template_configuration_file_path}')
62+
raise ApplicationError(f'Template configuration file contains invalid json: {file_path}')
63+
64+
65+
def _normalize_parameters(parsed):
66+
"""
67+
Detect the format of the parsed JSON and normalize to a flat {key: value} dict.
68+
"""
69+
70+
# Format 1: CodePipeline template configuration file - {"Parameters": {"Key": "Value"}}
71+
if isinstance(parsed, dict):
72+
parameters = parsed.get('Parameters', {})
73+
if not isinstance(parameters, dict):
74+
raise ApplicationError(
75+
'The value for "Parameters" in the template configuration file must be a JSON object.\n'
76+
'See CloudFormation documentation on format for this file: '
77+
'"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c21c15c15"'
78+
)
79+
return parameters
80+
81+
# Format 2 & 3: JSON array
82+
if isinstance(parsed, list):
83+
if len(parsed) == 0:
84+
return {}
85+
86+
first = parsed[0]
87+
88+
# Format 2: CloudFormation-style [{"ParameterKey": "Key1", "ParameterValue": "Value1"}, ...]
89+
if isinstance(first, dict):
90+
return _parse_cfn_style_parameters(parsed)
91+
92+
# Format 3: Key=Value string list ["Key1=Value1", "Key2=Value2"]
93+
if isinstance(first, str):
94+
return _parse_key_value_string_parameters(parsed)
95+
96+
raise ApplicationError(
97+
'Unsupported parameter file format. Supported formats:\n'
98+
' - CodePipeline configuration: {"Parameters": {"Key": "Value"}}\n'
99+
' - CloudFormation-style list: [{"ParameterKey": "Key", "ParameterValue": "Value"}, ...]\n'
100+
' - Key=Value string list: ["Key1=Value1", "Key2=Value2"]'
101+
)
102+
103+
104+
def _parse_cfn_style_parameters(parameter_list):
105+
"""Parse [{"ParameterKey": "K", "ParameterValue": "V"}, ...] into {K: V}."""
106+
result = {}
107+
for item in parameter_list:
108+
if not isinstance(item, dict):
109+
raise ApplicationError(
110+
f'Expected a JSON object with "ParameterKey" and "ParameterValue" but got: {item}'
111+
)
112+
if 'ParameterKey' not in item or 'ParameterValue' not in item:
113+
raise ApplicationError(
114+
f'Each parameter object must contain "ParameterKey" and "ParameterValue". Got: {json.dumps(item)}'
115+
)
116+
result[item['ParameterKey']] = item['ParameterValue']
117+
return result
118+
119+
120+
def _parse_key_value_string_parameters(parameter_list):
121+
"""Parse ["Key1=Value1", "Key2=Value2"] into {Key1: Value1}."""
122+
result = {}
123+
for item in parameter_list:
124+
if not isinstance(item, str) or '=' not in item:
125+
raise ApplicationError(
126+
f'Expected a parameter string in the format "Key=Value" but got: {item}'
127+
)
128+
key, value = item.split('=', 1)
129+
result[key] = value
130+
return result
52131

53132

54133
def validate_region(region):

0 commit comments

Comments
 (0)