Skip to content

Commit

Permalink
fix: parameter override prompts during guided deploy (#1558)
Browse files Browse the repository at this point in the history
* fix: parameter override prompts during guided deploy

* tests: unit tests for not saving secure params during guided deploy
  • Loading branch information
sriram-mv authored Nov 20, 2019
1 parent 6fe78f2 commit 9d2063a
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 19 deletions.
49 changes: 36 additions & 13 deletions samcli/commands/deploy/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def do_cli(
force_upload=force_upload,
s3_prefix=s3_prefix,
kms_key_id=kms_key_id,
parameter_overrides=_parameter_overrides if guided else parameter_overrides,
parameter_overrides=sanitize_parameter_overrides(_parameter_overrides) if guided else parameter_overrides,
capabilities=_capabilities if guided else capabilities,
no_execute_changeset=no_execute_changeset,
role_arn=role_arn,
Expand Down Expand Up @@ -305,13 +305,21 @@ def guided_deploy(
region = click.prompt(f"\t{start_bold}AWS Region{end_bold}", default=default_region, type=click.STRING)
if parameter_override_keys:
for parameter_key, parameter_properties in parameter_override_keys.items():
input_parameter_overrides[parameter_key] = click.prompt(
f"\t{start_bold}Parameter {parameter_key}{end_bold}",
default=parameter_overrides.get(
parameter_key, parameter_properties.get("Default", "No default specified")
),
type=click.STRING,
)
no_echo = parameter_properties.get("NoEcho", False)
if no_echo:
parameter = click.prompt(
f"\t{start_bold}Parameter {parameter_key}{end_bold}", type=click.STRING, hide_input=True
)
input_parameter_overrides[parameter_key] = {"Value": parameter, "Hidden": True}
else:
parameter = click.prompt(
f"\t{start_bold}Parameter {parameter_key}{end_bold}",
default=parameter_overrides.get(
parameter_key, parameter_properties.get("Default", "No default specified")
),
type=click.STRING,
)
input_parameter_overrides[parameter_key] = {"Value": parameter, "Hidden": False}

click.secho("\t#Shows you resources changes to be deployed and require a 'Y' to initiate deploy")
confirm_changeset = click.confirm(
Expand All @@ -332,7 +340,7 @@ def guided_deploy(
click.echo(color.yellow("\n\tS3 bucket for deployments\n\t========================="))
s3_bucket = manage_stack(profile=profile, region=region)
click.echo(f"\tS3 bucket: {s3_bucket}")
click.echo("\tA different default S3 bucket can be set in /.samconfig.toml")
click.echo("\tA different default S3 bucket can be set in samconfig.toml")

return (
stack_name,
Expand All @@ -348,7 +356,11 @@ def guided_deploy(

def print_deploy_args(stack_name, s3_bucket, region, capabilities, parameter_overrides, confirm_changeset):

param_overrides_string = parameter_overrides
_parameters = parameter_overrides.copy()
for key, value in _parameters.items():
if isinstance(value, dict):
_parameters[key] = value.get("Value", value) if not value.get("Hidden") else "*" * len(value.get("Value"))

capabilities_string = json.dumps(capabilities)

click.secho("\n\tDeploying with following values\n\t===============================", fg="yellow")
Expand All @@ -357,7 +369,7 @@ def print_deploy_args(stack_name, s3_bucket, region, capabilities, parameter_ove
click.echo(f"\tConfirm changeset : {confirm_changeset}")
click.echo(f"\tDeployment s3 bucket : {s3_bucket}")
click.echo(f"\tCapabilities : {capabilities_string}")
click.echo(f"\tParameter overrides : {param_overrides_string}")
click.echo(f"\tParameter overrides : {_parameters}")

click.secho("\nInitiating deployment\n=====================", fg="yellow")

Expand Down Expand Up @@ -394,8 +406,15 @@ def save_config(template_file, parameter_overrides, **kwargs):
samconfig.put(cmd_names, section, key, value)

if parameter_overrides:
parameter_overrides_value = " ".join([f"{key}={value}" for key, value in parameter_overrides.items()])
samconfig.put(cmd_names, section, "parameter_overrides", parameter_overrides_value)
_params = []
for key, value in parameter_overrides.items():
if isinstance(value, dict):
if not value.get("Hidden"):
_params.append(f"{key}={value.get('Value')}")
else:
_params.append(f"{key}={value}")
if _params:
samconfig.put(cmd_names, section, "parameter_overrides", " ".join(_params))

samconfig.flush()

Expand All @@ -413,3 +432,7 @@ def get_config_ctx(template_file):
config_dir=samconfig_dir if samconfig_dir else SamConfig.config_dir(template_file_path=template_file)
)
return ctx, samconfig


def sanitize_parameter_overrides(parameter_overrides):
return {key: value.get("Value") if isinstance(value, dict) else value for key, value in parameter_overrides.items()}
2 changes: 1 addition & 1 deletion samcli/lib/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def _create_stack(cloudformation_client):

def _get_stack_template():
gc = GlobalConfig()
info = {"version": __version__, "installationId": gc.installation_id}
info = {"version": __version__, "installationId": gc.installation_id if gc.installation_id else "unknown"}

template = """
AWSTemplateFormatVersion : '2010-09-09'
Expand Down
109 changes: 104 additions & 5 deletions tests/unit/commands/deploy/test_command.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from unittest import TestCase
from unittest.mock import patch, Mock, ANY, MagicMock
from unittest.mock import patch, Mock, ANY, MagicMock, call

from samcli.commands.deploy.command import do_cli
from tests.unit.cli.test_cli_config_file import MockContext


class TestDeployliCommand(TestCase):
Expand Down Expand Up @@ -105,10 +106,13 @@ def test_all_args_guided(
mock_sam_config = MagicMock()
mock_sam_config.exists = MagicMock(return_value=True)
mock_get_config_ctx.return_value = (None, mock_sam_config)
mock_get_template_parameters.return_value = {"Myparameter": {"Type": "String"}}
mock_get_template_parameters.return_value = {
"Myparameter": {"Type": "String"},
"MyNoEchoParameter": {"Type": "String", "NoEcho": True},
}
mock_deploy_context.return_value.__enter__.return_value = context_mock
mock_deploy_click.prompt = MagicMock(
side_effect=["sam-app", "us-east-1", "guidedParameter", ("CAPABILITY_IAM",)]
side_effect=["sam-app", "us-east-1", "guidedParameter", "secure", ("CAPABILITY_IAM",)]
)
mock_deploy_click.confirm = MagicMock(side_effect=[True, False, True])

Expand Down Expand Up @@ -144,7 +148,7 @@ def test_all_args_guided(
force_upload=self.force_upload,
s3_prefix=self.s3_prefix,
kms_key_id=self.kms_key_id,
parameter_overrides={"Myparameter": "guidedParameter"},
parameter_overrides={"Myparameter": "guidedParameter", "MyNoEchoParameter": "secure"},
capabilities=self.capabilities,
no_execute_changeset=self.no_execute_changeset,
role_arn=self.role_arn,
Expand All @@ -165,11 +169,106 @@ def test_all_args_guided(
region="us-east-1",
s3_bucket="managed-s3-bucket",
stack_name="sam-app",
parameter_overrides={"Myparameter": "guidedParameter"},
parameter_overrides={
"Myparameter": {"Value": "guidedParameter", "Hidden": False},
"MyNoEchoParameter": {"Value": "secure", "Hidden": True},
},
)
mock_managed_stack.assert_called_with(profile=self.profile, region="us-east-1")
self.assertEqual(context_mock.run.call_count, 1)

@patch("samcli.commands.package.command.click")
@patch("samcli.commands.package.package_context.PackageContext")
@patch("samcli.commands.deploy.command.click")
@patch("samcli.commands.deploy.deploy_context.DeployContext")
@patch("samcli.commands.deploy.command.manage_stack")
@patch("samcli.commands.deploy.command.get_template_parameters")
@patch("samcli.commands.deploy.command.get_config_ctx")
def test_all_args_guided_no_save_echo_param_to_config(
self,
mock_get_config_ctx,
mock_get_template_parameters,
mock_managed_stack,
mock_deploy_context,
mock_deploy_click,
mock_package_context,
mock_package_click,
):

context_mock = Mock()
mock_sam_config = MagicMock()
mock_sam_config.exists = MagicMock(return_value=True)
mock_get_config_ctx.return_value = (MockContext(info_name="deploy", parent=None), mock_sam_config)
mock_get_template_parameters.return_value = {
"Myparameter": {"Type": "String"},
"MyNoEchoParameter": {"Type": "String", "NoEcho": True},
}
mock_deploy_context.return_value.__enter__.return_value = context_mock
mock_deploy_click.prompt = MagicMock(
side_effect=["sam-app", "us-east-1", "guidedParameter", "secure", ("CAPABILITY_IAM",)]
)
mock_deploy_click.confirm = MagicMock(side_effect=[True, False, True])

mock_managed_stack.return_value = "managed-s3-bucket"

do_cli(
template_file=self.template_file,
stack_name=self.stack_name,
s3_bucket=None,
force_upload=self.force_upload,
s3_prefix=self.s3_prefix,
kms_key_id=self.kms_key_id,
parameter_overrides=self.parameter_overrides,
capabilities=self.capabilities,
no_execute_changeset=self.no_execute_changeset,
role_arn=self.role_arn,
notification_arns=self.notification_arns,
fail_on_empty_changeset=self.fail_on_empty_changset,
tags=self.tags,
region=self.region,
profile=self.profile,
use_json=self.use_json,
metadata=self.metadata,
guided=True,
confirm_changeset=True,
)

mock_deploy_context.assert_called_with(
template_file=ANY,
stack_name="sam-app",
s3_bucket="managed-s3-bucket",
force_upload=self.force_upload,
s3_prefix=self.s3_prefix,
kms_key_id=self.kms_key_id,
parameter_overrides={"Myparameter": "guidedParameter", "MyNoEchoParameter": "secure"},
capabilities=self.capabilities,
no_execute_changeset=self.no_execute_changeset,
role_arn=self.role_arn,
notification_arns=self.notification_arns,
fail_on_empty_changeset=self.fail_on_empty_changset,
tags=self.tags,
region="us-east-1",
profile=self.profile,
confirm_changeset=True,
)

context_mock.run.assert_called_with()
mock_managed_stack.assert_called_with(profile=self.profile, region="us-east-1")
self.assertEqual(context_mock.run.call_count, 1)

self.assertEqual(mock_sam_config.put.call_count, 6)
self.assertEqual(
mock_sam_config.put.call_args_list,
[
call(["deploy"], "parameters", "stack_name", "sam-app"),
call(["deploy"], "parameters", "s3_bucket", "managed-s3-bucket"),
call(["deploy"], "parameters", "region", "us-east-1"),
call(["deploy"], "parameters", "confirm_changeset", True),
call(["deploy"], "parameters", "capabilities", "CAPABILITY_IAM"),
call(["deploy"], "parameters", "parameter_overrides", "Myparameter=guidedParameter"),
],
)

@patch("samcli.commands.package.command.click")
@patch("samcli.commands.package.package_context.PackageContext")
@patch("samcli.commands.deploy.command.click")
Expand Down

0 comments on commit 9d2063a

Please sign in to comment.