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
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_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_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_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)
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_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 _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 """ policies = self.policies[:] if self.tracing and self.tracing.get("Enabled") is True: policies.append(get_xray_managed_policy_name()) state_machine_policies = ResourcePolicies( {"Policies": 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(), permissions_boundary=self.permissions_boundary, ) return execution_role
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))
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 = ResourcePolicies(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[ResourcePolicies.POLICIES_PROPERTY_NAME] = result
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
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)
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))