diff --git a/Makefile b/Makefile index 7ef33bcef..709820279 100755 --- a/Makefile +++ b/Makefile @@ -1,54 +1,17 @@ -NAME=samtranslator27 -PYTHON_VERSION=2.7.14 -CODE_COVERAGE=95 -PYENV := $(shell command -v pyenv 2> /dev/null) - target: $(info ${HELP_MESSAGE}) @exit 0 - -# Make sure that pyenv is configured properly and that we can use it in our setup target. -validation: -ifndef PYENV - $(error "make sure pyenv is accessible in your path, (usually by adding to PATH variable in bash_profile, zshrc, or other locations based on your platform) See: https://github.com/pyenv/pyenv#installation for the installation insructions.") -endif -ifndef PYENV_SHELL - $(error "Add 'pyenv init' to your shell to enable shims and autocompletion, (usually by adding to your bash_profile, zshrc, or other locations based on your platform)") -endif -ifndef PYENV_VIRTUALENV_INIT - $(error "Add 'pyenv virtualenv-init' to your shell to enable shims and autocompletion, (usually by adding to your bash_profile, zshrc, or other locations based on your platform)") -endif - -install: - $(info [*] Install pyenv using https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer...) - @curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer 2> /dev/null | bash - -setup: validation - $(info [*] Download and install python $(PYTHON_VERSION)...) - @pyenv install $(PYTHON_VERSION) - @pyenv local $(PYTHON_VERSION) - $(info [*] Create virtualenv $(NAME) using python $(PYTHON_VERSION)...) - @pyenv virtualenv $(PYTHON_VERSION) $(NAME) - @$(MAKE) activate - -activate: - $(info [*] Activate virtualenv $(NAME)...) - $(shell eval "$$(pyenv init -)" && eval "$$(pyenv virtualenv-init -)" && pyenv activate $(NAME) && pyenv local $(NAME)) init: - $(info [*] Install requirements...) - @pip install -r requirements/dev.txt -r requirements/base.txt + pip install -e '.[dev]' test: - $(info [*] Run the unit test with minimum code coverage of $(CODE_COVERAGE)%...) - @pytest --cov samtranslator --cov-report term-missing --cov-fail-under $(CODE_COVERAGE) tests + pytest --cov samtranslator --cov-report term-missing --cov-fail-under 95 tests black: - rm -f tests/*.pyc samtranslator/*.pyc black setup.py samtranslator/* tests/* bin/* black-check: - rm -f tests/*.pyc samtranslator/*.pyc black --check setup.py samtranslator/* tests/* bin/* # Command to run everytime you make changes to verify everything works @@ -62,9 +25,6 @@ define HELP_MESSAGE Usage: $ make [TARGETS] TARGETS - install Install pyenv using the pyenv-installer. - setup Download, install and activate a virtualenv for this project. - activate Activate the virtual environment for this project. init Initialize and install the requirements and dev-requirements for this project. test Run the Unit tests. dev Run all development tests after a change. diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index 282cfcb4e..4404cab31 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.23.0" +__version__ = "1.24.0" diff --git a/samtranslator/model/iam.py b/samtranslator/model/iam.py index ee27a68d5..d72f98dac 100644 --- a/samtranslator/model/iam.py +++ b/samtranslator/model/iam.py @@ -18,6 +18,36 @@ class IAMRole(Resource): class IAMRolePolicies: + @classmethod + def construct_assume_role_policy_for_service_principal(cls, service_principal): + document = { + "Version": "2012-10-17", + "Statement": [ + {"Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": {"Service": [service_principal]},} + ], + } + return document + + @classmethod + def step_functions_start_execution_role_policy(cls, state_machine_arn, logical_id): + document = { + "PolicyName": logical_id + "StartExecutionPolicy", + "PolicyDocument": { + "Statement": [{"Action": "states:StartExecution", "Effect": "Allow", "Resource": state_machine_arn}] + }, + } + return document + + @classmethod + def stepfunctions_assume_role_policy(cls): + document = { + "Version": "2012-10-17", + "Statement": [ + {"Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": {"Service": ["states.amazonaws.com"]},} + ], + } + return document + @classmethod def cloud_watch_log_assume_role_policy(cls): document = { diff --git a/samtranslator/model/resource_policies.py b/samtranslator/model/resource_policies.py new file mode 100644 index 000000000..810eb7976 --- /dev/null +++ b/samtranslator/model/resource_policies.py @@ -0,0 +1,200 @@ +from enum import Enum +from collections import namedtuple + +from six import string_types + +from samtranslator.model.intrinsics import is_intrinsic, is_intrinsic_if, is_intrinsic_no_value +from samtranslator.model.exceptions import InvalidTemplateException + +PolicyEntry = namedtuple("PolicyEntry", "data type") + + +class ResourcePolicies(object): + """ + Class encapsulating the policies property of SAM resources. This class strictly encapsulates the data + and does not take opinions on how to handle them. + + There are three types of policies: + - Policy Statements + - AWS or Custom Managed Policy names/arns + - Policy Templates + + This class is capable of parsing and detecting the type of the policy. Optionally, if policy template information + is provided to this class, it will detect Policy Templates too. + """ + + POLICIES_PROPERTY_NAME = "Policies" + + def __init__(self, resource_properties, policy_template_processor=None): + """ + Initialize with policies data from resource's properties + + :param dict resource_properties: Dictionary containing properties of this resource + :param policy_template_processor: Optional Instance of PolicyTemplateProcessor that can conclusively detect + if a given policy is a template or not. If not provided, then this class will not detect policy templates. + """ + + # This variable is required to get policies + self._policy_template_processor = policy_template_processor + + # Build the list of policies upon construction. + self.policies = self._get_policies(resource_properties) + + def get(self): + """ + Iterator method that "yields" the next policy entry on subsequent calls to this method. + + :yields namedtuple("data", "type"): Yields a named tuple containing the policy data and its type + """ + + for policy_tuple in self.policies: + yield policy_tuple + + def __len__(self): + return len(self.policies) + + def _get_policies(self, resource_properties): + """ + Returns a list of policies from the resource properties. This method knows how to interpret and handle + polymorphic nature of the policies property. + + Policies can be one of the following: + + * Managed policy name: string + * List of managed policy names: list of strings + * IAM Policy document: dict containing Statement key + * List of IAM Policy documents: list of IAM Policy Document + * Policy Template: dict with only one key where key is in list of supported policy template names + * List of Policy Templates: list of Policy Template + + + :param dict resource_properties: Dictionary of resource properties containing the policies property. + It is assumed that this is already a dictionary and contains policies key. + :return list of PolicyEntry: List of policies, where each item is an instance of named tuple `PolicyEntry` + """ + + policies = None + + if self._contains_policies(resource_properties): + policies = resource_properties[self.POLICIES_PROPERTY_NAME] + + if not policies: + # Policies is None or empty + return [] + + if not isinstance(policies, list): + # Just a single entry. Make it into a list of convenience + policies = [policies] + + result = [] + for policy in policies: + policy_type = self._get_type(policy) + entry = PolicyEntry(data=policy, type=policy_type) + result.append(entry) + + return result + + def _contains_policies(self, resource_properties): + """ + Is there policies data in this resource? + + :param dict resource_properties: Properties of the resource + :return: True if we can process this resource. False, otherwise + """ + return ( + resource_properties is not None + and isinstance(resource_properties, dict) + and self.POLICIES_PROPERTY_NAME in resource_properties + ) + + def _get_type(self, policy): + """ + Returns the type of the given policy + + :param string or dict policy: Policy data + :return PolicyTypes: Type of the given policy. None, if type could not be inferred + """ + + # Must handle intrinsic functions. Policy could be a primitive type or an intrinsic function + + # Managed policies are of type string + if isinstance(policy, string_types): + return PolicyTypes.MANAGED_POLICY + + # Handle the special case for 'if' intrinsic function + if is_intrinsic_if(policy): + return self._get_type_from_intrinsic_if(policy) + + # Intrinsic functions are treated as managed policies by default + if is_intrinsic(policy): + return PolicyTypes.MANAGED_POLICY + + # Policy statement is a dictionary with the key "Statement" in it + if isinstance(policy, dict) and "Statement" in policy: + return PolicyTypes.POLICY_STATEMENT + + # This could be a policy template then. + if self._is_policy_template(policy): + return PolicyTypes.POLICY_TEMPLATE + + # Nothing matches. Don't take opinions on how to handle it. Instead just set the appropriate type. + return PolicyTypes.UNKNOWN + + def _is_policy_template(self, policy): + """ + Is the given policy data a policy template? Policy templates is a dictionary with one key which is the name + of the template. + + :param dict policy: Policy data + :return: True, if this is a policy template. False if it is not + """ + + return ( + self._policy_template_processor is not None + and isinstance(policy, dict) + and len(policy) == 1 + and self._policy_template_processor.has(list(policy.keys())[0]) is True + ) + + def _get_type_from_intrinsic_if(self, policy): + """ + Returns the type of the given policy assuming that it is an intrinsic if function + + :param policy: Input value to get type from + :return: PolicyTypes: Type of the given policy. PolicyTypes.UNKNOWN, if type could not be inferred + """ + intrinsic_if_value = policy["Fn::If"] + + if not len(intrinsic_if_value) == 3: + raise InvalidTemplateException("Fn::If requires 3 arguments") + + if_data = intrinsic_if_value[1] + else_data = intrinsic_if_value[2] + + if_data_type = self._get_type(if_data) + else_data_type = self._get_type(else_data) + + if if_data_type == else_data_type: + return if_data_type + + if is_intrinsic_no_value(if_data): + return else_data_type + + if is_intrinsic_no_value(else_data): + return if_data_type + + raise InvalidTemplateException( + "Different policy types within the same Fn::If statement is unsupported. " + "Separate different policy types into different Fn::If statements" + ) + + +class PolicyTypes(Enum): + """ + Enum of different policy types supported by SAM & this plugin + """ + + MANAGED_POLICY = "managed_policy" + POLICY_STATEMENT = "policy_statement" + POLICY_TEMPLATE = "policy_template" + UNKNOWN = "unknown" diff --git a/samtranslator/model/role_utils/__init__.py b/samtranslator/model/role_utils/__init__.py new file mode 100644 index 000000000..c2f04ce48 --- /dev/null +++ b/samtranslator/model/role_utils/__init__.py @@ -0,0 +1 @@ +from .role_constructor import construct_role_for_resource diff --git a/samtranslator/model/role_utils/role_constructor.py b/samtranslator/model/role_utils/role_constructor.py new file mode 100644 index 000000000..560101849 --- /dev/null +++ b/samtranslator/model/role_utils/role_constructor.py @@ -0,0 +1,111 @@ +from six import string_types + +from samtranslator.model.iam import IAMRole +from samtranslator.model.resource_policies import ResourcePolicies, PolicyTypes +from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value +from samtranslator.model.exceptions import InvalidResourceException + + +def construct_role_for_resource( + resource_logical_id, + attributes, + managed_policy_map, + assume_role_policy_document, + resource_policies, + managed_policy_arns=None, + policy_documents=None, + permissions_boundary=None, + tags=None, +): + """ + Constructs an execution role for a resource. + :param resource_logical_id: The logical_id of the SAM resource that the role will be associated with + :param attributes: Map of resource attributes to their values + :param managed_policy_map: Map of managed policy names to the ARNs + :param assume_role_policy_document: The trust policy that must be associated with the role + :param resource_policies: ResourcePolicies object encapuslating the policies property of SAM resource + :param managed_policy_arns: List of managed policy ARNs to be associated with the role + :param policy_documents: List of policy documents to be associated with the role + :param permissions_boundary: The ARN of the policy used to set the permissions boundary for the role + :param tags: Tags to be associated with the role + + :returns: the generated IAM Role + :rtype: model.iam.IAMRole + """ + role_logical_id = resource_logical_id + "Role" + execution_role = IAMRole(logical_id=role_logical_id, attributes=attributes) + execution_role.AssumeRolePolicyDocument = assume_role_policy_document + + if not managed_policy_arns: + managed_policy_arns = [] + + if not policy_documents: + policy_documents = [] + + for index, policy_entry in enumerate(resource_policies.get()): + if policy_entry.type is PolicyTypes.POLICY_STATEMENT: + + if is_intrinsic_if(policy_entry.data): + + intrinsic_if = policy_entry.data + then_statement = intrinsic_if["Fn::If"][1] + else_statement = intrinsic_if["Fn::If"][2] + + if not is_intrinsic_no_value(then_statement): + then_statement = { + "PolicyName": execution_role.logical_id + "Policy" + str(index), + "PolicyDocument": then_statement, + } + intrinsic_if["Fn::If"][1] = then_statement + + if not is_intrinsic_no_value(else_statement): + else_statement = { + "PolicyName": execution_role.logical_id + "Policy" + str(index), + "PolicyDocument": else_statement, + } + intrinsic_if["Fn::If"][2] = else_statement + + policy_documents.append(intrinsic_if) + + else: + policy_documents.append( + { + "PolicyName": execution_role.logical_id + "Policy" + str(index), + "PolicyDocument": policy_entry.data, + } + ) + + elif policy_entry.type is PolicyTypes.MANAGED_POLICY: + + # There are three options: + # Managed Policy Name (string): Try to convert to Managed Policy ARN + # Managed Policy Arn (string): Insert it directly into the list + # Intrinsic Function (dict): Insert it directly into the list + # + # When you insert into managed_policy_arns list, de-dupe to prevent same ARN from showing up twice + # + + policy_arn = policy_entry.data + if isinstance(policy_entry.data, string_types) and policy_entry.data in managed_policy_map: + policy_arn = managed_policy_map[policy_entry.data] + + # De-Duplicate managed policy arns before inserting. Mainly useful + # when customer specifies a managed policy which is already inserted + # by SAM, such as AWSLambdaBasicExecutionRole + if policy_arn not in managed_policy_arns: + managed_policy_arns.append(policy_arn) + else: + # Policy Templates are not supported here in the "core" + raise InvalidResourceException( + resource_logical_id, + "Policy at index {} in the '{}' property is not valid".format( + index, resource_policies.POLICIES_PROPERTY_NAME + ), + ) + + execution_role.ManagedPolicyArns = list(managed_policy_arns) + execution_role.Policies = policy_documents or None + execution_role.PermissionsBoundary = permissions_boundary + execution_role.Tags = tags + + return execution_role diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index ce84a3c8d..b1b43f8d1 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -22,7 +22,7 @@ from samtranslator.model.cloudformation import NestedStack from samtranslator.model.dynamodb import DynamoDBTable from samtranslator.model.exceptions import InvalidEventException, InvalidResourceException -from samtranslator.model.function_policies import FunctionPolicies, PolicyTypes +from samtranslator.model.resource_policies import ResourcePolicies, PolicyTypes from samtranslator.model.iam import IAMRole, IAMRolePolicies from samtranslator.model.lambda_ import ( LambdaFunction, @@ -44,6 +44,8 @@ ) from samtranslator.model.sqs import SQSQueue from samtranslator.model.sns import SNSTopic +from samtranslator.model.stepfunctions import StateMachineGenerator +from samtranslator.model.role_utils import construct_role_for_resource class SamFunction(SamResourceMacro): @@ -431,12 +433,12 @@ def _construct_role(self, managed_policy_map, event_invoke_policies): :returns: the generated IAM Role :rtype: model.iam.IAMRole """ - execution_role = IAMRole(self.logical_id + "Role", attributes=self.get_passthrough_resource_attributes()) + role_attributes = self.get_passthrough_resource_attributes() if self.AssumeRolePolicyDocument is not None: - execution_role.AssumeRolePolicyDocument = self.AssumeRolePolicyDocument + assume_role_policy_document = self.AssumeRolePolicyDocument else: - execution_role.AssumeRolePolicyDocument = IAMRolePolicies.lambda_assume_role_policy() + assume_role_policy_document = IAMRolePolicies.lambda_assume_role_policy() managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn("service-role/AWSLambdaBasicExecutionRole")] if self.Tracing: @@ -446,7 +448,7 @@ def _construct_role(self, managed_policy_map, event_invoke_policies): ArnGenerator.generate_aws_managed_policy_arn("service-role/AWSLambdaVPCAccessExecutionRole") ) - function_policies = FunctionPolicies( + function_policies = ResourcePolicies( {"Policies": self.Policies}, # No support for policy templates in the "core" policy_template_processor=None, @@ -465,69 +467,17 @@ def _construct_role(self, managed_policy_map, event_invoke_policies): if event_invoke_policies is not None: policy_documents.extend(event_invoke_policies) - for index, policy_entry in enumerate(function_policies.get()): - if policy_entry.type is PolicyTypes.POLICY_STATEMENT: - - if is_intrinsic_if(policy_entry.data): - - intrinsic_if = policy_entry.data - then_statement = intrinsic_if["Fn::If"][1] - else_statement = intrinsic_if["Fn::If"][2] - - if not is_intrinsic_no_value(then_statement): - then_statement = { - "PolicyName": execution_role.logical_id + "Policy" + str(index), - "PolicyDocument": then_statement, - } - intrinsic_if["Fn::If"][1] = then_statement - - if not is_intrinsic_no_value(else_statement): - else_statement = { - "PolicyName": execution_role.logical_id + "Policy" + str(index), - "PolicyDocument": else_statement, - } - intrinsic_if["Fn::If"][2] = else_statement - - policy_documents.append(intrinsic_if) - - else: - policy_documents.append( - { - "PolicyName": execution_role.logical_id + "Policy" + str(index), - "PolicyDocument": policy_entry.data, - } - ) - - elif policy_entry.type is PolicyTypes.MANAGED_POLICY: - - # There are three options: - # Managed Policy Name (string): Try to convert to Managed Policy ARN - # Managed Policy Arn (string): Insert it directly into the list - # Intrinsic Function (dict): Insert it directly into the list - # - # When you insert into managed_policy_arns list, de-dupe to prevent same ARN from showing up twice - # - - policy_arn = policy_entry.data - if isinstance(policy_entry.data, string_types) and policy_entry.data in managed_policy_map: - policy_arn = managed_policy_map[policy_entry.data] - - # De-Duplicate managed policy arns before inserting. Mainly useful - # when customer specifies a managed policy which is already inserted - # by SAM, such as AWSLambdaBasicExecutionRole - if policy_arn not in managed_policy_arns: - managed_policy_arns.append(policy_arn) - else: - # Policy Templates are not supported here in the "core" - raise InvalidResourceException( - self.logical_id, "Policy at index {} in the 'Policies' property is not valid".format(index) - ) - - execution_role.ManagedPolicyArns = list(managed_policy_arns) - execution_role.Policies = policy_documents or None - execution_role.PermissionsBoundary = self.PermissionsBoundary - execution_role.Tags = self._construct_tag_list(self.Tags) - + execution_role = construct_role_for_resource( + resource_logical_id=self.logical_id, + attributes=role_attributes, + managed_policy_map=managed_policy_map, + assume_role_policy_document=assume_role_policy_document, + resource_policies=function_policies, + managed_policy_arns=managed_policy_arns, + policy_documents=policy_documents, + permissions_boundary=self.PermissionsBoundary, + tags=self._construct_tag_list(self.Tags), + ) return execution_role def _validate_dlq(self): @@ -1151,3 +1101,71 @@ def _get_retention_policy_value(self): self.logical_id, "'{}' must be one of the following options: {}.".format("RetentionPolicy", [self.RETAIN, self.DELETE]), ) + + +class SamStateMachine(SamResourceMacro): + """SAM state machine macro. + """ + + resource_type = "AWS::Serverless::StateMachine" + property_types = { + "Definition": PropertyType(False, is_type(dict)), + "DefinitionUri": PropertyType(False, one_of(is_str(), is_type(dict))), + "Logging": PropertyType(False, is_type(dict)), + "Role": PropertyType(False, is_str()), + "DefinitionSubstitutions": PropertyType(False, is_type(dict)), + "Events": PropertyType(False, dict_of(is_str(), is_type(dict))), + "Name": PropertyType(False, is_str()), + "Type": PropertyType(False, is_str()), + "Tags": PropertyType(False, is_type(dict)), + "Policies": PropertyType(False, one_of(is_str(), list_of(one_of(is_str(), is_type(dict), is_type(dict))))), + } + event_resolver = ResourceTypeResolver(samtranslator.model.stepfunctions.events,) + + def to_cloudformation(self, **kwargs): + managed_policy_map = kwargs.get("managed_policy_map", {}) + intrinsics_resolver = kwargs["intrinsics_resolver"] + event_resources = kwargs["event_resources"] + + state_machine_generator = StateMachineGenerator( + logical_id=self.logical_id, + depends_on=self.depends_on, + managed_policy_map=managed_policy_map, + intrinsics_resolver=intrinsics_resolver, + definition=self.Definition, + definition_uri=self.DefinitionUri, + logging=self.Logging, + name=self.Name, + policies=self.Policies, + definition_substitutions=self.DefinitionSubstitutions, + role=self.Role, + state_machine_type=self.Type, + events=self.Events, + event_resources=event_resources, + event_resolver=self.event_resolver, + tags=self.Tags, + resource_attributes=self.resource_attributes, + passthrough_resource_attributes=self.get_passthrough_resource_attributes(), + ) + + resources = state_machine_generator.to_cloudformation() + return resources + + def resources_to_link(self, resources): + try: + return {"event_resources": self._event_resources_to_link(resources)} + except InvalidEventException as e: + raise InvalidResourceException(self.logical_id, e.message) + + def _event_resources_to_link(self, resources): + event_resources = {} + if self.Events: + for logical_id, event_dict in self.Events.items(): + try: + event_source = self.event_resolver.resolve_resource_type(event_dict).from_dict( + self.logical_id + logical_id, event_dict, logical_id + ) + except (TypeError, AttributeError) as e: + raise InvalidEventException(logical_id, "{}".format(e)) + event_resources[logical_id] = event_source.resources_to_link(resources) + return event_resources diff --git a/samtranslator/model/stepfunctions/__init__.py b/samtranslator/model/stepfunctions/__init__.py new file mode 100644 index 000000000..4376a3e33 --- /dev/null +++ b/samtranslator/model/stepfunctions/__init__.py @@ -0,0 +1,3 @@ +from .resources import StepFunctionsStateMachine +from .generators import StateMachineGenerator +from . import events diff --git a/samtranslator/model/stepfunctions/events.py b/samtranslator/model/stepfunctions/events.py new file mode 100644 index 000000000..22d2e7e27 --- /dev/null +++ b/samtranslator/model/stepfunctions/events.py @@ -0,0 +1,401 @@ +from six import string_types +import json + +from samtranslator.model import PropertyType, ResourceMacro +from samtranslator.model.events import EventsRule +from samtranslator.model.iam import IAMRole, IAMRolePolicies +from samtranslator.model.types import dict_of, is_str, is_type, list_of, one_of +from samtranslator.model.intrinsics import fnSub +from samtranslator.translator import logical_id_generator +from samtranslator.model.exceptions import InvalidEventException, InvalidResourceException +from samtranslator.translator.arn_generator import ArnGenerator +from samtranslator.swagger.swagger import SwaggerEditor +from samtranslator.open_api.open_api import OpenApiEditor + +CONDITION = "Condition" + + +class EventSource(ResourceMacro): + """Base class for event sources for SAM State Machine. + + :cvar str principal: The AWS service principal of the source service. + """ + + principal = None + + def _generate_logical_id(self, prefix, suffix, resource_type): + """Helper utility to generate a logicial ID for a new resource + + :param string prefix: Prefix to use for the logical ID of the resource + :param string suffix: Suffix to add for the logical ID of the resource + :param string resource_type: Type of the resource + + :returns: the logical ID for the new resource + :rtype: string + """ + if prefix is None: + prefix = self.logical_id + if suffix.isalnum(): + logical_id = prefix + resource_type + suffix + else: + generator = logical_id_generator.LogicalIdGenerator(prefix + resource_type, suffix) + logical_id = generator.gen() + return logical_id + + def _construct_role(self, resource, prefix=None, suffix=""): + """Constructs the IAM Role resource allowing the event service to invoke + the StartExecution API of the state machine resource it is associated with. + + :param model.stepfunctions.StepFunctionsStateMachine resource: The state machine resource associated with the event + :param string prefix: Prefix to use for the logical ID of the IAM role + :param string suffix: Suffix to add for the logical ID of the IAM role + + :returns: the IAM Role resource + :rtype: model.iam.IAMRole + """ + role_logical_id = self._generate_logical_id(prefix=prefix, suffix=suffix, resource_type="Role") + event_role = IAMRole(role_logical_id, attributes=resource.get_passthrough_resource_attributes()) + event_role.AssumeRolePolicyDocument = IAMRolePolicies.construct_assume_role_policy_for_service_principal( + self.principal + ) + state_machine_arn = resource.get_runtime_attr("arn") + event_role.Policies = [ + IAMRolePolicies.step_functions_start_execution_role_policy(state_machine_arn, role_logical_id) + ] + + return event_role + + +class Schedule(EventSource): + """Scheduled executions for SAM State Machine.""" + + resource_type = "Schedule" + principal = "events.amazonaws.com" + property_types = { + "Schedule": PropertyType(True, is_str()), + "Input": PropertyType(False, is_str()), + "Enabled": PropertyType(False, is_type(bool)), + "Name": PropertyType(False, is_str()), + "Description": PropertyType(False, is_str()), + } + + def to_cloudformation(self, resource, **kwargs): + """Returns the EventBridge Rule and IAM Role to which this Schedule event source corresponds. + + :param dict kwargs: no existing resources need to be modified + :returns: a list of vanilla CloudFormation Resources, to which this Schedule event expands + :rtype: list + """ + resources = [] + + events_rule = EventsRule(self.logical_id) + resources.append(events_rule) + + events_rule.ScheduleExpression = self.Schedule + if self.Enabled is not None: + events_rule.State = "ENABLED" if self.Enabled else "DISABLED" + events_rule.Name = self.Name + events_rule.Description = self.Description + if CONDITION in resource.resource_attributes: + events_rule.set_resource_attribute(CONDITION, resource.resource_attributes[CONDITION]) + + role = self._construct_role(resource) + resources.append(role) + events_rule.Targets = [self._construct_target(resource, role)] + + return resources + + def _construct_target(self, resource, role): + """Constructs the Target property for the EventBridge Rule. + + :returns: the Target property + :rtype: dict + """ + target = { + "Arn": resource.get_runtime_attr("arn"), + "Id": self.logical_id + "StepFunctionsTarget", + "RoleArn": role.get_runtime_attr("arn"), + } + if self.Input is not None: + target["Input"] = self.Input + + return target + + +class CloudWatchEvent(EventSource): + """CloudWatch Events/EventBridge event source for SAM State Machine.""" + + resource_type = "CloudWatchEvent" + principal = "events.amazonaws.com" + property_types = { + "EventBusName": PropertyType(False, is_str()), + "Pattern": PropertyType(False, is_type(dict)), + "Input": PropertyType(False, is_str()), + "InputPath": PropertyType(False, is_str()), + } + + def to_cloudformation(self, resource, **kwargs): + """Returns the CloudWatch Events/EventBridge Rule and IAM Role to which this + CloudWatch Events/EventBridge event source corresponds. + + :param dict kwargs: no existing resources need to be modified + :returns: a list of vanilla CloudFormation Resources, to which this CloudWatch Events/EventBridge event expands + :rtype: list + """ + resources = [] + + events_rule = EventsRule(self.logical_id) + events_rule.EventBusName = self.EventBusName + events_rule.EventPattern = self.Pattern + if CONDITION in resource.resource_attributes: + events_rule.set_resource_attribute(CONDITION, resource.resource_attributes[CONDITION]) + + resources.append(events_rule) + + role = self._construct_role(resource) + resources.append(role) + events_rule.Targets = [self._construct_target(resource, role)] + + return resources + + def _construct_target(self, resource, role): + """Constructs the Target property for the CloudWatch Events/EventBridge Rule. + + :returns: the Target property + :rtype: dict + """ + target = { + "Arn": resource.get_runtime_attr("arn"), + "Id": self.logical_id + "StepFunctionsTarget", + "RoleArn": role.get_runtime_attr("arn"), + } + if self.Input is not None: + target["Input"] = self.Input + + if self.InputPath is not None: + target["InputPath"] = self.InputPath + return target + + +class EventBridgeRule(CloudWatchEvent): + """EventBridge Rule event source for SAM State Machine.""" + + resource_type = "EventBridgeRule" + + +class Api(EventSource): + """Api method event source for SAM State Machines.""" + + resource_type = "Api" + principal = "apigateway.amazonaws.com" + property_types = { + "Path": PropertyType(True, is_str()), + "Method": PropertyType(True, is_str()), + # Api Event sources must "always" be paired with a Serverless::Api + "RestApiId": PropertyType(True, is_str()), + "Stage": PropertyType(False, is_str()), + "Auth": PropertyType(False, is_type(dict)), + } + + def resources_to_link(self, resources): + """ + If this API Event Source refers to an explicit API resource, resolve the reference and grab + necessary data from the explicit API + """ + + rest_api_id = self.RestApiId + if isinstance(rest_api_id, dict) and "Ref" in rest_api_id: + rest_api_id = rest_api_id["Ref"] + + # If RestApiId is a resource in the same template, then we try find the StageName by following the reference + # Otherwise we default to a wildcard. This stage name is solely used to construct the permission to + # allow this stage to invoke the State Machine. If we are unable to resolve the stage name, we will + # simply permit all stages to invoke this State Machine + # This hack is necessary because customers could use !ImportValue, !Ref or other intrinsic functions which + # can be sometimes impossible to resolve (ie. when it has cross-stack references) + permitted_stage = "*" + stage_suffix = "AllStages" + explicit_api = None + if isinstance(rest_api_id, string_types): + + if ( + rest_api_id in resources + and "Properties" in resources[rest_api_id] + and "StageName" in resources[rest_api_id]["Properties"] + ): + + explicit_api = resources[rest_api_id]["Properties"] + permitted_stage = explicit_api["StageName"] + + # Stage could be a intrinsic, in which case leave the suffix to default value + if isinstance(permitted_stage, string_types): + stage_suffix = permitted_stage + else: + stage_suffix = "Stage" + + else: + # RestApiId is a string, not an intrinsic, but we did not find a valid API resource for this ID + raise InvalidEventException( + self.relative_id, + "RestApiId property of Api event must reference a valid resource in the same template.", + ) + + return {"explicit_api": explicit_api, "explicit_api_stage": {"suffix": stage_suffix}} + + def to_cloudformation(self, resource, **kwargs): + """If the Api event source has a RestApi property, then simply return the IAM role resource + allowing API Gateway to start the state machine execution. If no RestApi is provided, then + additionally inject the path, method, and the x-amazon-apigateway-integration into the + Swagger body for a provided implicit API. + + :param model.stepfunctions.resources.StepFunctionsStateMachine resource; the state machine \ + resource to which the Api event source must be associated + :param dict kwargs: a dict containing the implicit RestApi to be modified, should no \ + explicit RestApi be provided. + + :returns: a list of vanilla CloudFormation Resources, to which this Api event expands + :rtype: list + """ + resources = [] + + intrinsics_resolver = kwargs.get("intrinsics_resolver") + + if self.Method is not None: + # Convert to lower case so that user can specify either GET or get + self.Method = self.Method.lower() + + role = self._construct_role(resource) + resources.append(role) + + explicit_api = kwargs["explicit_api"] + if explicit_api.get("__MANAGE_SWAGGER"): + self._add_swagger_integration(explicit_api, resource, role, intrinsics_resolver) + + return resources + + def _add_swagger_integration(self, api, resource, role, intrinsics_resolver): + """Adds the path and method for this Api event source to the Swagger body for the provided RestApi. + + :param model.apigateway.ApiGatewayRestApi rest_api: the RestApi to which the path and method should be added. + """ + swagger_body = api.get("DefinitionBody") + if swagger_body is None: + return + + resource_arn = resource.get_runtime_attr("arn") + integration_uri = fnSub("arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution") + + editor = SwaggerEditor(swagger_body) + + if editor.has_integration(self.Path, self.Method): + # Cannot add the integration, if it is already present + raise InvalidEventException( + self.relative_id, + 'API method "{method}" defined multiple times for path "{path}".'.format( + method=self.Method, path=self.Path + ), + ) + + condition = None + if CONDITION in resource.resource_attributes: + condition = resource.resource_attributes[CONDITION] + + editor.add_state_machine_integration( + self.Path, + self.Method, + integration_uri, + role.get_runtime_attr("arn"), + self._generate_request_template(resource), + condition=condition, + ) + + # Note: Refactor and combine the section below with the Api eventsource for functions + if self.Auth: + method_authorizer = self.Auth.get("Authorizer") + api_auth = api.get("Auth") + api_auth = intrinsics_resolver.resolve_parameter_refs(api_auth) + + if method_authorizer: + api_authorizers = api_auth and api_auth.get("Authorizers") + + if method_authorizer != "AWS_IAM": + if method_authorizer != "NONE" and not api_authorizers: + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " + "because the related API does not define any Authorizers.".format( + authorizer=method_authorizer, method=self.Method, path=self.Path + ), + ) + + if method_authorizer != "NONE" and not api_authorizers.get(method_authorizer): + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " + "because it wasn't defined in the API's Authorizers.".format( + authorizer=method_authorizer, method=self.Method, path=self.Path + ), + ) + + if method_authorizer == "NONE": + if not api_auth or not api_auth.get("DefaultAuthorizer"): + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer on API method [{method}] for path [{path}] because 'NONE' " + "is only a valid value when a DefaultAuthorizer on the API is specified.".format( + method=self.Method, path=self.Path + ), + ) + + if self.Auth.get("AuthorizationScopes") and not isinstance(self.Auth.get("AuthorizationScopes"), list): + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer on API method [{method}] for path [{path}] because " + "'AuthorizationScopes' must be a list of strings.".format(method=self.Method, path=self.Path), + ) + + apikey_required_setting = self.Auth.get("ApiKeyRequired") + apikey_required_setting_is_false = apikey_required_setting is not None and not apikey_required_setting + if apikey_required_setting_is_false and (not api_auth or not api_auth.get("ApiKeyRequired")): + raise InvalidEventException( + self.relative_id, + "Unable to set ApiKeyRequired [False] on API method [{method}] for path [{path}] " + "because the related API does not specify any ApiKeyRequired.".format( + method=self.Method, path=self.Path + ), + ) + + if method_authorizer or apikey_required_setting is not None: + editor.add_auth_to_method(api=api, path=self.Path, method_name=self.Method, auth=self.Auth) + + if self.Auth.get("ResourcePolicy"): + resource_policy = self.Auth.get("ResourcePolicy") + editor.add_resource_policy( + resource_policy=resource_policy, path=self.Path, api_id=self.RestApiId.get("Ref"), stage=self.Stage + ) + if resource_policy.get("CustomStatements"): + editor.add_custom_statements(resource_policy.get("CustomStatements")) + + api["DefinitionBody"] = editor.swagger + + def _generate_request_template(self, resource): + """Generates the Body mapping request template for the Api. This allows for the input + request to the Api to be passed as the execution input to the associated state machine resource. + + :param model.stepfunctions.resources.StepFunctionsStateMachine resource; the state machine + resource to which the Api event source must be associated + + :returns: a body mapping request which passes the Api input to the state machine execution + :rtype: dict + """ + request_templates = { + "application/json": fnSub( + json.dumps( + { + "input": "$util.escapeJavaScript($input.json('$'))", + "stateMachineArn": "${" + resource.logical_id + "}", + } + ) + ) + } + return request_templates diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py new file mode 100644 index 000000000..42e172b45 --- /dev/null +++ b/samtranslator/model/stepfunctions/generators.py @@ -0,0 +1,307 @@ +import json +from uuid import uuid4 +from copy import deepcopy + +from six import string_types + +import samtranslator.model.eventsources.push +from samtranslator.model import ResourceTypeResolver +from samtranslator.model.exceptions import InvalidEventException, InvalidResourceException +from samtranslator.model.iam import IAMRolePolicies +from samtranslator.model.resource_policies import ResourcePolicies +from samtranslator.model.role_utils import construct_role_for_resource +from samtranslator.model.s3_utils.uri_parser import parse_s3_uri +from samtranslator.model.stepfunctions import StepFunctionsStateMachine +from samtranslator.model.stepfunctions import events +from samtranslator.model.intrinsics import fnJoin +from samtranslator.model.tags.resource_tagging import get_tag_list + +from samtranslator.model.intrinsics import is_intrinsic +from samtranslator.utils.cfn_dynamic_references import is_dynamic_reference + + +class StateMachineGenerator(object): + _SAM_KEY = "stateMachine:createdBy" + _SAM_VALUE = "SAM" + _SUBSTITUTION_NAME_TEMPLATE = "definition_substitution_%s" + _SUBSTITUTION_KEY_TEMPLATE = "${definition_substitution_%s}" + + def __init__( + self, + logical_id, + depends_on, + managed_policy_map, + intrinsics_resolver, + definition, + definition_uri, + logging, + name, + policies, + definition_substitutions, + role, + state_machine_type, + events, + event_resources, + event_resolver, + tags=None, + resource_attributes=None, + passthrough_resource_attributes=None, + ): + """ + Constructs an State Machine Generator class that generates a State Machine resource + + :param logical_id: Logical id of the SAM State Machine Resource + :param depends_on: Any resources that need to be depended on + :param managed_policy_map: Map of managed policy names to the ARNs + :param intrinsics_resolver: Instance of the resolver that knows how to resolve parameter references + :param definition: State Machine definition + :param definition_uri: URI to State Machine definition + :param logging: Logging configuration for the State Machine + :param name: Name of the State Machine resource + :param policies: Policies attached to the execution role + :param definition_substitutions: Variable-to-value mappings to be replaced in the State Machine definition + :param role: Role ARN to use for the execution role + :param state_machine_type: Type of the State Machine + :param events: List of event sources for the State Machine + :param event_resources: Event resources to link + :param event_resolver: Resolver that maps Event types to Event classes + :param tags: Tags to be associated with the State Machine resource + :param resource_attributes: Resource attributes to add to the State Machine resource + :param passthrough_resource_attributes: Attributes such as `Condition` that are added to derived resources + """ + self.logical_id = logical_id + self.depends_on = depends_on + self.managed_policy_map = managed_policy_map + self.intrinsics_resolver = intrinsics_resolver + self.passthrough_resource_attributes = passthrough_resource_attributes + self.resource_attributes = resource_attributes + self.definition = definition + self.definition_uri = definition_uri + self.name = name + self.logging = logging + self.policies = policies + self.definition_substitutions = definition_substitutions + self.role = role + self.type = state_machine_type + self.events = events + self.event_resources = event_resources + self.event_resolver = event_resolver + self.tags = tags + self.state_machine = StepFunctionsStateMachine( + logical_id, depends_on=depends_on, attributes=resource_attributes + ) + self.substitution_counter = 1 + + def to_cloudformation(self): + """ + Constructs and returns the State Machine resource and any additional resources associated with it. + + :returns: a list of resources including the State Machine resource. + :rtype: list + """ + resources = [self.state_machine] + + # Defaulting to {} will add the DefinitionSubstitutions field on the transform output even when it is not relevant + if self.definition_substitutions: + self.state_machine.DefinitionSubstitutions = self.definition_substitutions + + if self.definition and self.definition_uri: + raise InvalidResourceException( + self.logical_id, "Specify either 'Definition' or 'DefinitionUri' property and not both." + ) + elif self.definition: + processed_definition = deepcopy(self.definition) + substitutions = self._replace_dynamic_values_with_substitutions(processed_definition) + if len(substitutions) > 0: + if self.state_machine.DefinitionSubstitutions: + self.state_machine.DefinitionSubstitutions.update(substitutions) + else: + self.state_machine.DefinitionSubstitutions = substitutions + self.state_machine.DefinitionString = self._build_definition_string(processed_definition) + elif self.definition_uri: + self.state_machine.DefinitionS3Location = self._construct_definition_uri() + else: + raise InvalidResourceException( + self.logical_id, "Either 'Definition' or 'DefinitionUri' property must be specified." + ) + + if self.role and self.policies: + raise InvalidResourceException( + self.logical_id, "Specify either 'Role' or 'Policies' property and not both." + ) + elif self.role: + self.state_machine.RoleArn = self.role + elif self.policies: + if not self.managed_policy_map: + raise Exception("Managed policy map is empty, but should not be.") + + execution_role = self._construct_role() + self.state_machine.RoleArn = execution_role.get_runtime_attr("arn") + resources.append(execution_role) + else: + raise InvalidResourceException(self.logical_id, "Either 'Role' or 'Policies' property must be specified.") + + self.state_machine.StateMachineName = self.name + self.state_machine.StateMachineType = self.type + self.state_machine.LoggingConfiguration = self.logging + self.state_machine.Tags = self._construct_tag_list() + + event_resources = self._generate_event_resources() + resources.extend(event_resources) + + return resources + + def _construct_definition_uri(self): + """ + Constructs the State Machine's `DefinitionS3 property`_, from the SAM State Machines's DefinitionUri property. + + :returns: a DefinitionUri dict, containing the S3 Bucket, Key, and Version of the State Machine definition. + :rtype: dict + """ + if isinstance(self.definition_uri, dict): + if not self.definition_uri.get("Bucket", None) or not self.definition_uri.get("Key", None): + # DefinitionUri is a dictionary but does not contain Bucket or Key property + raise InvalidResourceException( + self.logical_id, "'DefinitionUri' requires Bucket and Key properties to be specified." + ) + s3_pointer = self.definition_uri + else: + # DefinitionUri is a string + s3_pointer = parse_s3_uri(self.definition_uri) + if s3_pointer is None: + raise InvalidResourceException( + self.logical_id, + "'DefinitionUri' is not a valid S3 Uri of the form " + "'s3://bucket/key' with optional versionId query parameter.", + ) + + definition_s3 = {"Bucket": s3_pointer["Bucket"], "Key": s3_pointer["Key"]} + if "Version" in s3_pointer: + definition_s3["Version"] = s3_pointer["Version"] + return definition_s3 + + def _build_definition_string(self, definition_dict): + """ + Builds a CloudFormation definition string from a definition dictionary. The definition string constructed is + a Fn::Join intrinsic function to make it readable. + + :param definition_dict: State machine definition as a dictionary + + :returns: the state machine definition. + :rtype: dict + """ + # Indenting and then splitting the JSON-encoded string for readability of the state machine definition in the CloudFormation translated resource. + # Separators are passed explicitly to maintain trailing whitespace consistency across Py2 and Py3 + definition_lines = json.dumps(definition_dict, sort_keys=True, indent=4, separators=(",", ": ")).split("\n") + definition_string = fnJoin("\n", definition_lines) + return definition_string + + def _construct_role(self): + """ + Constructs a State Machine execution role based on this SAM State Machine's Policies property. + + :returns: the generated IAM Role + :rtype: model.iam.IAMRole + """ + state_machine_policies = ResourcePolicies( + {"Policies": self.policies}, + # No support for policy templates in the "core" + policy_template_processor=None, + ) + + execution_role = construct_role_for_resource( + resource_logical_id=self.logical_id, + attributes=self.passthrough_resource_attributes, + managed_policy_map=self.managed_policy_map, + assume_role_policy_document=IAMRolePolicies.stepfunctions_assume_role_policy(), + resource_policies=state_machine_policies, + tags=self._construct_tag_list(), + ) + return execution_role + + def _construct_tag_list(self): + """ + Transforms the SAM defined Tags into the form CloudFormation is expecting. + + :returns: List of Tag Dictionaries + :rtype: list + """ + sam_tag = {self._SAM_KEY: self._SAM_VALUE} + return get_tag_list(sam_tag) + get_tag_list(self.tags) + + def _generate_event_resources(self): + """Generates and returns the resources associated with this state machine's event sources. + + :returns: a list containing the state machine's event resources + :rtype: list + """ + resources = [] + if self.events: + for logical_id, event_dict in self.events.items(): + kwargs = {"intrinsics_resolver": self.intrinsics_resolver} + try: + eventsource = self.event_resolver.resolve_resource_type(event_dict).from_dict( + self.state_machine.logical_id + logical_id, event_dict, logical_id + ) + for name, resource in self.event_resources[logical_id].items(): + kwargs[name] = resource + except (TypeError, AttributeError) as e: + raise InvalidEventException(logical_id, "{}".format(e)) + resources += eventsource.to_cloudformation(resource=self.state_machine, **kwargs) + + return resources + + def _replace_dynamic_values_with_substitutions(self, input): + """ + Replaces the CloudFormation instrinsic functions and dynamic references within the input with substitutions. + + :param input: Input dictionary in which the dynamic values need to be replaced with substitutions + + :returns: List of substitution to dynamic value mappings + :rtype: dict + """ + substitution_map = {} + for path in self._get_paths_to_intrinsics(input): + location = input + for step in path[:-1]: + location = location[step] + sub_name, sub_key = self._generate_substitution() + substitution_map[sub_name] = location[path[-1]] + location[path[-1]] = sub_key + return substitution_map + + def _get_paths_to_intrinsics(self, input, path=[]): + """ + Returns all paths to dynamic values within a dictionary + + :param input: Input dictionary to find paths to dynamic values in + :param path: Optional list to keep track of the path to the input dictionary + :returns list: List of keys that defines the path to a dynamic value within the input dictionary + """ + dynamic_value_paths = [] + if isinstance(input, dict): + iterator = input.items() + elif isinstance(input, list): + iterator = enumerate(input) + else: + return dynamic_value_paths + + for key, value in sorted(iterator, key=lambda item: item[0]): + if is_intrinsic(value) or is_dynamic_reference(value): + dynamic_value_paths.append(path + [key]) + elif isinstance(value, (dict, list)): + dynamic_value_paths.extend(self._get_paths_to_intrinsics(value, path + [key])) + + return dynamic_value_paths + + def _generate_substitution(self): + """ + Generates a name and key for a new substitution. + + :returns: Substitution name and key + :rtype: string, string + """ + substitution_name = self._SUBSTITUTION_NAME_TEMPLATE % self.substitution_counter + substitution_key = self._SUBSTITUTION_KEY_TEMPLATE % self.substitution_counter + self.substitution_counter += 1 + return substitution_name, substitution_key diff --git a/samtranslator/model/stepfunctions/resources.py b/samtranslator/model/stepfunctions/resources.py new file mode 100644 index 000000000..160342136 --- /dev/null +++ b/samtranslator/model/stepfunctions/resources.py @@ -0,0 +1,23 @@ +from samtranslator.model import PropertyType, Resource +from samtranslator.model.types import is_type, dict_of, list_of, is_str, one_of +from samtranslator.model.intrinsics import fnGetAtt, ref + + +class StepFunctionsStateMachine(Resource): + resource_type = "AWS::StepFunctions::StateMachine" + property_types = { + "Definition": PropertyType(False, is_type(dict)), + "DefinitionString": PropertyType(False, is_str()), + "DefinitionS3Location": PropertyType(False, is_type(dict)), + "LoggingConfiguration": PropertyType(False, is_type(dict)), + "RoleArn": PropertyType(True, is_str()), + "StateMachineName": PropertyType(False, is_str()), + "StateMachineType": PropertyType(False, is_str()), + "Tags": PropertyType(False, list_of(is_type(dict))), + "DefinitionSubstitutions": PropertyType(False, is_type(dict)), + } + + runtime_attrs = { + "arn": lambda self: ref(self.logical_id), + "name": lambda self: fnGetAtt(self.logical_id, "Name"), + } diff --git a/samtranslator/plugins/api/default_definition_body_plugin.py b/samtranslator/plugins/api/default_definition_body_plugin.py index 8ff6c4c28..2023137bf 100644 --- a/samtranslator/plugins/api/default_definition_body_plugin.py +++ b/samtranslator/plugins/api/default_definition_body_plugin.py @@ -31,7 +31,7 @@ def on_before_transform_template(self, template_dict): template = SamTemplate(template_dict) for api_type in [SamResourceType.Api.value, SamResourceType.HttpApi.value]: - for logicalId, api in template.iterate(api_type): + for logicalId, api in template.iterate({api_type}): if api.properties.get("DefinitionBody") or api.properties.get("DefinitionUri"): continue diff --git a/samtranslator/plugins/api/implicit_api_plugin.py b/samtranslator/plugins/api/implicit_api_plugin.py index 89da2c964..2ae336103 100644 --- a/samtranslator/plugins/api/implicit_api_plugin.py +++ b/samtranslator/plugins/api/implicit_api_plugin.py @@ -69,15 +69,17 @@ def on_before_transform_template(self, template_dict): template.set(self.implicit_api_logical_id, self._generate_implicit_api_resource()) errors = [] - for logicalId, function in template.iterate(SamResourceType.Function.value): + for logicalId, resource in template.iterate( + {SamResourceType.Function.value, SamResourceType.StateMachine.value} + ): - api_events = self._get_api_events(function) - condition = function.condition + api_events = self._get_api_events(resource) + condition = resource.condition if len(api_events) == 0: continue try: - self._process_api_events(function, api_events, template, condition) + self._process_api_events(resource, api_events, template, condition) except InvalidEventException as ex: errors.append(InvalidResourceException(logicalId, ex.message)) @@ -89,11 +91,11 @@ def on_before_transform_template(self, template_dict): if len(errors) > 0: raise InvalidDocumentException(errors) - def _get_api_events(self, function): + def _get_api_events(self, resource): """ - Method to return a dictionary of API Events on the function + Method to return a dictionary of API Events on the resource - :param SamResource function: Function Resource object + :param SamResource resource: SAM Resource object :return dict: Dictionary of API events along with any other configuration passed to it. Example: { FooEvent: {Path: "/foo", Method: "post", RestApiId: blah, MethodSettings: {}, @@ -104,30 +106,30 @@ def _get_api_events(self, function): """ if not ( - function.valid() - and isinstance(function.properties, dict) - and isinstance(function.properties.get("Events"), dict) + resource.valid() + and isinstance(resource.properties, dict) + and isinstance(resource.properties.get("Events"), dict) ): - # Function resource structure is invalid. + # Resource structure is invalid. return {} api_events = {} - for event_id, event in function.properties["Events"].items(): + for event_id, event in resource.properties["Events"].items(): if event and isinstance(event, dict) and event.get("Type") == self.api_event_type: api_events[event_id] = event return api_events - def _process_api_events(self, function, api_events, template, condition=None): + def _process_api_events(self, resource, api_events, template, condition=None): """ Actually process given API events. Iteratively adds the APIs to Swagger JSON in the respective Serverless::Api resource from the template - :param SamResource function: SAM Function containing the API events to be processed - :param dict api_events: API Events extracted from the function. These events will be processed + :param SamResource resource: SAM Resource containing the API events to be processed + :param dict api_events: API Events extracted from the resource. These events will be processed :param SamTemplate template: SAM Template where Serverless::Api resources can be found - :param str condition: optional; this is the condition that is on the function with the API event + :param str condition: optional; this is the condition that is on the resource with the API event """ raise NotImplementedError( "Method _setup_api_properties() must be implemented in a " "subclass of ImplicitApiPlugin" @@ -275,7 +277,7 @@ def _maybe_add_conditions_to_implicit_api_paths(self, template): that composite condition is added to the resource path. """ - for api_id, api in template.iterate(self.api_type): + for api_id, api in template.iterate({self.api_type}): if not api.properties.get("__MANAGE_SWAGGER"): continue diff --git a/samtranslator/plugins/application/serverless_app_plugin.py b/samtranslator/plugins/application/serverless_app_plugin.py index 246125ba5..2f6d42dca 100644 --- a/samtranslator/plugins/application/serverless_app_plugin.py +++ b/samtranslator/plugins/application/serverless_app_plugin.py @@ -82,7 +82,7 @@ def on_before_transform_template(self, template_dict): service_call = self._handle_get_application_request else: service_call = self._handle_create_cfn_template_request - for logical_id, app in template.iterate(SamResourceType.Application.value): + for logical_id, app in template.iterate({SamResourceType.Application.value}): if not self._can_process_application(app): # Handle these cases in the on_before_transform_resource event continue diff --git a/samtranslator/plugins/policies/policy_templates_plugin.py b/samtranslator/plugins/policies/policy_templates_plugin.py index 041291715..7a4a705ac 100644 --- a/samtranslator/plugins/policies/policy_templates_plugin.py +++ b/samtranslator/plugins/policies/policy_templates_plugin.py @@ -1,19 +1,20 @@ from samtranslator.plugins import BasePlugin -from samtranslator.model.function_policies import FunctionPolicies, PolicyTypes +from samtranslator.model.resource_policies import ResourcePolicies, PolicyTypes from samtranslator.model.exceptions import InvalidResourceException from samtranslator.policy_template_processor.exceptions import InsufficientParameterValues, InvalidParameterValues from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value -class PolicyTemplatesForFunctionPlugin(BasePlugin): +class PolicyTemplatesForResourcePlugin(BasePlugin): """ - Use this plugin to allow the usage of Policy Templates in `Policies` section of AWS::Serverless::Function resource. + Use this plugin to allow the usage of Policy Templates in `Policies` section of AWS::Serverless::Function or + AWS::Serverless::StateMachine resource. This plugin runs a `before_transform_resource` hook and converts policy templates into regular policy statements for the core SAM translator to take care of. """ _plugin_name = "" - SUPPORTED_RESOURCE_TYPE = "AWS::Serverless::Function" + SUPPORTED_RESOURCE_TYPE = {"AWS::Serverless::Function", "AWS::Serverless::StateMachine"} def __init__(self, policy_template_processor): """ @@ -24,8 +25,8 @@ def __init__(self, policy_template_processor): """ # Plugin name is the class name for easy disambiguation - _plugin_name = PolicyTemplatesForFunctionPlugin.__name__ - super(PolicyTemplatesForFunctionPlugin, self).__init__(_plugin_name) + _plugin_name = PolicyTemplatesForResourcePlugin.__name__ + super(PolicyTemplatesForResourcePlugin, self).__init__(_plugin_name) self._policy_template_processor = policy_template_processor @@ -42,7 +43,7 @@ def on_before_transform_resource(self, logical_id, resource_type, resource_prope if not self._is_supported(resource_type): return - function_policies = FunctionPolicies(resource_properties, self._policy_template_processor) + function_policies = ResourcePolicies(resource_properties, self._policy_template_processor) if len(function_policies) == 0: # No policies to process @@ -66,7 +67,7 @@ def on_before_transform_resource(self, logical_id, resource_type, resource_prope result.append(converted_policy) # Save the modified policies list to the input - resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result + resource_properties[ResourcePolicies.POLICIES_PROPERTY_NAME] = result def _process_intrinsic_if_policy_template(self, logical_id, policy_entry): intrinsic_if = policy_entry.data @@ -117,4 +118,4 @@ def _is_supported(self, resource_type): :param string resource_type: Type of the resource :return: True, if this plugin supports this resource. False otherwise """ - return resource_type == self.SUPPORTED_RESOURCE_TYPE + return resource_type in self.SUPPORTED_RESOURCE_TYPE diff --git a/samtranslator/policy_templates_data/policy_templates.json b/samtranslator/policy_templates_data/policy_templates.json index d14758caa..6f8115470 100644 --- a/samtranslator/policy_templates_data/policy_templates.json +++ b/samtranslator/policy_templates_data/policy_templates.json @@ -2014,6 +2014,252 @@ } ] } + }, + "ElasticMapReduceModifyInstanceFleetPolicy": { + "Description": "Gives permission to list details and modify capacities for instance fleets within a cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": [ + "elasticmapreduce:ModifyInstanceFleet", + "elasticmapreduce:ListInstanceFleets" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "ElasticMapReduceSetTerminationProtectionPolicy": { + "Description": "Gives permission to set termination protection for a cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": "elasticmapreduce:SetTerminationProtection", + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "ElasticMapReduceModifyInstanceGroupsPolicy": { + "Description": "Gives permission to list details and modify settings for instance groups within a cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": [ + "elasticmapreduce:ModifyInstanceGroups", + "elasticmapreduce:ListInstanceGroups" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "ElasticMapReduceCancelStepsPolicy": { + "Description": "Gives permission to cancel a pending step or steps in a running cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": "elasticmapreduce:CancelSteps", + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "ElasticMapReduceTerminateJobFlowsPolicy": { + "Description": "Gives permission to shut down a cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": "elasticmapreduce:TerminateJobFlows", + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "ElasticMapReduceAddJobFlowStepsPolicy": { + "Description": "Gives permission to add new steps to a running cluster", + "Parameters": { + "ClusterId": { + "Description": "The unique identifier of the cluster" + } + }, + "Definition": { + "Statement": [ + { + "Action": "elasticmapreduce:AddJobFlowSteps", + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:elasticmapreduce:${AWS::Region}:${AWS::AccountId}:cluster/${clusterId}", + { + "clusterId": { + "Ref": "ClusterId" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "SageMakerCreateEndpointPolicy": { + "Description": "Gives permission to create an endpoint in SageMaker", + "Parameters": { + "EndpointName": { + "Description": "Name of the SageMaker endpoint" + } + }, + "Definition": { + "Statement": [ + { + "Action": [ + "sagemaker:CreateEndpoint" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint/${endpointName}", + { + "endpointName": { + "Ref": "EndpointName" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "SageMakerCreateEndpointConfigPolicy": { + "Description": "Gives permission to create an endpoint configuration in SageMaker", + "Parameters": { + "EndpointConfigName": { + "Description": "Name of the SageMaker endpoint configuration" + } + }, + "Definition": { + "Statement": [ + { + "Action": [ + "sagemaker:CreateEndpointConfig" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint-config/${endpointConfigName}", + { + "endpointConfigName": { + "Ref": "EndpointConfigName" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + "EcsRunTaskPolicy": { + "Description": "Gives permission to start a new task for a task definition", + "Parameters": { + "TaskDefinition": { + "Description": "The family and revision (family:revision) of the task definition" + } + }, + "Definition": { + "Statement": [ + { + "Action": [ + "ecs:RunTask" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/${taskDefinition}", + { + "taskDefinition": { + "Ref": "TaskDefinition" + } + } + ] + }, + "Effect": "Allow" + } + ] + } } } } diff --git a/samtranslator/public/models.py b/samtranslator/public/models.py index 159c632f1..c56d94088 100644 --- a/samtranslator/public/models.py +++ b/samtranslator/public/models.py @@ -1,3 +1,3 @@ # flake8: noqa -from samtranslator.model.function_policies import FunctionPolicies, PolicyTypes +from samtranslator.model.resource_policies import ResourcePolicies, PolicyTypes diff --git a/samtranslator/sdk/resource.py b/samtranslator/sdk/resource.py index dc5a04ad0..d430feaa6 100644 --- a/samtranslator/sdk/resource.py +++ b/samtranslator/sdk/resource.py @@ -65,6 +65,7 @@ class SamResourceType(Enum): Application = "AWS::Serverless::Application" LambdaLayerVersion = "AWS::Serverless::LayerVersion" HttpApi = "AWS::Serverless::HttpApi" + StateMachine = "AWS::Serverless::StateMachine" @classmethod def has_value(cls, value): diff --git a/samtranslator/sdk/template.py b/samtranslator/sdk/template.py index 4db2d5126..36dfe07be 100644 --- a/samtranslator/sdk/template.py +++ b/samtranslator/sdk/template.py @@ -19,20 +19,21 @@ def __init__(self, template_dict): self.template_dict = template_dict self.resources = template_dict["Resources"] - def iterate(self, resource_type=None): + def iterate(self, resource_types=None): """ Iterate over all resources within the SAM template, optionally filtering by type - :param string resource_type: Optional type to filter the resources by + :param dict resource_types: Optional types to filter the resources by :yields (string, SamResource): Tuple containing LogicalId and the resource """ - + if resource_types is None: + resource_types = {} for logicalId, resource_dict in self.resources.items(): resource = SamResource(resource_dict) needs_filter = resource.valid() - if resource_type: - needs_filter = needs_filter and resource.type == resource_type + if resource_types: + needs_filter = needs_filter and resource.type in resource_types if needs_filter: yield logicalId, resource diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index abd15b92c..46e01ac4f 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -207,6 +207,55 @@ def add_lambda_integration( if condition: path_dict[method] = make_conditional(condition, path_dict[method]) + def add_state_machine_integration( + self, path, method, integration_uri, credentials, request_templates=None, condition=None, + ): + """ + Adds aws APIGW integration to the given path+method. + + :param string path: Path name + :param string method: HTTP Method + :param string integration_uri: URI for the integration + :param string credentials: Credentials for the integration + :param dict request_templates: A map of templates that are applied on the request payload. + :param bool condition: Condition for the integration + """ + + method = self._normalize_method_name(method) + if self.has_integration(path, method): + raise ValueError("Integration already exists on Path={}, Method={}".format(path, method)) + + self.add_path(path, method) + + # Wrap the integration_uri in a Condition if one exists on that state machine + # This is necessary so CFN doesn't try to resolve the integration reference. + if condition: + integration_uri = make_conditional(condition, integration_uri) + + path_dict = self.get_path(path) + + # Responses + integration_responses = {"200": {"statusCode": "200"}, "400": {"statusCode": "400"}} + default_method_responses = {"200": {"description": "OK"}, "400": {"description": "Bad Request"}} + + path_dict[method][self._X_APIGW_INTEGRATION] = { + "type": "aws", + "httpMethod": "POST", + "uri": integration_uri, + "responses": integration_responses, + "credentials": credentials, + } + + # If 'responses' key is *not* present, add it with an empty dict as value + path_dict[method].setdefault("responses", default_method_responses) + + if request_templates: + path_dict[method][self._X_APIGW_INTEGRATION].update({"requestTemplates": request_templates}) + + # If a condition is present, wrap all method contents up into the condition + if condition: + path_dict[method] = make_conditional(condition, path_dict[method]) + def make_path_conditional(self, path, condition): """ Wrap entire API path definition in a CloudFormation if condition. diff --git a/samtranslator/translator/translator.py b/samtranslator/translator/translator.py index 9547e4202..70014a6e4 100644 --- a/samtranslator/translator/translator.py +++ b/samtranslator/translator/translator.py @@ -16,7 +16,7 @@ from samtranslator.plugins import LifeCycleEvents from samtranslator.plugins import SamPlugins from samtranslator.plugins.globals.globals_plugin import GlobalsPlugin -from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForFunctionPlugin +from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForResourcePlugin from samtranslator.policy_template_processor.processor import PolicyTemplatesProcessor from samtranslator.sdk.parameter import SamParameterValues @@ -170,10 +170,11 @@ def _get_resources_to_iterate(self, sam_template, macro_resolver): Returns a list of resources to iterate, order them based on the following order: 1. AWS::Serverless::Function - because API Events need to modify the corresponding Serverless::Api resource. - 2. AWS::Serverless::Api - 3. Anything else + 2. AWS::Serverless::StateMachine - because API Events need to modify the corresponding Serverless::Api resource. + 3. AWS::Serverless::Api + 4. Anything else - This is necessary because a Function resource with API Events will modify the API resource's Swagger JSON. + This is necessary because a Function or State Machine resource with API Events will modify the API resource's Swagger JSON. Therefore API resource needs to be parsed only after all the Swagger modifications are complete. :param dict sam_template: SAM template @@ -182,6 +183,7 @@ def _get_resources_to_iterate(self, sam_template, macro_resolver): """ functions = [] + statemachines = [] apis = [] others = [] resources = sam_template["Resources"] @@ -195,12 +197,14 @@ def _get_resources_to_iterate(self, sam_template, macro_resolver): continue elif resource["Type"] == "AWS::Serverless::Function": functions.append(data) + elif resource["Type"] == "AWS::Serverless::StateMachine": + statemachines.append(data) elif resource["Type"] == "AWS::Serverless::Api" or resource["Type"] == "AWS::Serverless::HttpApi": apis.append(data) else: others.append(data) - return functions + apis + others + return functions + statemachines + apis + others def prepare_plugins(plugins, parameters={}): @@ -250,9 +254,9 @@ def make_policy_template_for_function_plugin(): """ Constructs an instance of policy templates processing plugin using default policy templates JSON data - :return plugins.policies.policy_templates_plugin.PolicyTemplatesForFunctionPlugin: Instance of the plugin + :return plugins.policies.policy_templates_plugin.PolicyTemplatesForResourcePlugin: Instance of the plugin """ policy_templates = PolicyTemplatesProcessor.get_default_policy_templates_json() processor = PolicyTemplatesProcessor(policy_templates) - return PolicyTemplatesForFunctionPlugin(processor) + return PolicyTemplatesForResourcePlugin(processor) diff --git a/samtranslator/translator/verify_logical_id.py b/samtranslator/translator/verify_logical_id.py index da8b726f7..d8bc44881 100644 --- a/samtranslator/translator/verify_logical_id.py +++ b/samtranslator/translator/verify_logical_id.py @@ -11,6 +11,7 @@ "AWS::Cognito::UserPool": "AWS::Cognito::UserPool", "AWS::ApiGateway::DomainName": "AWS::ApiGateway::DomainName", "AWS::ApiGateway::BasePathMapping": "AWS::ApiGateway::BasePathMapping", + "AWS::StepFunctions::StateMachine": "AWS::Serverless::StateMachine", } diff --git a/samtranslator/utils/__init__.py b/samtranslator/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samtranslator/utils/cfn_dynamic_references.py b/samtranslator/utils/cfn_dynamic_references.py new file mode 100644 index 000000000..65744d069 --- /dev/null +++ b/samtranslator/utils/cfn_dynamic_references.py @@ -0,0 +1,17 @@ +import re + + +def is_dynamic_reference(input): + """ + Checks if the given input is a dynamic reference. Dynamic references follow the pattern '{{resolve:service-name:reference-key}}' + + This method does not validate if the dynamic reference is valid or not, only if it follows the valid pattern: {{resolve:service-name:reference-key}} + + :param input: Input value to check if it is a dynamic reference + :return: True, if yes + """ + pattern = re.compile("^{{resolve:([a-z-]+):(.+)}}$") + if input is not None and isinstance(input, str): + if pattern.match(input): + return True + return False diff --git a/setup.py b/setup.py index 24c6ff975..38af9df29 100755 --- a/setup.py +++ b/setup.py @@ -58,7 +58,7 @@ def read_requirements(req="base.txt"): url="https://github.com/awslabs/serverless-application-model", license="Apache License 2.0", # Exclude all but the code folders - packages=find_packages(exclude=("tests", "docs", "examples", "versions")), + packages=find_packages(exclude=("tests", "tests.*", "docs", "examples", "versions")), install_requires=read_requirements("base.txt"), include_package_data=True, extras_require={"dev": read_requirements("dev.txt")}, diff --git a/tests/model/stepfunctions/__init__.py b/tests/model/stepfunctions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/model/stepfunctions/test_api_event.py b/tests/model/stepfunctions/test_api_event.py new file mode 100644 index 000000000..cc0457dac --- /dev/null +++ b/tests/model/stepfunctions/test_api_event.py @@ -0,0 +1,92 @@ +from mock import Mock +from unittest import TestCase + +from samtranslator.model.stepfunctions.events import Api +from samtranslator.model.exceptions import InvalidResourceException, InvalidEventException + + +class ApiEventSource(TestCase): + def setUp(self): + self.logical_id = "ApiEvent" + + self.api_event_source = Api(self.logical_id) + self.api_event_source.Path = "/statemachine" + self.api_event_source.Method = "POST" + + self.state_machine = Mock() + self.state_machine.logical_id = "MockStateMachine" + self.state_machine.get_runtime_attr = Mock() + self.state_machine.get_runtime_attr.return_value = "arn:aws:statemachine:mock" + self.state_machine.resource_attributes = {} + self.state_machine.get_passthrough_resource_attributes = Mock() + self.state_machine.get_passthrough_resource_attributes.return_value = {} + + def test_to_cloudformation_returns_role_resource(self): + resources = self.api_event_source.to_cloudformation(resource=self.state_machine, explicit_api={}) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_type, "AWS::IAM::Role") + + iam_role = resources[0] + self.assertEqual( + iam_role.AssumeRolePolicyDocument, + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": {"Service": ["apigateway.amazonaws.com"]}, + } + ], + }, + ) + self.assertEqual( + iam_role.Policies, + [ + { + "PolicyName": "ApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": "arn:aws:statemachine:mock", + "Effect": "Allow", + } + ] + }, + } + ], + ) + + def test_resources_to_link_with_explicit_api(self): + resources = {"MyExplicitApi": {"Type": "AWS::Serverless::Api", "Properties": {"StageName": "Prod"}}} + self.api_event_source.RestApiId = {"Ref": "MyExplicitApi"} + resources_to_link = self.api_event_source.resources_to_link(resources) + self.assertEqual( + resources_to_link, {"explicit_api": {"StageName": "Prod"}, "explicit_api_stage": {"suffix": "Prod"}} + ) + + def test_resources_to_link_with_undefined_explicit_api(self): + resources = {} + self.api_event_source.RestApiId = {"Ref": "MyExplicitApi"} + with self.assertRaises(InvalidEventException) as error: + resources_to_link = self.api_event_source.resources_to_link(resources) + + def test_resources_to_link_without_explicit_api(self): + resources = {} + resources_to_link = self.api_event_source.resources_to_link(resources) + self.assertEqual(resources_to_link, {"explicit_api": None, "explicit_api_stage": {"suffix": "AllStages"}}) + + def test_to_cloudformation_throws_when_no_resource(self): + self.assertRaises(TypeError, self.api_event_source.to_cloudformation) + + def test_request_template(self): + request_template = self.api_event_source._generate_request_template(resource=self.state_machine) + self.assertEqual( + request_template, + { + "application/json": { + "Fn::Sub": '{"input": "$util.escapeJavaScript($input.json(\'$\'))", "stateMachineArn": "${MockStateMachine}"}' + } + }, + ) diff --git a/tests/model/stepfunctions/test_cloudwatchevents_event.py b/tests/model/stepfunctions/test_cloudwatchevents_event.py new file mode 100644 index 000000000..d60241cfa --- /dev/null +++ b/tests/model/stepfunctions/test_cloudwatchevents_event.py @@ -0,0 +1,96 @@ +from mock import Mock +from unittest import TestCase +from samtranslator.model.stepfunctions.events import CloudWatchEvent + + +class CloudWatchEventsEventSource(TestCase): + def setUp(self): + self.logical_id = "CWEEvent" + + self.cwe_event_source = CloudWatchEvent(self.logical_id) + self.cwe_event_source.Pattern = {"detail": {"state": ["terminated"]}} + + self.state_machine = Mock() + self.state_machine.get_runtime_attr = Mock() + self.state_machine.get_runtime_attr.return_value = "arn:aws:statemachine:mock" + self.state_machine.resource_attributes = {} + self.state_machine.get_passthrough_resource_attributes = Mock() + self.state_machine.get_passthrough_resource_attributes.return_value = {} + + def test_to_cloudformation_returns_eventrule_and_role_resources(self): + resources = self.cwe_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_type, "AWS::Events::Rule") + self.assertEqual(resources[1].resource_type, "AWS::IAM::Role") + + iam_role = resources[1] + self.assertEqual( + iam_role.AssumeRolePolicyDocument, + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": {"Service": ["events.amazonaws.com"]}, + } + ], + }, + ) + self.assertEqual( + iam_role.Policies, + [ + { + "PolicyName": "CWEEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": "arn:aws:statemachine:mock", + "Effect": "Allow", + } + ] + }, + } + ], + ) + + event_rule = resources[0] + self.assertEqual(event_rule.EventPattern, {"detail": {"state": ["terminated"]}}) + self.assertEqual( + event_rule.Targets, + [ + { + "Id": "CWEEventStepFunctionsTarget", + "Arn": "arn:aws:statemachine:mock", + "RoleArn": {"Fn::GetAtt": [iam_role.logical_id, "Arn"]}, + } + ], + ) + + def test_to_cloudformation_throws_when_no_resource(self): + self.assertRaises(TypeError, self.cwe_event_source.to_cloudformation) + + def test_to_cloudformation_with_input(self): + input_to_service = '{"test_key": "test_value"}' + self.cwe_event_source.Input = input_to_service + resources = self.cwe_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + event_rule = resources[0] + self.assertEqual(event_rule.Targets[0]["Input"], input_to_service) + + def test_to_cloudformation_with_input_path(self): + input_path_to_service = "path/to/input" + self.cwe_event_source.InputPath = input_path_to_service + resources = self.cwe_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + event_rule = resources[0] + self.assertEqual(event_rule.Targets[0]["InputPath"], input_path_to_service) + + def test_to_cloudformation_with_eventbus_name(self): + input_to_service = '{"test_key": "test_value"}' + self.cwe_event_source.Input = input_to_service + resources = self.cwe_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + event_rule = resources[0] + self.assertEqual(event_rule.Targets[0]["Input"], input_to_service) diff --git a/tests/model/stepfunctions/test_schedule_event.py b/tests/model/stepfunctions/test_schedule_event.py new file mode 100644 index 000000000..4082dc91a --- /dev/null +++ b/tests/model/stepfunctions/test_schedule_event.py @@ -0,0 +1,87 @@ +from mock import Mock +from unittest import TestCase +from samtranslator.model.stepfunctions.events import Schedule + + +class ScheduleEventSource(TestCase): + def setUp(self): + self.logical_id = "ScheduleEvent" + + self.schedule_event_source = Schedule(self.logical_id) + self.schedule_event_source.Schedule = "rate(1 minute)" + + self.state_machine = Mock() + self.state_machine.get_runtime_attr = Mock() + self.state_machine.get_runtime_attr.return_value = "arn:aws:statemachine:mock" + self.state_machine.resource_attributes = {} + self.state_machine.get_passthrough_resource_attributes = Mock() + self.state_machine.get_passthrough_resource_attributes.return_value = {} + + def test_to_cloudformation_returns_eventrule_and_role_resources(self): + resources = self.schedule_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_type, "AWS::Events::Rule") + self.assertEqual(resources[1].resource_type, "AWS::IAM::Role") + + iam_role = resources[1] + self.assertEqual( + iam_role.AssumeRolePolicyDocument, + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": {"Service": ["events.amazonaws.com"]}, + } + ], + }, + ) + self.assertEqual( + iam_role.Policies, + [ + { + "PolicyName": "ScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": "arn:aws:statemachine:mock", + "Effect": "Allow", + } + ] + }, + } + ], + ) + + event_rule = resources[0] + self.assertEqual(event_rule.ScheduleExpression, "rate(1 minute)") + self.assertEqual( + event_rule.Targets, + [ + { + "Id": "ScheduleEventStepFunctionsTarget", + "Arn": "arn:aws:statemachine:mock", + "RoleArn": {"Fn::GetAtt": [iam_role.logical_id, "Arn"]}, + } + ], + ) + + def test_to_cloudformation_throws_when_no_resource(self): + self.assertRaises(TypeError, self.schedule_event_source.to_cloudformation) + + def test_to_cloudformation_when_event_is_disabled(self): + self.schedule_event_source.Enabled = False + resources = self.schedule_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + event_rule = resources[0] + self.assertEqual(event_rule.State, "DISABLED") + + def test_to_cloudformation_with_input(self): + input_to_service = '{"test_key": "test_value"}' + self.schedule_event_source.Input = input_to_service + resources = self.schedule_event_source.to_cloudformation(resource=self.state_machine) + self.assertEqual(len(resources), 2) + event_rule = resources[0] + self.assertEqual(event_rule.Targets[0]["Input"], input_to_service) diff --git a/tests/model/stepfunctions/test_state_machine_generator.py b/tests/model/stepfunctions/test_state_machine_generator.py new file mode 100644 index 000000000..d92e1179e --- /dev/null +++ b/tests/model/stepfunctions/test_state_machine_generator.py @@ -0,0 +1,149 @@ +from mock import Mock +from unittest import TestCase + +from samtranslator.model import ResourceTypeResolver +from samtranslator.model.exceptions import InvalidResourceException, InvalidEventException +from samtranslator.model.stepfunctions import StateMachineGenerator +from samtranslator.model.stepfunctions.events import CloudWatchEvent + + +class StepFunctionsStateMachine(TestCase): + def setUp(self): + self.kwargs = { + "logical_id": "StateMachineId", + "depends_on": None, + "managed_policy_map": None, + "intrinsics_resolver": None, + "definition": None, + "definition_uri": None, + "logging": None, + "name": None, + "policies": None, + "definition_substitutions": None, + "role": None, + "state_machine_type": None, + "events": None, + "event_resources": None, + "event_resolver": None, + "tags": None, + "resource_attributes": None, + "passthrough_resource_attributes": None, + } + + def test_state_machine_no_definition_source(self): + self.kwargs["definition"] = None + self.kwargs["definition_uri"] = None + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. Either 'Definition' or 'DefinitionUri' property must be specified.", + ) + + def test_state_machine_multiple_definition_sources(self): + self.kwargs["definition"] = {"StartAt": "StateOne", "States": {"StateOne": {"Type": "Pass", "End": True}}} + self.kwargs["definition_uri"] = "s3://my-sam-bucket/definition.asl.json" + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. Specify either 'Definition' or 'DefinitionUri' property and not both.", + ) + + def test_state_machine_no_role_or_policies(self): + self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" + self.kwargs["role"] = None + self.kwargs["policies"] = None + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. Either 'Role' or 'Policies' property must be specified.", + ) + + def test_state_machine_both_role_and_policies(self): + self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" + self.kwargs["role"] = "arn:my-sample-role" + self.kwargs["policies"] = { + "Policies": [{"Version": "2012-10-17", "Statement": [{"Effect": "Deny", "Action": "*", "Resource": "*"}]}] + } + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. Specify either 'Role' or 'Policies' property and not both.", + ) + + def test_state_machine_invalid_definition_uri_string(self): + self.kwargs["definition"] = None + self.kwargs["definition_uri"] = "invalid_uri" + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. 'DefinitionUri' is not a valid S3 Uri of the form 's3://bucket/key' with optional versionId query parameter.", + ) + + def test_state_machine_invalid_definition_uri_object(self): + self.kwargs["definition"] = None + self.kwargs["definition_uri"] = {"Bucket": "only-bucket-name"} + with self.assertRaises(InvalidResourceException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual( + error.exception.message, + "Resource with id [StateMachineId] is invalid. 'DefinitionUri' requires Bucket and Key properties to be specified.", + ) + + def test_state_machine_no_tags_provided(self): + self.kwargs["definition_uri"] = "s3://mybucket/myASLfile" + self.kwargs["role"] = "my-test-role-arn" + self.kwargs["tags"] = None + expected_tags = [{"Key": StateMachineGenerator._SAM_KEY, "Value": StateMachineGenerator._SAM_VALUE}] + generated_tags = StateMachineGenerator(**self.kwargs)._construct_tag_list() + self.assertEqual(generated_tags, expected_tags) + + def test_state_machine_with_tags_provided(self): + self.kwargs["definition_uri"] = "s3://mybucket/myASLfile" + self.kwargs["role"] = "my-test-role-arn" + self.kwargs["tags"] = {"Key01": "Value01", "Key02": "Value02"} + expected_tags = [ + {"Key": StateMachineGenerator._SAM_KEY, "Value": StateMachineGenerator._SAM_VALUE}, + {"Key": "Key01", "Value": "Value01"}, + {"Key": "Key02", "Value": "Value02"}, + ] + generated_tags = StateMachineGenerator(**self.kwargs)._construct_tag_list() + self.assertEqual(generated_tags, expected_tags) + + def test_state_machine_with_supported_event_source(self): + self.kwargs["definition_uri"] = "s3://mybucket/myASLfile" + self.kwargs["role"] = "my-test-role-arn" + event_resolver = Mock() + event_resolver.resolve_resource_type = Mock(return_value=CloudWatchEvent) + self.kwargs["event_resolver"] = event_resolver + self.kwargs["events"] = { + "CWEEvent": {"Type": "CloudWatchEvent", "Properties": {"Pattern": {"detail": {"state": ["terminated"]}}}} + } + self.kwargs["event_resources"] = {"CWEEvent": {}} + generated_event_resources = StateMachineGenerator(**self.kwargs)._generate_event_resources() + self.assertEqual(generated_event_resources[0].resource_type, "AWS::Events::Rule") + + def test_state_machine_with_unsupported_event_source(self): + self.kwargs["definition_uri"] = "s3://mybucket/myASLfile" + self.kwargs["role"] = "my-test-role-arn" + event_resolver = Mock() + event_resolver.resolve_resource_type = Mock(return_value=None) + self.kwargs["event_resolver"] = event_resolver + self.kwargs["events"] = { + "KinesesEvent": { + "Type": "Kineses", + "Properties": { + "Stream": "arn:aws:kinesis:us-east-1:123456789012:stream/my-stream", + "StartingPosition": "TRIM_HORIZON", + "BatchSize": 10, + "Enabled": False, + }, + } + } + self.kwargs["event_resources"] = {"KinesesEvent": {}} + with self.assertRaises(InvalidEventException) as error: + StateMachineGenerator(**self.kwargs).to_cloudformation() diff --git a/tests/model/test_resource_policies.py b/tests/model/test_resource_policies.py new file mode 100644 index 000000000..8c2731c2c --- /dev/null +++ b/tests/model/test_resource_policies.py @@ -0,0 +1,364 @@ +from mock import Mock, patch +from unittest import TestCase + +from samtranslator.model.resource_policies import ResourcePolicies, PolicyTypes, PolicyEntry +from samtranslator.model.exceptions import InvalidTemplateException +from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value + + +class TestResourcePolicies(TestCase): + def setUp(self): + self.policy_template_processor_mock = Mock() + self.is_policy_template_mock = Mock() + + self.function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + self.function_policies._is_policy_template = self.is_policy_template_mock + + @patch.object(ResourcePolicies, "_get_policies") + def test_initialization_must_ingest_policies_from_resource_properties(self, get_policies_mock): + resource_properties = {} + dummy_policy_results = ["some", "policy", "statements"] + expected_length = 3 + + get_policies_mock.return_value = dummy_policy_results + function_policies = ResourcePolicies(resource_properties, self.policy_template_processor_mock) + + get_policies_mock.assert_called_once_with(resource_properties) + self.assertEqual(expected_length, len(function_policies)) + + @patch.object(ResourcePolicies, "_get_policies") + def test_get_must_yield_results_on_every_call(self, get_policies_mock): + resource_properties = {} # Just some input + dummy_policy_results = ["some", "policy", "statements"] + expected_results = ["some", "policy", "statements"] + + # Setup _get_policies to return these dummy values for testing + get_policies_mock.return_value = dummy_policy_results + function_policies = ResourcePolicies(resource_properties, self.policy_template_processor_mock) + + # `list()` will implicitly call the `get()` repeatedly because it is a generator + self.assertEqual(list(function_policies.get()), expected_results) + + @patch.object(ResourcePolicies, "_get_policies") + def test_get_must_yield_no_results_with_no_policies(self, get_policies_mock): + resource_properties = {} # Just some input + dummy_policy_results = [] + expected_result = [] + + # Setup _get_policies to return these dummy values for testing + get_policies_mock.return_value = dummy_policy_results + function_policies = ResourcePolicies(resource_properties, self.policy_template_processor_mock) + + # `list()` will implicitly call the `get()` repeatedly because it is a generator + self.assertEqual(list(function_policies.get()), expected_result) + + def test_contains_policies_must_work_for_valid_input(self): + resource_properties = {"Policies": "some managed policy"} + + self.assertTrue(self.function_policies._contains_policies(resource_properties)) + + def test_contains_policies_must_ignore_resources_without_policies(self): + resource_properties = {"some key": "value"} + + self.assertFalse(self.function_policies._contains_policies(resource_properties)) + + def test_contains_policies_must_ignore_non_dict_resources(self): + resource_properties = "some value" + + self.assertFalse(self.function_policies._contains_policies(resource_properties)) + + def test_contains_policies_must_ignore_none_resources(self): + resource_properties = None + + self.assertFalse(self.function_policies._contains_policies(resource_properties)) + + def test_contains_policies_must_ignore_lowercase_property_name(self): + # Property names are case sensitive + resource_properties = {"policies": "some managed policy"} + + self.assertFalse(self.function_policies._contains_policies(resource_properties)) + + def test_get_type_must_work_for_managed_policy(self): + policy = "managed policy is a string" + expected = PolicyTypes.MANAGED_POLICY + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + + @patch("samtranslator.model.resource_policies.is_intrinsic") + def test_get_type_must_work_for_managed_policy_with_intrinsics(self, is_intrinsic_mock): + policy = {"Ref": "somevalue"} + expected = PolicyTypes.MANAGED_POLICY + is_intrinsic_mock.return_value = True + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + + def test_get_type_must_work_for_policy_statements(self): + policy = {"Statement": "policy statements have a 'Statement' key"} + expected = PolicyTypes.POLICY_STATEMENT + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + + def test_get_type_must_work_for_policy_templates(self): + policy = {"PolicyTemplate": "some template"} + self.is_policy_template_mock.return_value = True + expected = PolicyTypes.POLICY_TEMPLATE + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + + def test_get_type_must_ignore_invalid_policy(self): + policy = {"not-sure-what-this-is": "value"} + # This is also not a policy template + self.is_policy_template_mock.return_value = False + expected = PolicyTypes.UNKNOWN + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + + def test_get_type_must_ignore_invalid_policy_value_list(self): + policy = ["invalid", "policy"] + expected = PolicyTypes.UNKNOWN + + self.is_policy_template_mock.return_value = False + + result = self.function_policies._get_type(policy) + self.assertEqual(result, expected) + self.is_policy_template_mock.assert_called_once_with(policy) + + def test_get_policies_must_return_all_policies(self): + policies = [ + "managed policy 1", + {"Ref": "some managed policy"}, + {"Statement": "policy statement"}, + {"PolicyTemplate": "some value"}, + ["unknown", "policy"], + ] + resource_properties = {"Policies": policies} + self.is_policy_template_mock.side_effect = [True, False] # Return True for policy template, False for the list + + expected = [ + PolicyEntry(data="managed policy 1", type=PolicyTypes.MANAGED_POLICY), + PolicyEntry(data={"Ref": "some managed policy"}, type=PolicyTypes.MANAGED_POLICY), + PolicyEntry(data={"Statement": "policy statement"}, type=PolicyTypes.POLICY_STATEMENT), + PolicyEntry(data={"PolicyTemplate": "some value"}, type=PolicyTypes.POLICY_TEMPLATE), + PolicyEntry(data=["unknown", "policy"], type=PolicyTypes.UNKNOWN), + ] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_ignore_if_resource_does_not_contain_policy(self): + resource_properties = {} + expected = [] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_ignore_if_policies_is_empty(self): + resource_properties = {"Policies": []} + expected = [] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_work_for_single_policy_string(self): + resource_properties = {"Policies": "single managed policy"} + expected = [PolicyEntry(data="single managed policy", type=PolicyTypes.MANAGED_POLICY)] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_work_for_single_dict_with_managed_policy_intrinsic(self): + resource_properties = {"Policies": {"Ref": "some managed policy"}} + expected = [PolicyEntry(data={"Ref": "some managed policy"}, type=PolicyTypes.MANAGED_POLICY)] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_work_for_single_dict_with_policy_statement(self): + resource_properties = {"Policies": {"Statement": "some policy statement"}} + expected = [PolicyEntry(data={"Statement": "some policy statement"}, type=PolicyTypes.POLICY_STATEMENT)] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_get_policies_must_work_for_single_dict_of_policy_template(self): + resource_properties = {"Policies": {"PolicyTemplate": "some template"}} + self.is_policy_template_mock.return_value = True + expected = [PolicyEntry(data={"PolicyTemplate": "some template"}, type=PolicyTypes.POLICY_TEMPLATE)] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + self.is_policy_template_mock.assert_called_once_with(resource_properties["Policies"]) + + def test_get_policies_must_work_for_single_dict_of_invalid_policy_template(self): + resource_properties = {"Policies": {"InvalidPolicyTemplate": "some template"}} + self.is_policy_template_mock.return_value = False # Invalid policy template + expected = [PolicyEntry(data={"InvalidPolicyTemplate": "some template"}, type=PolicyTypes.UNKNOWN)] + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + self.is_policy_template_mock.assert_called_once_with({"InvalidPolicyTemplate": "some template"}) + + def test_get_policies_must_work_for_unknown_policy_types(self): + resource_properties = {"Policies": [1, 2, 3]} + expected = [ + PolicyEntry(data=1, type=PolicyTypes.UNKNOWN), + PolicyEntry(data=2, type=PolicyTypes.UNKNOWN), + PolicyEntry(data=3, type=PolicyTypes.UNKNOWN), + ] + + self.is_policy_template_mock.return_value = False + + result = self.function_policies._get_policies(resource_properties) + self.assertEqual(result, expected) + + def test_is_policy_template_must_detect_valid_policy_templates(self): + template_name = "template_name" + policy = {template_name: {"Param1": "foo"}} + + self.policy_template_processor_mock.has.return_value = True + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + + self.assertTrue(function_policies._is_policy_template(policy)) + + self.policy_template_processor_mock.has.assert_called_once_with(template_name) + + def test_is_policy_template_must_ignore_non_dict_policies(self): + policy = [1, 2, 3] + + self.policy_template_processor_mock.has.return_value = True + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + + self.assertFalse(function_policies._is_policy_template(policy)) + + self.policy_template_processor_mock.has.assert_not_called() + + def test_is_policy_template_must_ignore_none_policies(self): + policy = None + + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + self.assertFalse(function_policies._is_policy_template(policy)) + + def test_is_policy_template_must_ignore_dict_with_two_keys(self): + template_name = "template_name" + policy = {template_name: {"param1": "foo"}, "A": "B"} + + self.policy_template_processor_mock.has.return_value = True + + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + self.assertFalse(function_policies._is_policy_template(policy)) + + def test_is_policy_template_must_ignore_non_policy_templates(self): + template_name = "template_name" + policy = {template_name: {"param1": "foo"}} + + self.policy_template_processor_mock.has.return_value = False + + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + self.assertFalse(function_policies._is_policy_template(policy)) + + self.policy_template_processor_mock.has.assert_called_once_with(template_name) + + def test_is_policy_template_must_return_false_without_the_processor(self): + policy = {"template_name": {"param1": "foo"}} + + function_policies_obj = ResourcePolicies({}, None) # No policy template processor + + self.assertFalse(function_policies_obj._is_policy_template(policy)) + self.policy_template_processor_mock.has.assert_not_called() + + def test_is_intrinsic_if_must_return_true_for_if(self): + policy = {"Fn::If": "some value"} + + self.assertTrue(is_intrinsic_if(policy)) + + def test_is_intrinsic_if_must_return_false_for_others(self): + too_many_keys = {"Fn::If": "some value", "Fn::And": "other value"} + + not_if = {"Fn::Or": "some value"} + + self.assertFalse(is_intrinsic_if(too_many_keys)) + self.assertFalse(is_intrinsic_if(not_if)) + self.assertFalse(is_intrinsic_if(None)) + + def test_is_intrinsic_no_value_must_return_true_for_no_value(self): + policy = {"Ref": "AWS::NoValue"} + + self.assertTrue(is_intrinsic_no_value(policy)) + + def test_is_intrinsic_no_value_must_return_false_for_other_value(self): + bad_key = {"sRefs": "AWS::NoValue"} + + bad_value = {"Ref": "SWA::NoValue"} + + too_many_keys = {"Ref": "AWS::NoValue", "feR": "SWA::NoValue"} + + self.assertFalse(is_intrinsic_no_value(bad_key)) + self.assertFalse(is_intrinsic_no_value(bad_value)) + self.assertFalse(is_intrinsic_no_value(None)) + self.assertFalse(is_intrinsic_no_value(too_many_keys)) + + def test_get_type_with_intrinsic_if_must_return_managed_policy_type(self): + managed_policy = {"Fn::If": ["SomeCondition", "some managed policy arn", "other managed policy arn"]} + + no_value_if = {"Fn::If": ["SomeCondition", {"Ref": "AWS::NoValue"}, "other managed policy arn"]} + + no_value_else = {"Fn::If": ["SomeCondition", "other managed policy arn", {"Ref": "AWS::NoValue"}]} + + expected_managed_policy = PolicyTypes.MANAGED_POLICY + + self.assertTrue(expected_managed_policy, self.function_policies._get_type(managed_policy)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_return_policy_statement_type(self): + policy_statement = { + "Fn::If": ["SomeCondition", {"Statement": "then statement"}, {"Statement": "else statement"}] + } + + no_value_if = {"Fn::If": ["SomeCondition", {"Ref": "AWS::NoValue"}, {"Statement": "else statement"}]} + + no_value_else = {"Fn::If": ["SomeCondition", {"Statement": "then statement"}, {"Ref": "AWS::NoValue"}]} + expected_managed_policy = PolicyTypes.POLICY_STATEMENT + + self.assertTrue(expected_managed_policy, self.function_policies._get_type(policy_statement)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_return_policy_template_type(self): + policy_template = { + "Fn::If": [ + "SomeCondition", + {"template_name_one": {"Param1": "foo"}}, + {"template_name_one": {"Param1": "foo"}}, + ] + } + no_value_if = {"Fn::If": ["SomeCondition", {"Ref": "AWS::NoValue"}, {"template_name_one": {"Param1": "foo"}}]} + no_value_else = {"Fn::If": ["SomeCondition", {"template_name_one": {"Param1": "foo"}}, {"Ref": "AWS::NoValue"}]} + + expected_managed_policy = PolicyTypes.POLICY_TEMPLATE + self.policy_template_processor_mock.has.return_value = True + function_policies = ResourcePolicies({}, self.policy_template_processor_mock) + + self.assertTrue(expected_managed_policy, function_policies._get_type(policy_template)) + self.assertTrue(expected_managed_policy, function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_raise_exception_for_bad_policy(self): + policy_too_few_values = {"Fn::If": ["condition", "then"]} + + policy_too_many_values = {"Fn::If": ["condition", "then", "else", "extra"]} + + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_too_few_values) + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_too_many_values) + + def test_get_type_with_intrinsic_if_must_raise_exception_for_different_policy_types(self): + policy_one = {"Fn::If": ["condition", "then", {"Statement": "else"}]} + policy_two = {"Fn::If": ["condition", {"Statement": "then"}, "else"]} + + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_one) + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_two) diff --git a/tests/plugins/api/test_default_definition_body_plugin.py b/tests/plugins/api/test_default_definition_body_plugin.py index a6e519675..ad6e1648c 100644 --- a/tests/plugins/api/test_default_definition_body_plugin.py +++ b/tests/plugins/api/test_default_definition_body_plugin.py @@ -41,8 +41,8 @@ def test_must_process_functions(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) # Make sure this is called only for Apis - sam_template.iterate.assert_any_call("AWS::Serverless::Api") - sam_template.iterate.assert_any_call("AWS::Serverless::HttpApi") + sam_template.iterate.assert_any_call({"AWS::Serverless::Api"}) + sam_template.iterate.assert_any_call({"AWS::Serverless::HttpApi"}) class ApiResource(object): diff --git a/tests/plugins/api/test_implicit_api_plugin.py b/tests/plugins/api/test_implicit_api_plugin.py index d1f55ce59..3181e11bb 100644 --- a/tests/plugins/api/test_implicit_api_plugin.py +++ b/tests/plugins/api/test_implicit_api_plugin.py @@ -89,9 +89,9 @@ def test_must_process_functions(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) sam_template.set.assert_called_with(IMPLICIT_API_LOGICAL_ID, ImplicitApiResource().to_dict()) - # Make sure this is called only for Functions - sam_template.iterate.assert_any_call("AWS::Serverless::Function") - sam_template.iterate.assert_any_call("AWS::Serverless::Api") + # Make sure this is called only for Functions and State Machines + sam_template.iterate.assert_any_call({"AWS::Serverless::Function", "AWS::Serverless::StateMachine"}) + sam_template.iterate.assert_any_call({"AWS::Serverless::Api"}) self.plugin._get_api_events.assert_has_calls([call(function1), call(function2), call(function3)]) self.plugin._process_api_events.assert_has_calls( @@ -104,6 +104,43 @@ def test_must_process_functions(self, SamTemplateMock): self.plugin._maybe_remove_implicit_api.assert_called_with(sam_template) + @patch("samtranslator.plugins.api.implicit_api_plugin.SamTemplate") + def test_must_process_state_machines(self, SamTemplateMock): + + template_dict = {"a": "b"} + statemachine1 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine2 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine3 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine_resources = [("id1", statemachine1), ("id2", statemachine2), ("id3", statemachine3)] + api_events = ["event1", "event2"] + + sam_template = Mock() + SamTemplateMock.return_value = sam_template + sam_template.set = Mock() + sam_template.iterate = Mock() + sam_template.iterate.return_value = statemachine_resources + self.plugin._get_api_events.return_value = api_events + + self.plugin.on_before_transform_template(template_dict) + + SamTemplateMock.assert_called_with(template_dict) + sam_template.set.assert_called_with(IMPLICIT_API_LOGICAL_ID, ImplicitApiResource().to_dict()) + + # Make sure this is called only for Functions and State Machines + sam_template.iterate.assert_any_call({"AWS::Serverless::Function", "AWS::Serverless::StateMachine"}) + sam_template.iterate.assert_any_call({"AWS::Serverless::Api"}) + + self.plugin._get_api_events.assert_has_calls([call(statemachine1), call(statemachine2), call(statemachine3)]) + self.plugin._process_api_events.assert_has_calls( + [ + call(statemachine1, ["event1", "event2"], sam_template, None), + call(statemachine2, ["event1", "event2"], sam_template, None), + call(statemachine3, ["event1", "event2"], sam_template, None), + ] + ) + + self.plugin._maybe_remove_implicit_api.assert_called_with(sam_template) + @patch("samtranslator.plugins.api.implicit_api_plugin.SamTemplate") def test_must_skip_functions_without_events(self, SamTemplateMock): @@ -130,10 +167,35 @@ def test_must_skip_functions_without_events(self, SamTemplateMock): self.plugin._maybe_remove_implicit_api.assert_called_with(sam_template) @patch("samtranslator.plugins.api.implicit_api_plugin.SamTemplate") - def test_must_skip_without_functions(self, SamTemplateMock): + def test_must_skip_state_machines_without_events(self, SamTemplateMock): + + template_dict = {"a": "b"} + statemachine1 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine2 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine3 = SamResource({"Type": "AWS::Serverless::StateMachine"}) + statemachine_resources = [("id1", statemachine1), ("id2", statemachine2), ("id3", statemachine3)] + # NO EVENTS for any state machine + api_events = [] + + sam_template = Mock() + SamTemplateMock.return_value = sam_template + sam_template.set = Mock() + sam_template.iterate = Mock() + sam_template.iterate.return_value = statemachine_resources + self.plugin._get_api_events.return_value = api_events + + self.plugin.on_before_transform_template(template_dict) + + self.plugin._get_api_events.assert_has_calls([call(statemachine1), call(statemachine2), call(statemachine3)]) + self.plugin._process_api_events.assert_not_called() + + self.plugin._maybe_remove_implicit_api.assert_called_with(sam_template) + + @patch("samtranslator.plugins.api.implicit_api_plugin.SamTemplate") + def test_must_skip_without_functions_or_statemachines(self, SamTemplateMock): template_dict = {"a": "b"} - # NO FUNCTIONS + # NO FUNCTIONS OR STATE MACHINES function_resources = [] sam_template = Mock() diff --git a/tests/plugins/application/test_serverless_app_plugin.py b/tests/plugins/application/test_serverless_app_plugin.py index 3dd4449c4..b27d0fb2e 100644 --- a/tests/plugins/application/test_serverless_app_plugin.py +++ b/tests/plugins/application/test_serverless_app_plugin.py @@ -125,7 +125,7 @@ def test_must_process_applications(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) # Make sure this is called only for Apis - sam_template.iterate.assert_called_with("AWS::Serverless::Application") + sam_template.iterate.assert_called_with({"AWS::Serverless::Application"}) @patch("samtranslator.plugins.application.serverless_app_plugin.SamTemplate") @patch("botocore.client.BaseClient._make_api_call", mock_get_application) @@ -150,7 +150,7 @@ def test_must_process_applications_validate(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) # Make sure this is called only for Apis - sam_template.iterate.assert_called_with("AWS::Serverless::Application") + sam_template.iterate.assert_called_with({"AWS::Serverless::Application"}) @patch("samtranslator.plugins.application.serverless_app_plugin.SamTemplate") @patch("botocore.client.BaseClient._make_api_call", mock_create_cloud_formation_template) @@ -174,7 +174,7 @@ def test_process_invalid_applications(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) # Make sure this is called only for Apis - sam_template.iterate.assert_called_with("AWS::Serverless::Application") + sam_template.iterate.assert_called_with({"AWS::Serverless::Application"}) @patch("samtranslator.plugins.application.serverless_app_plugin.SamTemplate") @patch("botocore.client.BaseClient._make_api_call", mock_get_application) @@ -198,7 +198,7 @@ def test_process_invalid_applications_validate(self, SamTemplateMock): SamTemplateMock.assert_called_with(template_dict) # Make sure this is called only for Apis - sam_template.iterate.assert_called_with("AWS::Serverless::Application") + sam_template.iterate.assert_called_with({"AWS::Serverless::Application"}) @patch("botocore.client.ClientEndpointBridge._check_default_region", mock_get_region) def test_sar_service_calls(self): diff --git a/tests/plugins/policies/test_policy_templates_plugin.py b/tests/plugins/policies/test_policy_templates_plugin.py index 9faad31d6..ce16bc92a 100644 --- a/tests/plugins/policies/test_policy_templates_plugin.py +++ b/tests/plugins/policies/test_policy_templates_plugin.py @@ -2,20 +2,20 @@ from mock import Mock, MagicMock, patch, call from samtranslator.plugins import BasePlugin -from samtranslator.model.function_policies import PolicyTypes, PolicyEntry +from samtranslator.model.resource_policies import PolicyTypes, PolicyEntry from samtranslator.model.exceptions import InvalidResourceException -from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForFunctionPlugin +from samtranslator.plugins.policies.policy_templates_plugin import PolicyTemplatesForResourcePlugin from samtranslator.policy_template_processor.exceptions import InsufficientParameterValues, InvalidParameterValues -class TestPolicyTemplatesForFunctionPlugin(TestCase): +class TestPolicyTemplatesForResourcePlugin(TestCase): def setUp(self): self._policy_template_processor_mock = Mock() - self.plugin = PolicyTemplatesForFunctionPlugin(self._policy_template_processor_mock) + self.plugin = PolicyTemplatesForResourcePlugin(self._policy_template_processor_mock) def test_plugin_must_setup_correct_name(self): # Name is the class name - expected_name = "PolicyTemplatesForFunctionPlugin" + expected_name = "PolicyTemplatesForResourcePlugin" self.assertEqual(self.plugin.name, expected_name) @@ -30,7 +30,7 @@ def test_must_not_support_non_function_resources(self): resource_type = "AWS::Serverless::Api" self.assertFalse(self.plugin._is_supported(resource_type)) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_resource_must_work_on_every_policy_template(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock @@ -69,7 +69,7 @@ def test_on_before_transform_resource_must_work_on_every_policy_template(self, f [call("MyTemplate1", {"Param1": "value1"}), call("MyTemplate2", {"Param2": "value2"})] ) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_resource_must_skip_non_policy_templates(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock @@ -114,7 +114,7 @@ def test_on_before_transform_resource_must_skip_non_policy_templates(self, funct [call("MyTemplate1", {"Param1": "value1"}), call("MyTemplate2", {"Param2": "value2"})] ) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_must_raise_on_insufficient_parameter_values(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock @@ -141,7 +141,7 @@ def test_on_before_transform_must_raise_on_insufficient_parameter_values(self, f # Make sure the input was not changed self.assertEqual(resource_properties, {"Policies": {"MyTemplate1": {"Param1": "value1"}}}) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_must_raise_on_invalid_parameter_values(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock @@ -167,7 +167,7 @@ def test_on_before_transform_must_raise_on_invalid_parameter_values(self, functi # Make sure the input was not changed self.assertEqual(resource_properties, {"Policies": {"MyTemplate1": {"Param1": "value1"}}}) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_must_bubble_exception(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock @@ -206,7 +206,7 @@ def test_on_before_transform_resource_must_skip_unsupported_resources(self): # Make sure none of the data elements were accessed, because the method returned immediately self.assertEqual([], data_mock.method_calls) - @patch("samtranslator.plugins.policies.policy_templates_plugin.FunctionPolicies") + @patch("samtranslator.plugins.policies.policy_templates_plugin.ResourcePolicies") def test_on_before_transform_resource_must_skip_function_with_no_policies(self, function_policies_class_mock): is_supported_mock = Mock() self.plugin._is_supported = is_supported_mock diff --git a/tests/sdk/test_template.py b/tests/sdk/test_template.py index 161833b2a..64e5247b7 100644 --- a/tests/sdk/test_template.py +++ b/tests/sdk/test_template.py @@ -43,7 +43,7 @@ def test_iterate_must_filter_by_resource_type(self): ("Function2", {"Type": "AWS::Serverless::Function", "a": "b", "Properties": {}}), ] - actual = [(id, resource.to_dict()) for id, resource in template.iterate(type)] + actual = [(id, resource.to_dict()) for id, resource in template.iterate({type})] self.assertEqual(expected, actual) def test_iterate_must_filter_by_layers_resource_type(self): @@ -52,7 +52,7 @@ def test_iterate_must_filter_by_layers_resource_type(self): type = "AWS::Serverless::LayerVersion" expected = [("Layer", {"Type": "AWS::Serverless::LayerVersion", "Properties": {}})] - actual = [(id, resource.to_dict()) for id, resource in template.iterate(type)] + actual = [(id, resource.to_dict()) for id, resource in template.iterate({type})] self.assertEqual(expected, actual) def test_iterate_must_not_return_non_sam_resources_with_filter(self): @@ -61,7 +61,7 @@ def test_iterate_must_not_return_non_sam_resources_with_filter(self): type = "AWS::Lambda::Function" expected = [] - actual = [(id, resource.to_dict()) for id, resource in template.iterate(type)] + actual = [(id, resource.to_dict()) for id, resource in template.iterate({type})] self.assertEqual(expected, actual) def test_iterate_must_filter_with_resource_not_found(self): @@ -70,7 +70,7 @@ def test_iterate_must_filter_with_resource_not_found(self): type = "AWS::Serverless::SimpleTable" expected = [] - actual = [(id, resource.to_dict()) for id, resource in template.iterate(type)] + actual = [(id, resource.to_dict()) for id, resource in template.iterate({type})] self.assertEqual(expected, actual) def test_set_must_add_to_template(self): diff --git a/tests/translator/input/error_state_machine_definition_string.yaml b/tests/translator/input/error_state_machine_definition_string.yaml new file mode 100644 index 000000000..dbb00ca8a --- /dev/null +++ b/tests/translator/input/error_state_machine_definition_string.yaml @@ -0,0 +1,12 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Definition: "{}" + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Deny + Action: "*" + Resource: "*" diff --git a/tests/translator/input/error_state_machine_invalid_s3_object.yaml b/tests/translator/input/error_state_machine_invalid_s3_object.yaml new file mode 100644 index 000000000..426e22515 --- /dev/null +++ b/tests/translator/input/error_state_machine_invalid_s3_object.yaml @@ -0,0 +1,13 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + DefinitionUri: + Bucket: my-sam-demo-bucket + Version: 3 + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Deny + Action: "*" + Resource: "*" diff --git a/tests/translator/input/error_state_machine_invalid_s3_string.yaml b/tests/translator/input/error_state_machine_invalid_s3_string.yaml new file mode 100644 index 000000000..7e05010e0 --- /dev/null +++ b/tests/translator/input/error_state_machine_invalid_s3_string.yaml @@ -0,0 +1,11 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + DefinitionUri: my-invalid-s3-uri + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Deny + Action: "*" + Resource: "*" diff --git a/tests/translator/input/error_state_machine_with_api_auth_none.yaml b/tests/translator/input/error_state_machine_with_api_auth_none.yaml new file mode 100644 index 000000000..b044ab072 --- /dev/null +++ b/tests/translator/input/error_state_machine_with_api_auth_none.yaml @@ -0,0 +1,54 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + ApiKeyRequired: true + Authorizers: + MyLambdaTokenAuth: + FunctionPayloadType: TOKEN + FunctionArn: arn:aws + FunctionInvokeRole: arn:aws:iam::123456789012:role/S3Access + Identity: + Header: MyCustomAuthHeader + ValidationExpression: mycustomauthexpression + ReauthorizeEvery: 20 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + WithNoAuthorizer: + Type: Api + Properties: + Path: /startNoAuth + Method: post + WithLambdaTokenAuth: + Type: Api + Properties: + Path: /startWithLambdaToken + Method: post + RestApiId: !Ref MyApi + Auth: + Authorizer: NONE diff --git a/tests/translator/input/error_state_machine_with_no_api_authorizers.yaml b/tests/translator/input/error_state_machine_with_no_api_authorizers.yaml new file mode 100644 index 000000000..1f3dcf104 --- /dev/null +++ b/tests/translator/input/error_state_machine_with_no_api_authorizers.yaml @@ -0,0 +1,43 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + WithNoAuthorizer: + Type: Api + Properties: + Path: /startNoAuth + Method: post + WithLambdaTokenAuth: + Type: Api + Properties: + Path: /startWithLambdaToken + Method: post + RestApiId: !Ref MyApi + Auth: + Authorizer: MyUndefinedAuthorizer diff --git a/tests/translator/input/error_state_machine_with_undefined_api_authorizer.yaml b/tests/translator/input/error_state_machine_with_undefined_api_authorizer.yaml new file mode 100644 index 000000000..fa81cb741 --- /dev/null +++ b/tests/translator/input/error_state_machine_with_undefined_api_authorizer.yaml @@ -0,0 +1,55 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: MyLambdaTokenAuth + ApiKeyRequired: true + Authorizers: + MyLambdaTokenAuth: + FunctionPayloadType: TOKEN + FunctionArn: arn:aws + FunctionInvokeRole: arn:aws:iam::123456789012:role/S3Access + Identity: + Header: MyCustomAuthHeader + ValidationExpression: mycustomauthexpression + ReauthorizeEvery: 20 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + WithNoAuthorizer: + Type: Api + Properties: + Path: /startNoAuth + Method: post + WithLambdaTokenAuth: + Type: Api + Properties: + Path: /startWithLambdaToken + Method: post + RestApiId: !Ref MyApi + Auth: + Authorizer: MyUndefinedAuthorizer diff --git a/tests/translator/input/state_machine_with_api_auth_default_scopes.yaml b/tests/translator/input/state_machine_with_api_auth_default_scopes.yaml new file mode 100644 index 000000000..87cd87030 --- /dev/null +++ b/tests/translator/input/state_machine_with_api_auth_default_scopes.yaml @@ -0,0 +1,105 @@ +Resources: + MyApiWithCognitoAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + OpenApiVersion: "3.0.1" + Auth: + DefaultAuthorizer: MyDefaultCognitoAuth + Authorizers: + MyDefaultCognitoAuth: + UserPoolArn: arn:aws:1 + AuthorizationScopes: + - default.write + - default.read + MyCognitoAuthWithDefaultScopes: + UserPoolArn: arn:aws:2 + AuthorizationScopes: + - default.delete + - default.update + + MyStateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + CognitoAuthorizerWithDefaultScopes: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitoauthorizerwithdefaultscopes + Auth: + Authorizer: MyCognitoAuthWithDefaultScopes + CognitoDefaultScopesDefaultAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitodefaultscopesdefaultauthorizer + CognitoWithAuthNone: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitowithauthnone + Auth: + Authorizer: NONE + CognitoDefaultScopesWithOverwritten: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitodefaultscopesoverwritten + Auth: + Authorizer: MyDefaultCognitoAuth + AuthorizationScopes: + - overwritten.read + - overwritten.write + CognitoAuthorizerScopesOverwritten: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitoauthorizercopesoverwritten + Auth: + Authorizer: MyCognitoAuthWithDefaultScopes + AuthorizationScopes: + - overwritten.read + - overwritten.write + CognitoDefaultScopesNone: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitodefaultscopesnone + Auth: + Authorizer: MyDefaultCognitoAuth + AuthorizationScopes: [] + CognitoDefaultAuthDefaultScopesNone: + Type: Api + Properties: + RestApiId: !Ref MyApiWithCognitoAuth + Method: get + Path: /cognitodefaultauthdefaultscopesnone + Auth: + Authorizer: MyCognitoAuthWithDefaultScopes + AuthorizationScopes: [] diff --git a/tests/translator/input/state_machine_with_api_authorizer.yaml b/tests/translator/input/state_machine_with_api_authorizer.yaml new file mode 100644 index 000000000..1940b0ed0 --- /dev/null +++ b/tests/translator/input/state_machine_with_api_authorizer.yaml @@ -0,0 +1,55 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: MyLambdaTokenAuth + ApiKeyRequired: true + Authorizers: + MyLambdaTokenAuth: + FunctionPayloadType: TOKEN + FunctionArn: arn:aws + FunctionInvokeRole: arn:aws:iam::123456789012:role/S3Access + Identity: + Header: MyCustomAuthHeader + ValidationExpression: mycustomauthexpression + ReauthorizeEvery: 20 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + WithNoAuthorizer: + Type: Api + Properties: + Path: /startNoAuth + Method: post + WithLambdaTokenAuth: + Type: Api + Properties: + Path: /startWithLambdaToken + Method: post + RestApiId: !Ref MyApi + Auth: + Authorizer: MyLambdaTokenAuth diff --git a/tests/translator/input/state_machine_with_api_authorizer_maximum.yaml b/tests/translator/input/state_machine_with_api_authorizer_maximum.yaml new file mode 100644 index 000000000..31b235666 --- /dev/null +++ b/tests/translator/input/state_machine_with_api_authorizer_maximum.yaml @@ -0,0 +1,123 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: MyCognitoAuth + ApiKeyRequired: true + Authorizers: + MyCognitoAuth: + UserPoolArn: arn:aws:1 + Identity: + Header: MyAuthorizationHeader + ValidationExpression: myauthvalidationexpression + + MyCognitoAuthMultipleUserPools: + UserPoolArn: + - arn:aws:2 + - arn:aws:3 + Identity: + Header: MyAuthorizationHeader2 + ValidationExpression: myauthvalidationexpression2 + + MyLambdaTokenAuth: + FunctionPayloadType: TOKEN + FunctionArn: arn:aws + FunctionInvokeRole: arn:aws:iam::123456789012:role/S3Access + Identity: + Header: MyCustomAuthHeader + ValidationExpression: mycustomauthexpression + ReauthorizeEvery: 20 + + MyLambdaTokenAuthNoneFunctionInvokeRole: + FunctionArn: arn:aws + FunctionInvokeRole: NONE + Identity: + ReauthorizeEvery: 0 + + MyLambdaRequestAuth: + FunctionPayloadType: REQUEST + FunctionArn: arn:aws + FunctionInvokeRole: arn:aws:iam::123456789012:role/S3Access + Identity: + Headers: + - Authorization1 + QueryStrings: + - Authorization2 + StageVariables: + - Authorization3 + Context: + - Authorization4 + ReauthorizeEvery: 0 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + WithNoAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: / + Method: get + Auth: + Authorizer: NONE + WithCognitoMultipleUserPoolsAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: /users + Method: post + Auth: + Authorizer: MyCognitoAuthMultipleUserPools + WithLambdaTokenAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: /users + Method: get + Auth: + Authorizer: MyLambdaTokenAuth + WithLambdaTokenAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: /users + Method: patch + Auth: + Authorizer: MyLambdaTokenAuthNoneFunctionInvokeRole + WithLambdaRequestAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: /users + Method: delete + Auth: + Authorizer: MyLambdaRequestAuth + WithDefaultAuthorizer: + Type: Api + Properties: + RestApiId: !Ref MyApi + Path: /users + Method: put \ No newline at end of file diff --git a/tests/translator/input/state_machine_with_api_resource_policy.yaml b/tests/translator/input/state_machine_with_api_resource_policy.yaml new file mode 100644 index 000000000..8ca0bbed1 --- /dev/null +++ b/tests/translator/input/state_machine_with_api_resource_policy.yaml @@ -0,0 +1,58 @@ +Resources: + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + + MyStateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + GetHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /one + Method: get + Auth: + ResourcePolicy: + IpRangeWhitelist: ["1.2.3.4"] + IpRangeBlacklist: ["1.2.3.4"] + PostHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /two + Method: post + Auth: + ResourcePolicy: + IpRangeWhitelist: ["1.2.3.4"] + IpRangeBlacklist: ["1.2.3.4"] + PutHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /three + Method: put diff --git a/tests/translator/input/state_machine_with_condition.yaml b/tests/translator/input/state_machine_with_condition.yaml new file mode 100644 index 000000000..58f2227da --- /dev/null +++ b/tests/translator/input/state_machine_with_condition.yaml @@ -0,0 +1,16 @@ +Conditions: + TestCondition: + Fn::Equals: + - test + - test +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Condition: "TestCondition" + Properties: + Name: MyStateMachine + DefinitionUri: + Bucket: sam-demo-bucket + Key: my-state-machine.asl.json + Version: 3 + Role: arn:aws:iam::123456123456:role/service-role/SampleRole diff --git a/tests/translator/input/state_machine_with_condition_and_events.yaml b/tests/translator/input/state_machine_with_condition_and_events.yaml new file mode 100644 index 000000000..710eb4bd3 --- /dev/null +++ b/tests/translator/input/state_machine_with_condition_and_events.yaml @@ -0,0 +1,34 @@ +Conditions: + TestCondition: + Fn::Equals: + - test + - test +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Condition: "TestCondition" + Properties: + Name: MyStateMachine + Events: + ScheduleEvent: + Type: Schedule + Properties: + Schedule: "rate(1 minute)" + Name: TestSchedule + CWEvent: + Type: CloudWatchEvent + Properties: + Pattern: + detail: + state: + - terminated + MyApiEvent: + Type: Api + Properties: + Path: /startMyExecution + Method: post + DefinitionUri: + Bucket: sam-demo-bucket + Key: my-state-machine.asl.json + Version: 3 + Role: arn:aws:iam::123456123456:role/service-role/SampleRole diff --git a/tests/translator/input/state_machine_with_cwe.yaml b/tests/translator/input/state_machine_with_cwe.yaml new file mode 100644 index 000000000..488d8dc99 --- /dev/null +++ b/tests/translator/input/state_machine_with_cwe.yaml @@ -0,0 +1,14 @@ +Resources: + StateMachine: + Type: 'AWS::Serverless::StateMachine' + Properties: + DefinitionUri: s3://sam-demo-bucket/my_state_machine.asl.json + Role: arn:aws:iam::123456123456:role/service-role/SampleRole + Events: + CWEvent: + Type: CloudWatchEvent + Properties: + Pattern: + detail: + state: + - terminated diff --git a/tests/translator/input/state_machine_with_definition_S3_object.yaml b/tests/translator/input/state_machine_with_definition_S3_object.yaml new file mode 100644 index 000000000..7a9923f2b --- /dev/null +++ b/tests/translator/input/state_machine_with_definition_S3_object.yaml @@ -0,0 +1,26 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + ReservedConcurrentExecutions: 100 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachineWithDefinitionInS3 + Type: STANDARD + DefinitionUri: + Bucket: sam-demo-bucket + Key: my-state-machine.asl.json + Version: 3 + DefinitionSubstitutions: + my_lambda_arn: !GetAtt MyFunction.Arn + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn diff --git a/tests/translator/input/state_machine_with_definition_S3_string.yaml b/tests/translator/input/state_machine_with_definition_S3_string.yaml new file mode 100644 index 000000000..c26974b90 --- /dev/null +++ b/tests/translator/input/state_machine_with_definition_S3_string.yaml @@ -0,0 +1,23 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + ReservedConcurrentExecutions: 100 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachineWithDefinitionInS3 + Type: STANDARD + DefinitionUri: s3://sam-demo-bucket/my-state-machine.asl.json + DefinitionSubstitutions: + my_lambda_arn: !GetAtt MyFunction.Arn + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn diff --git a/tests/translator/input/state_machine_with_definition_substitutions.yaml b/tests/translator/input/state_machine_with_definition_substitutions.yaml new file mode 100644 index 000000000..1558eebeb --- /dev/null +++ b/tests/translator/input/state_machine_with_definition_substitutions.yaml @@ -0,0 +1,32 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: "${my_state_var_1}" + Result: Hello + Next: World + World: + Type: "${my_state_var_2}" + Resource: !GetAtt MyFunction.Arn + End: true + DefinitionSubstitutions: + my_state_var_1: Pass + my_state_var_2: Task + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn diff --git a/tests/translator/input/state_machine_with_explicit_api.yaml b/tests/translator/input/state_machine_with_explicit_api.yaml new file mode 100644 index 000000000..6f07fbba0 --- /dev/null +++ b/tests/translator/input/state_machine_with_explicit_api.yaml @@ -0,0 +1,36 @@ +Resources: + MyApi: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + MyApiEvent: + Type: Api + Properties: + Path: /startMyExecution + Method: post + RestApiId: !Ref MyApi diff --git a/tests/translator/input/state_machine_with_express_logging.yaml b/tests/translator/input/state_machine_with_express_logging.yaml new file mode 100644 index 000000000..29d253a50 --- /dev/null +++ b/tests/translator/input/state_machine_with_express_logging.yaml @@ -0,0 +1,48 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + + ExpressLogGroup: + Type: AWS::Logs::LogGroup + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStandardStateMachineWithLogging + Type: EXPRESS + DefinitionUri: + Bucket: sam-demo-bucket + Key: my-state-machine.asl.json + Version: 3 + DefinitionSubstitutions: + my_lambda_arn: !GetAtt MyFunction.Arn + Logging: + Level: FATAL + IncludeExecutionData: False + Destinations: + - CloudWatchLogsLogGroup: + LogGroupArn: !GetAtt ExpressLogGroup.Arn + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "logs:CreateLogDelivery" + - "logs:GetLogDelivery" + - "logs:UpdateLogDelivery" + - "logs:DeleteLogDelivery" + - "logs:ListLogDeliveries" + - "logs:PutResourcePolicy" + - "logs:DescribeResourcePolicies" + - "logs:DescribeLogGroups" + Resource: + - "*" diff --git a/tests/translator/input/state_machine_with_implicit_api.yaml b/tests/translator/input/state_machine_with_implicit_api.yaml new file mode 100644 index 000000000..368285562 --- /dev/null +++ b/tests/translator/input/state_machine_with_implicit_api.yaml @@ -0,0 +1,30 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + MyApiEvent: + Type: Api + Properties: + Path: /startMyExecution + Method: post diff --git a/tests/translator/input/state_machine_with_implicit_api_globals.yaml b/tests/translator/input/state_machine_with_implicit_api_globals.yaml new file mode 100644 index 000000000..5c1c227c0 --- /dev/null +++ b/tests/translator/input/state_machine_with_implicit_api_globals.yaml @@ -0,0 +1,35 @@ +Globals: + Api: + Auth: + ResourcePolicy: + AwsAccountBlacklist: ["12345"] +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Events: + MyApiEvent: + Type: Api + Properties: + Path: /startMyExecution + Method: post diff --git a/tests/translator/input/state_machine_with_inline_definition.yaml b/tests/translator/input/state_machine_with_inline_definition.yaml new file mode 100644 index 000000000..f77f25a2e --- /dev/null +++ b/tests/translator/input/state_machine_with_inline_definition.yaml @@ -0,0 +1,24 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyBasicStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Deny + Action: "*" + Resource: "*" diff --git a/tests/translator/input/state_machine_with_inline_definition_intrinsics.yaml b/tests/translator/input/state_machine_with_inline_definition_intrinsics.yaml new file mode 100644 index 000000000..2949605fb --- /dev/null +++ b/tests/translator/input/state_machine_with_inline_definition_intrinsics.yaml @@ -0,0 +1,32 @@ +Resources: + MyFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + ReservedConcurrentExecutions: 100 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyBasicStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Task + Resource: !GetAtt MyFunction.Arn + End: true + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn diff --git a/tests/translator/input/state_machine_with_inline_policies.yaml b/tests/translator/input/state_machine_with_inline_policies.yaml new file mode 100644 index 000000000..1d68c6b82 --- /dev/null +++ b/tests/translator/input/state_machine_with_inline_policies.yaml @@ -0,0 +1,32 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + ReservedConcurrentExecutions: 100 + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyBasicStateMachine + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Task + Resource: !GetAtt MyFunction.Arn + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn diff --git a/tests/translator/input/state_machine_with_managed_policy.yaml b/tests/translator/input/state_machine_with_managed_policy.yaml new file mode 100644 index 000000000..3479983dc --- /dev/null +++ b/tests/translator/input/state_machine_with_managed_policy.yaml @@ -0,0 +1,9 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachineWithManagedPolicy + Type: STANDARD + DefinitionUri: s3://sam-demo-bucket/my-state-machine.asl.json + Policies: + - AmazonDynamoDBFullAccess diff --git a/tests/translator/input/state_machine_with_role.yaml b/tests/translator/input/state_machine_with_role.yaml new file mode 100644 index 000000000..1d0885f5f --- /dev/null +++ b/tests/translator/input/state_machine_with_role.yaml @@ -0,0 +1,8 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachineWithRole + Type: STANDARD + DefinitionUri: s3://sam-demo-bucket/my-state-machine.asl.json + Role: arn:aws:iam::123456123456:role/service-role/SampleRole diff --git a/tests/translator/input/state_machine_with_sam_policy_templates.yaml b/tests/translator/input/state_machine_with_sam_policy_templates.yaml new file mode 100644 index 000000000..a099fc204 --- /dev/null +++ b/tests/translator/input/state_machine_with_sam_policy_templates.yaml @@ -0,0 +1,126 @@ +Resources: + StarterLambda: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/starter.zip + Handler: starter.handler + Runtime: python2.7 + + ProcessingQueue: + Type: AWS::SQS::Queue + + ResolverLambda: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/resolver.zip + Handler: resolver.handler + Runtime: python3.8 + + NestedWorkflow: + Type: AWS::Serverless::StateMachine + Properties: + Type: STANDARD + Definition: + Comment: An example ASL file for nested workflows + StartAt: NestedStateOne + States: + NestedStateOne: + Type: Pass + Result: + Value: MyValue + Next: NestedStateTwo + NestedStateTwo: + Type: Task + Resource: !GetAtt StarterLambda.Arn + End: True + Role: arn:aws:iam::123456123456:role/service-role/SampleRole + + OutputStore: + Type: AWS::Serverless::SimpleTable + Properties: + TableName: MySimpleTable + + ProcessingWorkflow: + Type: AWS::Serverless::StateMachine + Properties: + Type: STANDARD + Definition: + Comment: An example ASL file with parallel states + StartAt: StateOne + States: + StateOne: + Type: Pass + Result: + Value: MyValue + Next: StateTwo + StateTwo: + Type: Parallel + End: true + Branches: + - StartAt: BranchOne_StateOne + States: + BranchOne_StateOne: + Type: Task + Resource: !GetAtt StarterLambda.Arn + Next: BranchOne_StateTwo + BranchOne_StateTwo: + Type: Task + Resource: arn:aws:states:::sqs:sendMessage.waitForTaskToken + Parameters: + QueueUrl: !Ref ProcessingQueue + MessageBody.$: "$.input.message" + Next: BranchOne_StateThree + BranchOne_StateThree: + Type: Task + Resource: arn:aws:states:::lambda:invoke + Parameters: + FunctionName: !Ref ResolverLambda + Next: BranchOne_StateFour + BranchOne_StateFour: + Type: Choice + Choices: + - Variable: "$.value" + NumericEquals: 0 + Next: ValueIsZero + - Variable: "$.value" + NumericEquals: 1 + Next: ValueIsOne + ValueIsZero: + Type: Fail + ValueIsOne: + Type: Succeed + - StartAt: BranchTwo_StateOne + States: + BranchTwo_StateOne: + Type: Task + Resource: arn:aws:states:::states:startExecution.sync + Parameters: + StateMachineArn: !Ref NestedWorkflow + Input: + KeyA: ValueA + KeyC: ValueC + Next: BranchTwo_StateTwo + BranchTwo_StateTwo: + Type: Task + Resource: arn:aws:states:::dynamodb:putItem + Parameters: + TableName: !Ref OutputStore + Item: + MessageId: + S.$: "$.MessageDetails.MessageId" + Body: + S.$: "$.MessageDetails.Body" + Next: BranchTwo_StateThree + BranchTwo_StateThree: + Type: Succeed + Policies: + - LambdaInvokePolicy: + FunctionName: !Ref StarterLambda + - SQSSendMessagePolicy: + QueueName: !GetAtt ProcessingQueue.QueueName + - LambdaInvokePolicy: + FunctionName: !Ref ResolverLambda + - StepFunctionsExecutionPolicy: + StateMachineName: !GetAtt NestedWorkflow.Name + - DynamoDBWritePolicy: + TableName: !Ref OutputStore \ No newline at end of file diff --git a/tests/translator/input/state_machine_with_schedule.yaml b/tests/translator/input/state_machine_with_schedule.yaml new file mode 100644 index 000000000..324ce30f8 --- /dev/null +++ b/tests/translator/input/state_machine_with_schedule.yaml @@ -0,0 +1,14 @@ +Resources: + StateMachine: + Type: 'AWS::Serverless::StateMachine' + Properties: + DefinitionUri: s3://sam-demo-bucket/my_state_machine.asl.json + Role: arn:aws:iam::123456123456:role/service-role/SampleRole + Events: + ScheduleEvent: + Type: Schedule + Properties: + Schedule: 'rate(1 minute)' + Name: TestSchedule + Description: test schedule + Enabled: False \ No newline at end of file diff --git a/tests/translator/input/state_machine_with_standard_logging.yaml b/tests/translator/input/state_machine_with_standard_logging.yaml new file mode 100644 index 000000000..529a1a1dd --- /dev/null +++ b/tests/translator/input/state_machine_with_standard_logging.yaml @@ -0,0 +1,48 @@ +Resources: + MyFunction: + Type: "AWS::Serverless::Function" + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + + StandardLogGroup: + Type: AWS::Logs::LogGroup + + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStandardStateMachineWithLogging + Type: STANDARD + DefinitionUri: + Bucket: sam-demo-bucket + Key: my-state-machine.asl.json + Version: 3 + DefinitionSubstitutions: + my_lambda_arn: !GetAtt MyFunction.Arn + Logging: + Level: ALL + IncludeExecutionData: True + Destinations: + - CloudWatchLogsLogGroup: + LogGroupArn: !GetAtt StandardLogGroup.Arn + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: !GetAtt MyFunction.Arn + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "logs:CreateLogDelivery" + - "logs:GetLogDelivery" + - "logs:UpdateLogDelivery" + - "logs:DeleteLogDelivery" + - "logs:ListLogDeliveries" + - "logs:PutResourcePolicy" + - "logs:DescribeResourcePolicies" + - "logs:DescribeLogGroups" + Resource: + - "*" diff --git a/tests/translator/input/state_machine_with_tags.yaml b/tests/translator/input/state_machine_with_tags.yaml new file mode 100644 index 000000000..dd1e15b12 --- /dev/null +++ b/tests/translator/input/state_machine_with_tags.yaml @@ -0,0 +1,27 @@ +Resources: + StateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Name: MyStateMachineWithTags + Type: STANDARD + Definition: + Comment: A Hello World example of the Amazon States Language using Pass states + StartAt: Hello + States: + Hello: + Type: Pass + Result: Hello + Next: World + World: + Type: Pass + Result: World + End: true + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Deny + Action: "*" + Resource: "*" + Tags: + TagOne: ValueOne + TagTwo: ValueTwo diff --git a/tests/translator/output/aws-cn/state_machine_with_api_auth_default_scopes.json b/tests/translator/output/aws-cn/state_machine_with_api_auth_default_scopes.json new file mode 100644 index 000000000..6a466f04a --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_api_auth_default_scopes.json @@ -0,0 +1,733 @@ +{ + "Resources": { + "MyApiWithCognitoAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/cognitowithauthnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoWithAuthNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultauthdefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizerwithdefaultscopes": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "default.delete", + "default.update" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizercopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesdefaultauthorizer": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "default.write", + "default.read" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "MyCognitoAuthWithDefaultScopes": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:2" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyDefaultCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyStateMachineCognitoWithAuthNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoWithAuthNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesWithOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithCognitoAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithCognitoAuthDeployment57b57dfc88" + }, + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "StageName": "Prod" + } + }, + "MyApiWithCognitoAuthDeployment57b57dfc88": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "Description": "RestApi deployment id: 57b57dfc88b1b438a0437eadd869d77e938eedb6" + } + }, + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerWithDefaultScopesRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerScopesOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_api_authorizer.json b/tests/translator/output/aws-cn/state_machine_with_api_authorizer.json new file mode 100644 index 000000000..859dea489 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_api_authorizer.json @@ -0,0 +1,384 @@ +{ + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaaffc688ce" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startNoAuth": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "StateMachineWithLambdaTokenAuthRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startWithLambdaToken": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment2d6a709a2a" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeploymentaaffc688ce": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aaffc688ce6d1b26ccd7a90641e103263f6240bb", + "StageName": "Stage" + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiDeployment2d6a709a2a": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 2d6a709a2a2b67ee19ca14fe4594114921c537d0", + "StageName": "Stage" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_api_authorizer_maximum.json b/tests/translator/output/aws-cn/state_machine_with_api_authorizer_maximum.json new file mode 100644 index 000000000..4755fb316 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_api_authorizer_maximum.json @@ -0,0 +1,690 @@ +{ + "Resources": { + "MyApiMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineWithLambdaRequestAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaRequestAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineWithDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/users": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "patch": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "delete": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaRequestAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaTokenAuthNoneFunctionInvokeRole": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 0, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuthMultipleUserPools": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineWithLambdaTokenAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "MyApiDeployment704a2ea820": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 704a2ea8202a6b11b22e31524b5e5dfa2b528378", + "StageName": "Stage" + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment704a2ea820" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithCognitoMultipleUserPoolsAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_api_resource_policy.json b/tests/translator/output/aws-cn/state_machine_with_api_resource_policy.json new file mode 100644 index 000000000..f9b4100a5 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_api_resource_policy.json @@ -0,0 +1,482 @@ +{ + "Resources": { + "MyStateMachineGetHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineGetHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/one": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineGetHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/three": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePutHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/two": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePostHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment17065a95ba" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "MyStateMachinePutHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePutHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExplicitApiDeployment17065a95ba": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 17065a95bac1ac0e3dc22fef2ff7aa228539b1d2", + "StageName": "Stage" + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachinePostHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePostHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_condition.json b/tests/translator/output/aws-cn/state_machine_with_condition.json new file mode 100644 index 000000000..7d67abe1a --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_condition.json @@ -0,0 +1,31 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_condition_and_events.json b/tests/translator/output/aws-cn/state_machine_with_condition_and_events.json new file mode 100644 index 000000000..8e0a7a0ab --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_condition_and_events.json @@ -0,0 +1,305 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaeae651245" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ], + "Name": "TestSchedule" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + }, + "Condition": "TestCondition" + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "Fn::If": [ + "TestCondition", + { + "post": { + "Fn::If": [ + "TestCondition", + { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::If": [ + "TestCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiDeploymentaeae651245": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aeae651245fe7d417a17f2bea50b255f2727e2b8", + "StageName": "Stage" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_cwe.json b/tests/translator/output/aws-cn/state_machine_with_cwe.json new file mode 100644 index 000000000..04164e943 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_cwe.json @@ -0,0 +1,83 @@ +{ + "Resources": { + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_definition_S3_object.json b/tests/translator/output/aws-cn/state_machine_with_definition_S3_object.json new file mode 100644 index 000000000..81caf3cfe --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_definition_S3_object.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_definition_S3_string.json b/tests/translator/output/aws-cn/state_machine_with_definition_S3_string.json new file mode 100644 index 000000000..97b28ece4 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_definition_S3_string.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_definition_substitutions.json b/tests/translator/output/aws-cn/state_machine_with_definition_substitutions.json new file mode 100644 index 000000000..0b6ac94f6 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_definition_substitutions.json @@ -0,0 +1,155 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "my_state_var_1": "Pass", + "my_state_var_2": "Task" + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"${my_state_var_1}\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"${my_state_var_2}\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_explicit_api.json b/tests/translator/output/aws-cn/state_machine_with_explicit_api.json new file mode 100644 index 000000000..70ef4676a --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_explicit_api.json @@ -0,0 +1,210 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_express_logging.json b/tests/translator/output/aws-cn/state_machine_with_express_logging.json new file mode 100644 index 000000000..5a5583bf6 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_express_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExpressLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": false, + "Level": "FATAL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "ExpressLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "EXPRESS", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_implicit_api.json b/tests/translator/output/aws-cn/state_machine_with_implicit_api.json new file mode 100644 index 000000000..ebb4b1c02 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_implicit_api.json @@ -0,0 +1,210 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_implicit_api_globals.json b/tests/translator/output/aws-cn/state_machine_with_implicit_api_globals.json new file mode 100644 index 000000000..c28b4704f --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_implicit_api_globals.json @@ -0,0 +1,232 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment1f01b589d4" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment1f01b589d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 1f01b589d4e226c84a3e14ca738b5d060e7b611a", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/startMyExecution", + { + "__Stage__": "Prod" + } + ] + } + ], + "Effect": "Deny", + "Principal": { + "AWS": [ + "12345" + ] + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_inline_definition.json b/tests/translator/output/aws-cn/state_machine_with_inline_definition.json new file mode 100644 index 000000000..722bc9ec7 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_inline_definition.json @@ -0,0 +1,89 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_inline_definition_intrinsics.json b/tests/translator/output/aws-cn/state_machine_with_inline_definition_intrinsics.json new file mode 100644 index 000000000..0237cf961 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_inline_definition_intrinsics.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_inline_policies.json b/tests/translator/output/aws-cn/state_machine_with_inline_policies.json new file mode 100644 index 000000000..0237cf961 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_inline_policies.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_managed_policy.json b/tests/translator/output/aws-cn/state_machine_with_managed_policy.json new file mode 100644 index 000000000..be6090ce9 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_managed_policy.json @@ -0,0 +1,57 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithManagedPolicy", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_role.json b/tests/translator/output/aws-cn/state_machine_with_role.json new file mode 100644 index 000000000..0db8c03ab --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_role.json @@ -0,0 +1,22 @@ +{ + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachineWithRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_sam_policy_templates.json b/tests/translator/output/aws-cn/state_machine_with_sam_policy_templates.json new file mode 100644 index 000000000..17fb1640d --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_sam_policy_templates.json @@ -0,0 +1,491 @@ +{ + "Resources": { + "ResolverLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "resolver.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "resolver.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ResolverLambdaRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "NestedWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file for nested workflows\",", + " \"StartAt\": \"NestedStateOne\",", + " \"States\": {", + " \"NestedStateOne\": {", + " \"Next\": \"NestedStateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"NestedStateTwo\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "starter.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "starter.zip" + }, + "Role": { + "Fn::GetAtt": [ + "StarterLambdaRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_4": { + "Ref": "NestedWorkflow" + }, + "definition_substitution_5": { + "Ref": "OutputStore" + }, + "definition_substitution_2": { + "Ref": "ResolverLambda" + }, + "definition_substitution_3": { + "Ref": "ProcessingQueue" + }, + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "ProcessingWorkflowRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file with parallel states\",", + " \"StartAt\": \"StateOne\",", + " \"States\": {", + " \"StateOne\": {", + " \"Next\": \"StateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"StateTwo\": {", + " \"Branches\": [", + " {", + " \"StartAt\": \"BranchOne_StateOne\",", + " \"States\": {", + " \"BranchOne_StateFour\": {", + " \"Choices\": [", + " {", + " \"Next\": \"ValueIsZero\",", + " \"NumericEquals\": 0,", + " \"Variable\": \"$.value\"", + " },", + " {", + " \"Next\": \"ValueIsOne\",", + " \"NumericEquals\": 1,", + " \"Variable\": \"$.value\"", + " }", + " ],", + " \"Type\": \"Choice\"", + " },", + " \"BranchOne_StateOne\": {", + " \"Next\": \"BranchOne_StateTwo\",", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateThree\": {", + " \"Next\": \"BranchOne_StateFour\",", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_2}\"", + " },", + " \"Resource\": \"arn:aws:states:::lambda:invoke\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateTwo\": {", + " \"Next\": \"BranchOne_StateThree\",", + " \"Parameters\": {", + " \"MessageBody.$\": \"$.input.message\",", + " \"QueueUrl\": \"${definition_substitution_3}\"", + " },", + " \"Resource\": \"arn:aws:states:::sqs:sendMessage.waitForTaskToken\",", + " \"Type\": \"Task\"", + " },", + " \"ValueIsOne\": {", + " \"Type\": \"Succeed\"", + " },", + " \"ValueIsZero\": {", + " \"Type\": \"Fail\"", + " }", + " }", + " },", + " {", + " \"StartAt\": \"BranchTwo_StateOne\",", + " \"States\": {", + " \"BranchTwo_StateOne\": {", + " \"Next\": \"BranchTwo_StateTwo\",", + " \"Parameters\": {", + " \"Input\": {", + " \"KeyA\": \"ValueA\",", + " \"KeyC\": \"ValueC\"", + " },", + " \"StateMachineArn\": \"${definition_substitution_4}\"", + " },", + " \"Resource\": \"arn:aws:states:::states:startExecution.sync\",", + " \"Type\": \"Task\"", + " },", + " \"BranchTwo_StateThree\": {", + " \"Type\": \"Succeed\"", + " },", + " \"BranchTwo_StateTwo\": {", + " \"Next\": \"BranchTwo_StateThree\",", + " \"Parameters\": {", + " \"Item\": {", + " \"Body\": {", + " \"S.$\": \"$.MessageDetails.Body\"", + " },", + " \"MessageId\": {", + " \"S.$\": \"$.MessageDetails.MessageId\"", + " }", + " },", + " \"TableName\": \"${definition_substitution_5}\"", + " },", + " \"Resource\": \"arn:aws:states:::dynamodb:putItem\",", + " \"Type\": \"Task\"", + " }", + " }", + " }", + " ],", + " \"End\": true,", + " \"Type\": \"Parallel\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflowRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "ProcessingWorkflowRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "StarterLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy1", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:SendMessage*" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:sqs:${AWS::Region}:${AWS::AccountId}:${queueName}", + { + "queueName": { + "Fn::GetAtt": [ + "ProcessingQueue", + "QueueName" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy2", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "ResolverLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy3", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "states:StartExecution" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${stateMachineName}", + { + "stateMachineName": { + "Fn::GetAtt": [ + "NestedWorkflow", + "Name" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy4", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:BatchWriteItem" + ], + "Resource": [ + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + }, + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/*", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + } + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "OutputStore": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "KeyType": "HASH", + "AttributeName": "id" + } + ], + "TableName": "MySimpleTable", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST" + } + }, + "ProcessingQueue": { + "Type": "AWS::SQS::Queue" + }, + "ResolverLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_schedule.json b/tests/translator/output/aws-cn/state_machine_with_schedule.json new file mode 100644 index 000000000..8730521be --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_schedule.json @@ -0,0 +1,80 @@ +{ + "Resources": { + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "State": "DISABLED", + "ScheduleExpression": "rate(1 minute)", + "Name": "TestSchedule", + "Description": "test schedule", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_standard_logging.json b/tests/translator/output/aws-cn/state_machine_with_standard_logging.json new file mode 100644 index 000000000..315b60c2f --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_standard_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StandardLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": true, + "Level": "ALL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "StandardLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/state_machine_with_tags.json b/tests/translator/output/aws-cn/state_machine_with_tags.json new file mode 100644 index 000000000..6016da420 --- /dev/null +++ b/tests/translator/output/aws-cn/state_machine_with_tags.json @@ -0,0 +1,105 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithTags", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_api_auth_default_scopes.json b/tests/translator/output/aws-us-gov/state_machine_with_api_auth_default_scopes.json new file mode 100644 index 000000000..6a466f04a --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_api_auth_default_scopes.json @@ -0,0 +1,733 @@ +{ + "Resources": { + "MyApiWithCognitoAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/cognitowithauthnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoWithAuthNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultauthdefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizerwithdefaultscopes": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "default.delete", + "default.update" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizercopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesdefaultauthorizer": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "default.write", + "default.read" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "MyCognitoAuthWithDefaultScopes": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:2" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyDefaultCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyStateMachineCognitoWithAuthNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoWithAuthNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesWithOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithCognitoAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithCognitoAuthDeployment57b57dfc88" + }, + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "StageName": "Prod" + } + }, + "MyApiWithCognitoAuthDeployment57b57dfc88": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "Description": "RestApi deployment id: 57b57dfc88b1b438a0437eadd869d77e938eedb6" + } + }, + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerWithDefaultScopesRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerScopesOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer.json b/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer.json new file mode 100644 index 000000000..c7a7a8711 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer.json @@ -0,0 +1,384 @@ +{ + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaaffc688ce" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startNoAuth": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "StateMachineWithLambdaTokenAuthRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiDeployment3c26186470": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 3c2618647036e31ff3ebf6ae8d4602ba63997fd7", + "StageName": "Stage" + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment3c26186470" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeploymentaaffc688ce": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aaffc688ce6d1b26ccd7a90641e103263f6240bb", + "StageName": "Stage" + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startWithLambdaToken": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer_maximum.json b/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer_maximum.json new file mode 100644 index 000000000..42ad354b4 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_api_authorizer_maximum.json @@ -0,0 +1,690 @@ +{ + "Resources": { + "MyApiMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineWithLambdaRequestAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaRequestAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiDeployment2120b73f3e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 2120b73f3e7efc28dc4baca314ee3b30d8d8c783", + "StageName": "Stage" + } + }, + "StateMachineWithDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineWithLambdaTokenAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment2120b73f3e" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithCognitoMultipleUserPoolsAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/users": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "patch": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "delete": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaRequestAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaTokenAuthNoneFunctionInvokeRole": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 0, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuthMultipleUserPools": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_api_resource_policy.json b/tests/translator/output/aws-us-gov/state_machine_with_api_resource_policy.json new file mode 100644 index 000000000..f9b4100a5 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_api_resource_policy.json @@ -0,0 +1,482 @@ +{ + "Resources": { + "MyStateMachineGetHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineGetHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/one": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineGetHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/three": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePutHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/two": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePostHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment17065a95ba" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "MyStateMachinePutHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePutHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExplicitApiDeployment17065a95ba": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 17065a95bac1ac0e3dc22fef2ff7aa228539b1d2", + "StageName": "Stage" + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachinePostHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePostHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_condition.json b/tests/translator/output/aws-us-gov/state_machine_with_condition.json new file mode 100644 index 000000000..7d67abe1a --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_condition.json @@ -0,0 +1,31 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_condition_and_events.json b/tests/translator/output/aws-us-gov/state_machine_with_condition_and_events.json new file mode 100644 index 000000000..8e0a7a0ab --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_condition_and_events.json @@ -0,0 +1,305 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaeae651245" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ], + "Name": "TestSchedule" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + }, + "Condition": "TestCondition" + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "Fn::If": [ + "TestCondition", + { + "post": { + "Fn::If": [ + "TestCondition", + { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::If": [ + "TestCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiDeploymentaeae651245": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aeae651245fe7d417a17f2bea50b255f2727e2b8", + "StageName": "Stage" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_cwe.json b/tests/translator/output/aws-us-gov/state_machine_with_cwe.json new file mode 100644 index 000000000..04164e943 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_cwe.json @@ -0,0 +1,83 @@ +{ + "Resources": { + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_object.json b/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_object.json new file mode 100644 index 000000000..d324146d6 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_object.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_string.json b/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_string.json new file mode 100644 index 000000000..4caed8074 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_definition_S3_string.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_definition_substitutions.json b/tests/translator/output/aws-us-gov/state_machine_with_definition_substitutions.json new file mode 100644 index 000000000..3695a061e --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_definition_substitutions.json @@ -0,0 +1,155 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "my_state_var_1": "Pass", + "my_state_var_2": "Task" + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"${my_state_var_1}\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"${my_state_var_2}\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_explicit_api.json b/tests/translator/output/aws-us-gov/state_machine_with_explicit_api.json new file mode 100644 index 000000000..70ef4676a --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_explicit_api.json @@ -0,0 +1,210 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_express_logging.json b/tests/translator/output/aws-us-gov/state_machine_with_express_logging.json new file mode 100644 index 000000000..338d3a0e7 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_express_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExpressLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": false, + "Level": "FATAL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "ExpressLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "EXPRESS", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_implicit_api.json b/tests/translator/output/aws-us-gov/state_machine_with_implicit_api.json new file mode 100644 index 000000000..ebb4b1c02 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_implicit_api.json @@ -0,0 +1,210 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_implicit_api_globals.json b/tests/translator/output/aws-us-gov/state_machine_with_implicit_api_globals.json new file mode 100644 index 000000000..c28b4704f --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_implicit_api_globals.json @@ -0,0 +1,232 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment1f01b589d4" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment1f01b589d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 1f01b589d4e226c84a3e14ca738b5d060e7b611a", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/startMyExecution", + { + "__Stage__": "Prod" + } + ] + } + ], + "Effect": "Deny", + "Principal": { + "AWS": [ + "12345" + ] + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_inline_definition.json b/tests/translator/output/aws-us-gov/state_machine_with_inline_definition.json new file mode 100644 index 000000000..722bc9ec7 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_inline_definition.json @@ -0,0 +1,89 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_inline_definition_intrinsics.json b/tests/translator/output/aws-us-gov/state_machine_with_inline_definition_intrinsics.json new file mode 100644 index 000000000..b3d2b2154 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_inline_definition_intrinsics.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_inline_policies.json b/tests/translator/output/aws-us-gov/state_machine_with_inline_policies.json new file mode 100644 index 000000000..b3d2b2154 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_inline_policies.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_managed_policy.json b/tests/translator/output/aws-us-gov/state_machine_with_managed_policy.json new file mode 100644 index 000000000..496ec9f64 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_managed_policy.json @@ -0,0 +1,57 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithManagedPolicy", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_role.json b/tests/translator/output/aws-us-gov/state_machine_with_role.json new file mode 100644 index 000000000..0db8c03ab --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_role.json @@ -0,0 +1,22 @@ +{ + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachineWithRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_sam_policy_templates.json b/tests/translator/output/aws-us-gov/state_machine_with_sam_policy_templates.json new file mode 100644 index 000000000..cc8fd1b19 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_sam_policy_templates.json @@ -0,0 +1,491 @@ +{ + "Resources": { + "ResolverLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "resolver.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "resolver.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ResolverLambdaRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "NestedWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file for nested workflows\",", + " \"StartAt\": \"NestedStateOne\",", + " \"States\": {", + " \"NestedStateOne\": {", + " \"Next\": \"NestedStateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"NestedStateTwo\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "starter.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "starter.zip" + }, + "Role": { + "Fn::GetAtt": [ + "StarterLambdaRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_4": { + "Ref": "NestedWorkflow" + }, + "definition_substitution_5": { + "Ref": "OutputStore" + }, + "definition_substitution_2": { + "Ref": "ResolverLambda" + }, + "definition_substitution_3": { + "Ref": "ProcessingQueue" + }, + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "ProcessingWorkflowRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file with parallel states\",", + " \"StartAt\": \"StateOne\",", + " \"States\": {", + " \"StateOne\": {", + " \"Next\": \"StateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"StateTwo\": {", + " \"Branches\": [", + " {", + " \"StartAt\": \"BranchOne_StateOne\",", + " \"States\": {", + " \"BranchOne_StateFour\": {", + " \"Choices\": [", + " {", + " \"Next\": \"ValueIsZero\",", + " \"NumericEquals\": 0,", + " \"Variable\": \"$.value\"", + " },", + " {", + " \"Next\": \"ValueIsOne\",", + " \"NumericEquals\": 1,", + " \"Variable\": \"$.value\"", + " }", + " ],", + " \"Type\": \"Choice\"", + " },", + " \"BranchOne_StateOne\": {", + " \"Next\": \"BranchOne_StateTwo\",", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateThree\": {", + " \"Next\": \"BranchOne_StateFour\",", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_2}\"", + " },", + " \"Resource\": \"arn:aws:states:::lambda:invoke\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateTwo\": {", + " \"Next\": \"BranchOne_StateThree\",", + " \"Parameters\": {", + " \"MessageBody.$\": \"$.input.message\",", + " \"QueueUrl\": \"${definition_substitution_3}\"", + " },", + " \"Resource\": \"arn:aws:states:::sqs:sendMessage.waitForTaskToken\",", + " \"Type\": \"Task\"", + " },", + " \"ValueIsOne\": {", + " \"Type\": \"Succeed\"", + " },", + " \"ValueIsZero\": {", + " \"Type\": \"Fail\"", + " }", + " }", + " },", + " {", + " \"StartAt\": \"BranchTwo_StateOne\",", + " \"States\": {", + " \"BranchTwo_StateOne\": {", + " \"Next\": \"BranchTwo_StateTwo\",", + " \"Parameters\": {", + " \"Input\": {", + " \"KeyA\": \"ValueA\",", + " \"KeyC\": \"ValueC\"", + " },", + " \"StateMachineArn\": \"${definition_substitution_4}\"", + " },", + " \"Resource\": \"arn:aws:states:::states:startExecution.sync\",", + " \"Type\": \"Task\"", + " },", + " \"BranchTwo_StateThree\": {", + " \"Type\": \"Succeed\"", + " },", + " \"BranchTwo_StateTwo\": {", + " \"Next\": \"BranchTwo_StateThree\",", + " \"Parameters\": {", + " \"Item\": {", + " \"Body\": {", + " \"S.$\": \"$.MessageDetails.Body\"", + " },", + " \"MessageId\": {", + " \"S.$\": \"$.MessageDetails.MessageId\"", + " }", + " },", + " \"TableName\": \"${definition_substitution_5}\"", + " },", + " \"Resource\": \"arn:aws:states:::dynamodb:putItem\",", + " \"Type\": \"Task\"", + " }", + " }", + " }", + " ],", + " \"End\": true,", + " \"Type\": \"Parallel\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflowRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "ProcessingWorkflowRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "StarterLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy1", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:SendMessage*" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:sqs:${AWS::Region}:${AWS::AccountId}:${queueName}", + { + "queueName": { + "Fn::GetAtt": [ + "ProcessingQueue", + "QueueName" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy2", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "ResolverLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy3", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "states:StartExecution" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${stateMachineName}", + { + "stateMachineName": { + "Fn::GetAtt": [ + "NestedWorkflow", + "Name" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy4", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:BatchWriteItem" + ], + "Resource": [ + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + }, + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/*", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + } + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "OutputStore": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "KeyType": "HASH", + "AttributeName": "id" + } + ], + "TableName": "MySimpleTable", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST" + } + }, + "ProcessingQueue": { + "Type": "AWS::SQS::Queue" + }, + "ResolverLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_schedule.json b/tests/translator/output/aws-us-gov/state_machine_with_schedule.json new file mode 100644 index 000000000..8730521be --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_schedule.json @@ -0,0 +1,80 @@ +{ + "Resources": { + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "State": "DISABLED", + "ScheduleExpression": "rate(1 minute)", + "Name": "TestSchedule", + "Description": "test schedule", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_standard_logging.json b/tests/translator/output/aws-us-gov/state_machine_with_standard_logging.json new file mode 100644 index 000000000..f351648c4 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_standard_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StandardLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": true, + "Level": "ALL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "StandardLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/state_machine_with_tags.json b/tests/translator/output/aws-us-gov/state_machine_with_tags.json new file mode 100644 index 000000000..6016da420 --- /dev/null +++ b/tests/translator/output/aws-us-gov/state_machine_with_tags.json @@ -0,0 +1,105 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithTags", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_definition_string.json b/tests/translator/output/error_state_machine_definition_string.json new file mode 100644 index 000000000..ff05e29ec --- /dev/null +++ b/tests/translator/output/error_state_machine_definition_string.json @@ -0,0 +1,9 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [StateMachine] is invalid. Type of property 'Definition' is invalid." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [StateMachine] is invalid. Type of property 'Definition' is invalid." +} + \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_invalid_s3_object.json b/tests/translator/output/error_state_machine_invalid_s3_object.json new file mode 100644 index 000000000..c07a486ce --- /dev/null +++ b/tests/translator/output/error_state_machine_invalid_s3_object.json @@ -0,0 +1,9 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [StateMachine] is invalid. 'DefinitionUri' requires Bucket and Key properties to be specified." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [StateMachine] is invalid. 'DefinitionUri' requires Bucket and Key properties to be specified." +} + \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_invalid_s3_string.json b/tests/translator/output/error_state_machine_invalid_s3_string.json new file mode 100644 index 000000000..1292f3011 --- /dev/null +++ b/tests/translator/output/error_state_machine_invalid_s3_string.json @@ -0,0 +1,9 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [StateMachine] is invalid. 'DefinitionUri' is not a valid S3 Uri of the form 's3://bucket/key' with optional versionId query parameter." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [StateMachine] is invalid. 'DefinitionUri' is not a valid S3 Uri of the form 's3://bucket/key' with optional versionId query parameter." +} + \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_with_api_auth_none.json b/tests/translator/output/error_state_machine_with_api_auth_none.json new file mode 100644 index 000000000..54a0f3487 --- /dev/null +++ b/tests/translator/output/error_state_machine_with_api_auth_none.json @@ -0,0 +1,8 @@ +{ + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer on API method [post] for path [/startWithLambdaToken] because 'NONE' is only a valid value when a DefaultAuthorizer on the API is specified.", + "errors": [ + { + "errorMessage": "Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer on API method [post] for path [/startWithLambdaToken] because 'NONE' is only a valid value when a DefaultAuthorizer on the API is specified." + } + ] +} \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_with_no_api_authorizers.json b/tests/translator/output/error_state_machine_with_no_api_authorizers.json new file mode 100644 index 000000000..600097f94 --- /dev/null +++ b/tests/translator/output/error_state_machine_with_no_api_authorizers.json @@ -0,0 +1,8 @@ +{ + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer [MyUndefinedAuthorizer] on API method [post] for path [/startWithLambdaToken] because the related API does not define any Authorizers.", + "errors": [ + { + "errorMessage": "Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer [MyUndefinedAuthorizer] on API method [post] for path [/startWithLambdaToken] because the related API does not define any Authorizers." + } + ] +} \ No newline at end of file diff --git a/tests/translator/output/error_state_machine_with_undefined_api_authorizer.json b/tests/translator/output/error_state_machine_with_undefined_api_authorizer.json new file mode 100644 index 000000000..f11a5fc93 --- /dev/null +++ b/tests/translator/output/error_state_machine_with_undefined_api_authorizer.json @@ -0,0 +1,8 @@ +{ + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer [MyUndefinedAuthorizer] on API method [post] for path [/startWithLambdaToken] because it wasn't defined in the API's Authorizers.", + "errors": [ + { + "errorMessage": "Event with id [WithLambdaTokenAuth] is invalid. Unable to set Authorizer [MyUndefinedAuthorizer] on API method [post] for path [/startWithLambdaToken] because it wasn't defined in the API's Authorizers." + } + ] +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_api_auth_default_scopes.json b/tests/translator/output/state_machine_with_api_auth_default_scopes.json new file mode 100644 index 000000000..70042db2f --- /dev/null +++ b/tests/translator/output/state_machine_with_api_auth_default_scopes.json @@ -0,0 +1,725 @@ +{ + "Resources": { + "MyApiWithCognitoAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/cognitowithauthnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoWithAuthNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultauthdefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesnone": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesNoneRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizerwithdefaultscopes": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "default.delete", + "default.update" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitoauthorizercopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthWithDefaultScopes": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesoverwritten": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "overwritten.read", + "overwritten.write" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/cognitodefaultscopesdefaultauthorizer": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyDefaultCognitoAuth": [ + "default.write", + "default.read" + ] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "MyCognitoAuthWithDefaultScopes": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:2" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyDefaultCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + } + } + } + } + } + }, + "MyStateMachineCognitoWithAuthNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoWithAuthNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultAuthDefaultScopesNoneRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoDefaultScopesWithOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesWithOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithCognitoAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithCognitoAuthDeployment57b57dfc88" + }, + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "StageName": "Prod" + } + }, + "MyApiWithCognitoAuthDeployment57b57dfc88": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithCognitoAuth" + }, + "Description": "RestApi deployment id: 57b57dfc88b1b438a0437eadd869d77e938eedb6" + } + }, + "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoDefaultScopesDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachineCognitoAuthorizerWithDefaultScopesRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerWithDefaultScopesRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineCognitoAuthorizerScopesOverwrittenRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineCognitoAuthorizerScopesOverwrittenRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_api_authorizer.json b/tests/translator/output/state_machine_with_api_authorizer.json new file mode 100644 index 000000000..fba1f1847 --- /dev/null +++ b/tests/translator/output/state_machine_with_api_authorizer.json @@ -0,0 +1,368 @@ +{ + "Resources": { + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaaffc688ce" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startNoAuth": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + } + } + }, + "StateMachineWithLambdaTokenAuthRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiDeploymentc2779253ee": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: c2779253eecd9c0b8252440b0cf5ef8d2759b211", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeploymentc2779253ee" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeploymentaaffc688ce": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aaffc688ce6d1b26ccd7a90641e103263f6240bb", + "StageName": "Stage" + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startWithLambdaToken": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_api_authorizer_maximum.json b/tests/translator/output/state_machine_with_api_authorizer_maximum.json new file mode 100644 index 000000000..f4b6bc22f --- /dev/null +++ b/tests/translator/output/state_machine_with_api_authorizer_maximum.json @@ -0,0 +1,682 @@ +{ + "Resources": { + "MyApiDeploymentde088eafc3": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: de088eafc3dd099f3b79506a6e0542dadb9fcd23", + "StageName": "Stage" + } + }, + "MyApiMyLambdaRequestAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineWithLambdaRequestAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaRequestAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineWithDefaultAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithDefaultAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithNoAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/users": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithDefaultAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "patch": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaTokenAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "delete": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineWithLambdaRequestAuthorizerRole", + "Arn" + ] + }, + "type": "aws" + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "MyLambdaTokenAuthNoneFunctionInvokeRole": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 0, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuthMultipleUserPools": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, + "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + } + }, + "MyApiMyLambdaTokenAuthAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineWithLambdaTokenAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithLambdaTokenAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + { + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeploymentde088eafc3" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineWithCognitoMultipleUserPoolsAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithCognitoMultipleUserPoolsAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachineWithNoAuthorizerRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineWithNoAuthorizerRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_api_resource_policy.json b/tests/translator/output/state_machine_with_api_resource_policy.json new file mode 100644 index 000000000..262ecdf37 --- /dev/null +++ b/tests/translator/output/state_machine_with_api_resource_policy.json @@ -0,0 +1,474 @@ +{ + "Resources": { + "MyStateMachineGetHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachineGetHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/one": { + "get": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachineGetHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/three": { + "put": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePutHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/two": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${MyStateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "MyStateMachinePostHtmlRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/GET/one", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Allow", + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "NotIpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/two", + { + "__Stage__": null + } + ] + } + ], + "Effect": "Deny", + "Condition": { + "IpAddress": { + "aws:SourceIp": [ + "1.2.3.4" + ] + } + }, + "Principal": "*" + } + ] + } + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment17065a95ba" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "MyStateMachinePutHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePutHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyStateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "MyStateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExplicitApiDeployment17065a95ba": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 17065a95bac1ac0e3dc22fef2ff7aa228539b1d2", + "StageName": "Stage" + } + }, + "MyStateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "MyStateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyStateMachinePostHtmlRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "MyStateMachinePostHtmlRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "MyStateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_condition.json b/tests/translator/output/state_machine_with_condition.json new file mode 100644 index 000000000..7d67abe1a --- /dev/null +++ b/tests/translator/output/state_machine_with_condition.json @@ -0,0 +1,31 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_condition_and_events.json b/tests/translator/output/state_machine_with_condition_and_events.json new file mode 100644 index 000000000..413d4ac37 --- /dev/null +++ b/tests/translator/output/state_machine_with_condition_and_events.json @@ -0,0 +1,297 @@ +{ + "Conditions": { + "TestCondition": { + "Fn::Equals": [ + "test", + "test" + ] + } + }, + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachine", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentaeae651245" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + }, + "Condition": "TestCondition" + }, + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ], + "Name": "TestSchedule" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + }, + "Condition": "TestCondition" + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "Fn::If": [ + "TestCondition", + { + "post": { + "Fn::If": [ + "TestCondition", + { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::If": [ + "TestCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, + "swagger": "2.0" + } + }, + "Condition": "TestCondition" + }, + "ServerlessRestApiDeploymentaeae651245": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aeae651245fe7d417a17f2bea50b255f2727e2b8", + "StageName": "Stage" + }, + "Condition": "TestCondition" + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + }, + "Condition": "TestCondition" + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_cwe.json b/tests/translator/output/state_machine_with_cwe.json new file mode 100644 index 000000000..04164e943 --- /dev/null +++ b/tests/translator/output/state_machine_with_cwe.json @@ -0,0 +1,83 @@ +{ + "Resources": { + "StateMachineCWEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineCWEventRole", + "Arn" + ] + }, + "Id": "StateMachineCWEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachineCWEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineCWEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_definition_S3_object.json b/tests/translator/output/state_machine_with_definition_S3_object.json new file mode 100644 index 000000000..e01d31fd6 --- /dev/null +++ b/tests/translator/output/state_machine_with_definition_S3_object.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_definition_S3_string.json b/tests/translator/output/state_machine_with_definition_S3_string.json new file mode 100644 index 000000000..97f3b26e5 --- /dev/null +++ b/tests/translator/output/state_machine_with_definition_S3_string.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithDefinitionInS3", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_definition_substitutions.json b/tests/translator/output/state_machine_with_definition_substitutions.json new file mode 100644 index 000000000..5bae321ef --- /dev/null +++ b/tests/translator/output/state_machine_with_definition_substitutions.json @@ -0,0 +1,155 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "my_state_var_1": "Pass", + "my_state_var_2": "Task" + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"${my_state_var_1}\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"${my_state_var_2}\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_explicit_api.json b/tests/translator/output/state_machine_with_explicit_api.json new file mode 100644 index 000000000..59f36f236 --- /dev/null +++ b/tests/translator/output/state_machine_with_explicit_api.json @@ -0,0 +1,202 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_express_logging.json b/tests/translator/output/state_machine_with_express_logging.json new file mode 100644 index 000000000..ede760c3a --- /dev/null +++ b/tests/translator/output/state_machine_with_express_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ExpressLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": false, + "Level": "FATAL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "ExpressLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "EXPRESS", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_implicit_api.json b/tests/translator/output/state_machine_with_implicit_api.json new file mode 100644 index 000000000..0a76883a3 --- /dev/null +++ b/tests/translator/output/state_machine_with_implicit_api.json @@ -0,0 +1,202 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment05bc9f394c" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment05bc9f394c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 05bc9f394c3ca5d24b8d6dc69d133762afd1298e", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_implicit_api_globals.json b/tests/translator/output/state_machine_with_implicit_api_globals.json new file mode 100644 index 000000000..b8fb271d4 --- /dev/null +++ b/tests/translator/output/state_machine_with_implicit_api_globals.json @@ -0,0 +1,224 @@ +{ + "Resources": { + "StateMachineMyApiEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineMyApiEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "apigateway.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment1f01b589d4" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment1f01b589d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 1f01b589d4e226c84a3e14ca738b5d060e7b611a", + "StageName": "Stage" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/startMyExecution": { + "post": { + "x-amazon-apigateway-integration": { + "responses": { + "200": { + "statusCode": "200" + }, + "400": { + "statusCode": "400" + } + }, + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:states:action/StartExecution" + }, + "httpMethod": "POST", + "requestTemplates": { + "application/json": { + "Fn::Sub": "{\"input\": \"$util.escapeJavaScript($input.json('$'))\", \"stateMachineArn\": \"${StateMachine}\"}" + } + }, + "credentials": { + "Fn::GetAtt": [ + "StateMachineMyApiEventRole", + "Arn" + ] + }, + "type": "aws" + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": { + "Action": "execute-api:Invoke", + "Resource": [ + { + "Fn::Sub": [ + "execute-api:/${__Stage__}/POST/startMyExecution", + { + "__Stage__": "Prod" + } + ] + } + ], + "Effect": "Deny", + "Principal": { + "AWS": [ + "12345" + ] + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_inline_definition.json b/tests/translator/output/state_machine_with_inline_definition.json new file mode 100644 index 000000000..722bc9ec7 --- /dev/null +++ b/tests/translator/output/state_machine_with_inline_definition.json @@ -0,0 +1,89 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_inline_definition_intrinsics.json b/tests/translator/output/state_machine_with_inline_definition_intrinsics.json new file mode 100644 index 000000000..7c7f91219 --- /dev/null +++ b/tests/translator/output/state_machine_with_inline_definition_intrinsics.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_inline_policies.json b/tests/translator/output/state_machine_with_inline_policies.json new file mode 100644 index 000000000..7c7f91219 --- /dev/null +++ b/tests/translator/output/state_machine_with_inline_policies.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "ReservedConcurrentExecutions": 100, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyBasicStateMachine", + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "StateMachineType": "STANDARD" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_managed_policy.json b/tests/translator/output/state_machine_with_managed_policy.json new file mode 100644 index 000000000..82124708d --- /dev/null +++ b/tests/translator/output/state_machine_with_managed_policy.json @@ -0,0 +1,57 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithManagedPolicy", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_role.json b/tests/translator/output/state_machine_with_role.json new file mode 100644 index 000000000..0db8c03ab --- /dev/null +++ b/tests/translator/output/state_machine_with_role.json @@ -0,0 +1,22 @@ +{ + "Resources": { + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "StateMachineName": "MyStateMachineWithRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_sam_policy_templates.json b/tests/translator/output/state_machine_with_sam_policy_templates.json new file mode 100644 index 000000000..c14e8cd07 --- /dev/null +++ b/tests/translator/output/state_machine_with_sam_policy_templates.json @@ -0,0 +1,491 @@ +{ + "Resources": { + "ResolverLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "resolver.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "resolver.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ResolverLambdaRole", + "Arn" + ] + }, + "Runtime": "python3.8", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "NestedWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file for nested workflows\",", + " \"StartAt\": \"NestedStateOne\",", + " \"States\": {", + " \"NestedStateOne\": {", + " \"Next\": \"NestedStateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"NestedStateTwo\": {", + " \"End\": true,", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambda": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "starter.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "starter.zip" + }, + "Role": { + "Fn::GetAtt": [ + "StarterLambdaRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflow": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionSubstitutions": { + "definition_substitution_4": { + "Ref": "NestedWorkflow" + }, + "definition_substitution_5": { + "Ref": "OutputStore" + }, + "definition_substitution_2": { + "Ref": "ResolverLambda" + }, + "definition_substitution_3": { + "Ref": "ProcessingQueue" + }, + "definition_substitution_1": { + "Fn::GetAtt": [ + "StarterLambda", + "Arn" + ] + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "ProcessingWorkflowRole", + "Arn" + ] + }, + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"An example ASL file with parallel states\",", + " \"StartAt\": \"StateOne\",", + " \"States\": {", + " \"StateOne\": {", + " \"Next\": \"StateTwo\",", + " \"Result\": {", + " \"Value\": \"MyValue\"", + " },", + " \"Type\": \"Pass\"", + " },", + " \"StateTwo\": {", + " \"Branches\": [", + " {", + " \"StartAt\": \"BranchOne_StateOne\",", + " \"States\": {", + " \"BranchOne_StateFour\": {", + " \"Choices\": [", + " {", + " \"Next\": \"ValueIsZero\",", + " \"NumericEquals\": 0,", + " \"Variable\": \"$.value\"", + " },", + " {", + " \"Next\": \"ValueIsOne\",", + " \"NumericEquals\": 1,", + " \"Variable\": \"$.value\"", + " }", + " ],", + " \"Type\": \"Choice\"", + " },", + " \"BranchOne_StateOne\": {", + " \"Next\": \"BranchOne_StateTwo\",", + " \"Resource\": \"${definition_substitution_1}\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateThree\": {", + " \"Next\": \"BranchOne_StateFour\",", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_2}\"", + " },", + " \"Resource\": \"arn:aws:states:::lambda:invoke\",", + " \"Type\": \"Task\"", + " },", + " \"BranchOne_StateTwo\": {", + " \"Next\": \"BranchOne_StateThree\",", + " \"Parameters\": {", + " \"MessageBody.$\": \"$.input.message\",", + " \"QueueUrl\": \"${definition_substitution_3}\"", + " },", + " \"Resource\": \"arn:aws:states:::sqs:sendMessage.waitForTaskToken\",", + " \"Type\": \"Task\"", + " },", + " \"ValueIsOne\": {", + " \"Type\": \"Succeed\"", + " },", + " \"ValueIsZero\": {", + " \"Type\": \"Fail\"", + " }", + " }", + " },", + " {", + " \"StartAt\": \"BranchTwo_StateOne\",", + " \"States\": {", + " \"BranchTwo_StateOne\": {", + " \"Next\": \"BranchTwo_StateTwo\",", + " \"Parameters\": {", + " \"Input\": {", + " \"KeyA\": \"ValueA\",", + " \"KeyC\": \"ValueC\"", + " },", + " \"StateMachineArn\": \"${definition_substitution_4}\"", + " },", + " \"Resource\": \"arn:aws:states:::states:startExecution.sync\",", + " \"Type\": \"Task\"", + " },", + " \"BranchTwo_StateThree\": {", + " \"Type\": \"Succeed\"", + " },", + " \"BranchTwo_StateTwo\": {", + " \"Next\": \"BranchTwo_StateThree\",", + " \"Parameters\": {", + " \"Item\": {", + " \"Body\": {", + " \"S.$\": \"$.MessageDetails.Body\"", + " },", + " \"MessageId\": {", + " \"S.$\": \"$.MessageDetails.MessageId\"", + " }", + " },", + " \"TableName\": \"${definition_substitution_5}\"", + " },", + " \"Resource\": \"arn:aws:states:::dynamodb:putItem\",", + " \"Type\": \"Task\"", + " }", + " }", + " }", + " ],", + " \"End\": true,", + " \"Type\": \"Parallel\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "StarterLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ProcessingWorkflowRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "ProcessingWorkflowRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "StarterLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy1", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:SendMessage*" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:sqs:${AWS::Region}:${AWS::AccountId}:${queueName}", + { + "queueName": { + "Fn::GetAtt": [ + "ProcessingQueue", + "QueueName" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy2", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}*", + { + "functionName": { + "Ref": "ResolverLambda" + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy3", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "states:StartExecution" + ], + "Resource": { + "Fn::Sub": [ + "arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${stateMachineName}", + { + "stateMachineName": { + "Fn::GetAtt": [ + "NestedWorkflow", + "Name" + ] + } + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "ProcessingWorkflowRolePolicy4", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:BatchWriteItem" + ], + "Resource": [ + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + }, + { + "Fn::Sub": [ + "arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/*", + { + "tableName": { + "Ref": "OutputStore" + } + } + ] + } + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "OutputStore": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "KeyType": "HASH", + "AttributeName": "id" + } + ], + "TableName": "MySimpleTable", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": "PAY_PER_REQUEST" + } + }, + "ProcessingQueue": { + "Type": "AWS::SQS::Queue" + }, + "ResolverLambdaRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_schedule.json b/tests/translator/output/state_machine_with_schedule.json new file mode 100644 index 000000000..8730521be --- /dev/null +++ b/tests/translator/output/state_machine_with_schedule.json @@ -0,0 +1,80 @@ +{ + "Resources": { + "StateMachineScheduleEvent": { + "Type": "AWS::Events::Rule", + "Properties": { + "State": "DISABLED", + "ScheduleExpression": "rate(1 minute)", + "Name": "TestSchedule", + "Description": "test schedule", + "Targets": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineScheduleEventRole", + "Arn" + ] + }, + "Id": "StateMachineScheduleEventStepFunctionsTarget", + "Arn": { + "Ref": "StateMachine" + } + } + ] + } + }, + "StateMachineScheduleEventRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "Policies": [ + { + "PolicyName": "StateMachineScheduleEventRoleStartExecutionPolicy", + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Resource": { + "Ref": "StateMachine" + }, + "Effect": "Allow" + } + ] + } + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "events.amazonaws.com" + ] + } + } + ] + } + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": "arn:aws:iam::123456123456:role/service-role/SampleRole", + "DefinitionS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "my_state_machine.asl.json" + }, + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_standard_logging.json b/tests/translator/output/state_machine_with_standard_logging.json new file mode 100644 index 000000000..84a2a2e56 --- /dev/null +++ b/tests/translator/output/state_machine_with_standard_logging.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "MyFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StandardLogGroup": { + "Type": "AWS::Logs::LogGroup" + }, + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Resource": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "StateMachineRolePolicy1", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:CreateLogDelivery", + "logs:GetLogDelivery", + "logs:UpdateLogDelivery", + "logs:DeleteLogDelivery", + "logs:ListLogDeliveries", + "logs:PutResourcePolicy", + "logs:DescribeResourcePolicies", + "logs:DescribeLogGroups" + ], + "Resource": [ + "*" + ], + "Effect": "Allow" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ] + } + }, + "MyFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStandardStateMachineWithLogging", + "DefinitionSubstitutions": { + "my_lambda_arn": { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + }, + "LoggingConfiguration": { + "IncludeExecutionData": true, + "Level": "ALL", + "Destinations": [ + { + "CloudWatchLogsLogGroup": { + "LogGroupArn": { + "Fn::GetAtt": [ + "StandardLogGroup", + "Arn" + ] + } + } + } + ] + }, + "StateMachineType": "STANDARD", + "DefinitionS3Location": { + "Version": 3, + "Bucket": "sam-demo-bucket", + "Key": "my-state-machine.asl.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/state_machine_with_tags.json b/tests/translator/output/state_machine_with_tags.json new file mode 100644 index 000000000..6016da420 --- /dev/null +++ b/tests/translator/output/state_machine_with_tags.json @@ -0,0 +1,105 @@ +{ + "Resources": { + "StateMachineRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [], + "Policies": [ + { + "PolicyName": "StateMachineRolePolicy0", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "*", + "Resource": "*", + "Effect": "Deny" + } + ] + } + } + ], + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + }, + "StateMachine": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRole", + "Arn" + ] + }, + "StateMachineName": "MyStateMachineWithTags", + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"Comment\": \"A Hello World example of the Amazon States Language using Pass states\",", + " \"StartAt\": \"Hello\",", + " \"States\": {", + " \"Hello\": {", + " \"Next\": \"World\",", + " \"Result\": \"Hello\",", + " \"Type\": \"Pass\"", + " },", + " \"World\": {", + " \"End\": true,", + " \"Result\": \"World\",", + " \"Type\": \"Pass\"", + " }", + " }", + "}" + ] + ] + }, + "StateMachineType": "STANDARD", + "Tags": [ + { + "Value": "SAM", + "Key": "stateMachine:createdBy" + }, + { + "Value": "ValueTwo", + "Key": "TagTwo" + }, + { + "Value": "ValueOne", + "Key": "TagOne" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 304d50f2c..755891adc 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -274,6 +274,29 @@ class TestTranslatorEndToEnd(TestCase): "function_with_event_dest_conditional", "api_with_usageplans", "api_with_usageplans_intrinsics", + "state_machine_with_inline_definition", + "state_machine_with_tags", + "state_machine_with_inline_definition_intrinsics", + "state_machine_with_role", + "state_machine_with_inline_policies", + "state_machine_with_sam_policy_templates", + "state_machine_with_definition_S3_string", + "state_machine_with_definition_S3_object", + "state_machine_with_definition_substitutions", + "state_machine_with_standard_logging", + "state_machine_with_express_logging", + "state_machine_with_managed_policy", + "state_machine_with_condition", + "state_machine_with_schedule", + "state_machine_with_cwe", + "state_machine_with_explicit_api", + "state_machine_with_implicit_api", + "state_machine_with_implicit_api_globals", + "state_machine_with_api_authorizer", + "state_machine_with_api_authorizer_maximum", + "state_machine_with_api_resource_policy", + "state_machine_with_api_auth_default_scopes", + "state_machine_with_condition_and_events", ], [ ("aws", "ap-southeast-1"), @@ -534,6 +557,12 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw @pytest.mark.parametrize( "testcase", [ + "error_state_machine_definition_string", + "error_state_machine_invalid_s3_object", + "error_state_machine_invalid_s3_string", + "error_state_machine_with_api_auth_none", + "error_state_machine_with_no_api_authorizers", + "error_state_machine_with_undefined_api_authorizer", "error_cognito_userpool_duplicate_trigger", "error_api_duplicate_methods_same_path", "error_api_gateway_responses_nonnumeric_status_code", @@ -914,7 +943,7 @@ def test_prepare_plugins_must_handle_empty_input(self): self.assertEqual(6, len(sam_plugins)) @patch("samtranslator.translator.translator.PolicyTemplatesProcessor") - @patch("samtranslator.translator.translator.PolicyTemplatesForFunctionPlugin") + @patch("samtranslator.translator.translator.PolicyTemplatesForResourcePlugin") def test_make_policy_template_for_function_plugin_must_work( self, policy_templates_for_function_plugin_mock, policy_templates_processor_mock ): diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/tests/utils/test_dynamic_references.py b/tests/utils/test_dynamic_references.py new file mode 100644 index 000000000..303b8553f --- /dev/null +++ b/tests/utils/test_dynamic_references.py @@ -0,0 +1,28 @@ +from parameterized import parameterized +from unittest import TestCase + +from samtranslator.utils.cfn_dynamic_references import is_dynamic_reference + + +class TestDynamicReferences(TestCase): + valid_dynamic_references = [ + "{{resolve:ssm:S3AccessControl:2}}", + "{{resolve:ssm-secure:IAMUserPassword:10}}", + "{{resolve:secretsmanager:MyRDSSecret:SecretString:password}}", + "{{resolve:secretsmanager:MyRDSSecret:SecretString}}", + ] + + @parameterized.expand(valid_dynamic_references) + def test_is_dynamic_reference_must_detect_dynamic_reference(self, dynamic_reference): + self.assertTrue(is_dynamic_reference(dynamic_reference)) + + invalid_dynamic_references = [ + "{{resolve}}", + "{{resolve::}}", + "{{invalid:ssm:S3AccessControl:2}}", + "{{invalid:ssm:S3AccessControl}}", + ] + + @parameterized.expand(invalid_dynamic_references) + def test_is_intrinsic_on_invalid_input(self, invalid_dynamic_reference): + self.assertFalse(is_dynamic_reference(invalid_dynamic_reference))