def _construct_role(self, managed_policy_map):
        """Constructs a Lambda execution role based on this SAM function's Policies property.

        :returns: the generated IAM Role
        :rtype: model.iam.IAMRole
        """
        execution_role = IAMRole(self.logical_id + 'Role')
        execution_role.AssumeRolePolicyDocument = IAMRolePolicies.lambda_assume_role_policy()

        managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn('service-role/AWSLambdaBasicExecutionRole')]
        if self.Tracing:
            managed_policy_arns.append(ArnGenerator.generate_aws_managed_policy_arn('AWSXrayWriteOnlyAccess'))

        function_policies = FunctionPolicies({"Policies": self.Policies},
                                             # No support for policy templates in the "core"
                                             policy_template_processor=None)
        policy_documents = []

        if self.DeadLetterQueue:
            policy_documents.append(IAMRolePolicies.dead_letter_queue_policy(
                self.dead_letter_queue_policy_actions[self.DeadLetterQueue['Type']],
                self.DeadLetterQueue['TargetArn']))

        for index, policy_entry in enumerate(function_policies.get()):

            if policy_entry.type is PolicyTypes.POLICY_STATEMENT:

                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

        return execution_role
    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 = FunctionPolicies({}, 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))
Exemplo n.º 3
0
    def setUp(self):
        self.policy_template_processor_mock = Mock()
        self.is_policy_template_mock = Mock()

        self.function_policies = FunctionPolicies(
            {}, self.policy_template_processor_mock)
        self.function_policies._is_policy_template = self.is_policy_template_mock
    def test_is_policy_template_must_return_false_without_the_processor(self):
        policy = {"template_name": {"param1": "foo"}}

        function_policies_obj = FunctionPolicies({}, None)  # No policy template processor

        self.assertFalse(function_policies_obj._is_policy_template(policy))
        self.policy_template_processor_mock.has.assert_not_called()
    def _construct_role(self, managed_policy_map):
        """Constructs a Lambda execution role based on this SAM function's Policies property.

        :returns: the generated IAM Role
        :rtype: model.iam.IAMRole
        """
        execution_role = IAMRole(self.logical_id + 'Role')
        execution_role.AssumeRolePolicyDocument = IAMRolePolicies.lambda_assume_role_policy()

        managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn('service-role/AWSLambdaBasicExecutionRole')]
        if self.Tracing:
            managed_policy_arns.append(ArnGenerator.generate_aws_managed_policy_arn('AWSXrayWriteOnlyAccess'))

        function_policies = FunctionPolicies({"Policies": self.Policies},
                                             # No support for policy templates in the "core"
                                             policy_template_processor=None)
        policy_documents = []

        if self.DeadLetterQueue:
            policy_documents.append(IAMRolePolicies.dead_letter_queue_policy(
                self.dead_letter_queue_policy_actions[self.DeadLetterQueue['Type']],
                self.DeadLetterQueue['TargetArn']))

        for index, policy_entry in enumerate(function_policies.get()):

            if policy_entry.type is PolicyTypes.POLICY_STATEMENT:

                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

        return execution_role
    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 = FunctionPolicies({}, self.policy_template_processor_mock)
        self.assertFalse(function_policies._is_policy_template(policy))
    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 = FunctionPolicies({}, 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_non_dict_policies(self):
        policy = [1,2,3]

        self.policy_template_processor_mock.has.return_value = True
        function_policies = FunctionPolicies({}, 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_return_false_without_the_processor(self):
        policy = {
            "template_name": {"param1": "foo"}
        }

        function_policies_obj = FunctionPolicies({}, 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_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 = FunctionPolicies({}, 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_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 = FunctionPolicies({}, 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_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 = FunctionPolicies(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_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 = FunctionPolicies({}, self.policy_template_processor_mock)
        self.assertFalse(function_policies._is_policy_template(policy))
    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 = FunctionPolicies(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)
Exemplo n.º 15
0
    def on_before_transform_resource(self, logical_id, resource_type,
                                     resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties,
                                             self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            # We are processing policy templates. We know they have a particular structure:
            # {"templateName": { parameter_values_dict }}
            template_data = policy_entry.data
            template_name = list(template_data.keys())[0]
            template_parameters = list(template_data.values())[0]

            try:

                # 'convert' will return a list of policy statements
                result.append(
                    self._policy_template_processor.convert(
                        template_name, template_parameters))

            except InsufficientParameterValues as ex:
                # Exception's message will give lot of specific details
                raise InvalidResourceException(logical_id, str(ex))
            except InvalidParameterValues:
                raise InvalidResourceException(
                    logical_id,
                    "Must specify valid parameter values for policy template '{}'"
                    .format(template_name))

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result
    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 = FunctionPolicies({}, 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_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 = FunctionPolicies({}, 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 on_before_transform_resource(self, logical_id, resource_type, resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties, self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            # We are processing policy templates. We know they have a particular structure:
            # {"templateName": { parameter_values_dict }}
            template_data = policy_entry.data
            template_name = list(template_data.keys())[0]
            template_parameters = list(template_data.values())[0]

            try:

                # 'convert' will return a list of policy statements
                result.append(self._policy_template_processor.convert(template_name, template_parameters))

            except InsufficientParameterValues as ex:
                # Exception's message will give lot of specific details
                raise InvalidResourceException(logical_id, str(ex))
            except InvalidParameterValues:
                raise InvalidResourceException(logical_id,
                                               "Must specify valid parameter values for policy template '{}'"
                                               .format(template_name))

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result
    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 = FunctionPolicies(resource_properties, self.policy_template_processor_mock)

        get_policies_mock.assert_called_once_with(resource_properties)
        self.assertEqual(expected_length, len(function_policies))
    def on_before_transform_resource(self, logical_id, resource_type,
                                     resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties,
                                             self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            if is_intrinsic_if(policy_entry.data):
                # If policy is an intrinsic if, we need to process each sub-statement separately
                processed_intrinsic_if = self._process_intrinsic_if_policy_template(
                    logical_id, policy_entry)
                result.append(processed_intrinsic_if)
                continue

            converted_policy = self._process_policy_template(
                logical_id, policy_entry.data)
            result.append(converted_policy)

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result
Exemplo n.º 21
0
class TestFunctionPolicies(TestCase):
    def setUp(self):
        self.policy_template_processor_mock = Mock()
        self.is_policy_template_mock = Mock()

        self.function_policies = FunctionPolicies(
            {}, self.policy_template_processor_mock)
        self.function_policies._is_policy_template = self.is_policy_template_mock

    @patch.object(FunctionPolicies, "_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 = FunctionPolicies(
            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(FunctionPolicies, "_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 = FunctionPolicies(
            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(FunctionPolicies, "_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 = FunctionPolicies(
            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.function_policies.is_instrinsic")
    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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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 = FunctionPolicies(
            {}, 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)
Exemplo n.º 22
0
    def test_is_policy_template_must_ignore_none_policies(self):
        policy = None

        function_policies = FunctionPolicies(
            {}, self.policy_template_processor_mock)
        self.assertFalse(function_policies._is_policy_template(policy))
    def test_is_policy_template_must_ignore_none_policies(self):
        policy = None

        function_policies = FunctionPolicies({}, self.policy_template_processor_mock)
        self.assertFalse(function_policies._is_policy_template(policy))
    def setUp(self):
        self.policy_template_processor_mock = Mock()
        self.is_policy_template_mock = Mock()

        self.function_policies = FunctionPolicies({}, self.policy_template_processor_mock)
        self.function_policies._is_policy_template = self.is_policy_template_mock
class TestFunctionPolicies(TestCase):

    def setUp(self):
        self.policy_template_processor_mock = Mock()
        self.is_policy_template_mock = Mock()

        self.function_policies = FunctionPolicies({}, self.policy_template_processor_mock)
        self.function_policies._is_policy_template = self.is_policy_template_mock


    @patch.object(FunctionPolicies, "_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 = FunctionPolicies(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(FunctionPolicies, "_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 = FunctionPolicies(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(FunctionPolicies, "_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 = FunctionPolicies(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.function_policies.is_instrinsic")
    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 = FunctionPolicies({}, 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 = FunctionPolicies({}, 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 = FunctionPolicies({}, 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 = FunctionPolicies({}, 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 = FunctionPolicies({}, 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 = FunctionPolicies({}, None) # No policy template processor

        self.assertFalse(function_policies_obj._is_policy_template(policy))
        self.policy_template_processor_mock.has.assert_not_called()