def test_non_matching_filters_are_reported_normally( invalid_security_group_range): mock_config = Config( rules=["EC2SecurityGroupOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "EC2SecurityGroupOpenToWorldRule": RuleConfig(filters=[ Filter(rule_mode=RuleMode.WHITELISTED, eval={ "eq": [{ "ref": "config.stack_name" }, "anotherstack"] }) ], ) }, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template(invalid_security_group_range, mock_config) assert not result.valid assert result.failed_rules[0].rule == "EC2SecurityGroupOpenToWorldRule" assert ( result.failed_rules[0].reason == "Port(s) 0-79, 81-100 open to public IPs: (11.0.0.0/8) in security group 'SecurityGroup'" )
def test_filter_do_not_report_anything(invalid_security_group_range): mock_config = Config( rules=["EC2SecurityGroupOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_filters=[ Filter( rule_mode=RuleMode.ALLOWED, eval={ "and": [ { "eq": [{ "ref": "config.stack_name" }, "mockstack"] }, { "eq": [{ "ref": "open_ports" }, list(range(0, 101))] }, ] }, rules={"EC2SecurityGroupOpenToWorldRule"}, ) ], ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template(invalid_security_group_range, mock_config) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_non_matching_filters_are_reported_normally( single_security_group_one_cidr_ingress): mock_config = Config( rules=["EC2SecurityGroupMissingEgressRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "EC2SecurityGroupMissingEgressRule": RuleConfig(filters=[ Filter(rule_mode=RuleMode.WHITELISTED, eval={ "eq": [{ "ref": "config.stack_name" }, "anotherstack"] }) ], ) }, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template( single_security_group_one_cidr_ingress, mock_config) assert result.valid assert len(result.failed_rules) == 0 assert len(result.failed_monitored_rules) == 1 assert result.failed_monitored_rules[ 0].rule == "EC2SecurityGroupMissingEgressRule" assert ( result.failed_monitored_rules[0].reason == "Missing egress rule in sg means all traffic is allowed outbound. Make this explicit if it is desired configuration" )
def test_only_whitelisted_resources_are_removed(mock_rule_to_resource_whitelist): config = Config( stack_name="otherstack", rules=["S3CrossAccountTrustRule"], rule_to_resource_whitelist=mock_rule_to_resource_whitelist, ) result = Result() failed_rules = [ Failure( rule="S3CrossAccountTrustRule", reason="Forbidden cross-account policy allow with 123456789 for an S3 bucket.", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"rolething", "thenotwhitelistedthing", "anotherone"}, actions=None, granularity=RuleGranularity.RESOURCE, ) ] result.failed_rules = failed_rules RuleProcessor.remove_failures_of_whitelisted_resources(config=config, result=result) assert result.failed_rules == [ Failure( rule="S3CrossAccountTrustRule", reason="Forbidden cross-account policy allow with 123456789 for an S3 bucket.", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"thenotwhitelistedthing", "anotherone"}, actions=None, granularity=RuleGranularity.RESOURCE, ) ]
def test_filter_do_not_report_anything(bad_template): mock_config = Config( rules=["EC2SecurityGroupIngressOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "EC2SecurityGroupIngressOpenToWorldRule": RuleConfig(filters=[ Filter( rule_mode=RuleMode.WHITELISTED, eval={ "and": [ { "eq": [{ "ref": "config.stack_name" }, "mockstack"] }, { "eq": [{ "ref": "ingress.FromPort" }, 46] }, ] }, ) ], ) }, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template(bad_template, mock_config) assert result.valid
def test_filter_works_as_expected(template_two_roles_dict, expected_result_two_roles): config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "CrossAccountTrustRule": RuleConfig( filters=[ Filter( rule_mode=RuleMode.WHITELISTED, eval={ "and": [ {"eq": [{"ref": "config.stack_name"}, "mockstack"]}, {"eq": [{"ref": "logical_id"}, "RootRoleOne"]}, ] }, ) ], ) }, ) rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, config) assert not result.valid assert result.failed_rules[0] == expected_result_two_roles[-1]
def test_remove_failures_from_whitelisted_actions_failure_no_actions_is_removed( mock_logger, mock_rule_to_action_whitelist): config = Config( stack_name="teststack", rules=["S3CrossAccountTrustRule"], rule_to_action_whitelist=mock_rule_to_action_whitelist, ) result = Result() failure = Failure( rule="S3CrossAccountTrustRule", reason= "rolething has forbidden cross-account policy allow with 123456789 for an S3 bucket.", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions=set(), granularity=RuleGranularity.ACTION, ) result.failed_rules = [failure] RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result) assert result.failed_rules == [] mock_logger.assert_called_once_with( f"Failure with action granularity doesn't have actions: {failure}")
def test_filter_context_set_correctly(mock_failure_to_result, bad_template): mock_failure_to_result.side_effect = [None, None] mock_config = Config( rules=["EC2SecurityGroupIngressOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={}, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) processor.process_cf_template(bad_template, mock_config) assert mock_failure_to_result.mock_calls[0][2]["context"][ "ingress_ip"] == "11.0.0.0/8" assert mock_failure_to_result.mock_calls[1][2]["context"][ "ingress_ip"] == "::/0" assert mock_failure_to_result.mock_calls[0][2]["context"][ "ingress_obj"] == SecurityGroupIngressProperties( CidrIp=IPv4Network("11.0.0.0/8"), FromPort=46, IpProtocol="tcp", ToPort=46, GroupId="sg-12341234", ) assert mock_failure_to_result.mock_calls[1][2]["context"][ "ingress_obj"] == SecurityGroupIngressProperties( CidrIpv6=IPv6Network("::/0"), FromPort=46, IpProtocol="tcp", ToPort=46, GroupId="sg-12341234", )
def test_filter_do_not_report_anything(single_security_group_one_cidr_ingress): mock_config = Config( rules=["EC2SecurityGroupMissingEgressRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "EC2SecurityGroupMissingEgressRule": RuleConfig(filters=[ Filter( rule_mode=RuleMode.WHITELISTED, eval={"eq": [{ "ref": "config.stack_name" }, "mockstack"]}, ) ], ) }, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template( single_security_group_one_cidr_ingress, mock_config) assert result.valid
def test_action_whitelist_keeps_non_whitelisted_actions(): whitelist_for_all_stacks = {"MockRule": {".*": {"s3:List"}}} config = Config(stack_name="abcd", rules=["MockRule"], rule_to_action_whitelist=whitelist_for_all_stacks) result = Result() failed_rules = [ Failure( rule="MockRule", reason="MockRule is invalid for some actions", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions={"s3:ListBucket", "s3:GetBucket"}, granularity=RuleGranularity.ACTION, ) ] result.failed_rules = failed_rules RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result) assert result.failed_rules == [ Failure( rule="MockRule", reason="MockRule is invalid for some actions", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions={"s3:GetBucket"}, granularity=RuleGranularity.ACTION, ) ]
def test_with_no_rules(mock_remove_whitelisted_actions, mock_remove_whitelisted_resources, template): processor = RuleProcessor() config = Mock() processor.process_cf_template(template, config) mock_remove_whitelisted_actions.assert_called() mock_remove_whitelisted_resources.assert_called()
def test_with_mock_rule(template): rule = Mock() processor = RuleProcessor(rule) config = Mock() processor.process_cf_template(template, config) rule.invoke.assert_called()
def test_rule_processor_dont_invoke_disabled_rules(): rule = Mock() rule.rule_mode = RuleMode.DISABLED processor = RuleProcessor(rule) template = Mock() config = Mock() processor.process_cf_template(template, config) rule.invoke.assert_not_called()
def test_rule_processor_invoke_rules(): rule = Mock() rule.rule_mode = RuleMode.BLOCKING processor = RuleProcessor(rule) template = Mock() config = Mock() processor.process_cf_template(template, config) rule.invoke.assert_called()
def test_exist_function_and_property_exists( template_cross_account_role_with_name): mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "CrossAccountTrustRule": RuleConfig(filters=[ Filter( rule_mode=RuleMode.WHITELISTED, eval={ "and": [ { "and": [ { "exists": { "ref": "resource.Properties.RoleName" } }, { "regex": [ "^prefix-.*$", { "ref": "resource.Properties.RoleName" } ] }, ] }, { "eq": [{ "ref": "principal" }, "arn:aws:iam::999999999:role/[email protected]" ] }, ] }, ), ]) }, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template( template_cross_account_role_with_name, mock_config) assert result.valid
def test_whitelisted_stacks_do_not_report_anything(template_two_roles_dict): mock_stack_whitelist = {"mockstack": ["CrossAccountTrustRule"]} mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", stack_whitelist=mock_stack_whitelist, ) rules = [DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, mock_config) assert result.valid
def test_non_whitelisted_stacks_are_reported_normally(template_two_roles_dict, expected_result_two_roles): mock_stack_whitelist = {"mockstack": ["CrossAccountTrustRule"]} mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="anotherstack", stack_whitelist=mock_stack_whitelist, ) rules = [DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, mock_config) assert not result.valid assert result.failed_rules == expected_result_two_roles
def test_can_whitelist_resource_from_any_stack_if_granularity_is_resource(): whitelist_for_all_stacks = { "S3CrossAccountTrustRule": { ".*": {"ProductionAccessTest"}, "otherstack": {"rolething"} } } config = Config(stack_name="abcd", rules=["S3CrossAccountTrustRule"], rule_to_resource_whitelist=whitelist_for_all_stacks) result = Result() failed_rules = [ Failure( rule="S3CrossAccountTrustRule", reason= "ProductionAccessTest has forbidden cross-account policy allow with 123456789 for an S3 bucket.", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"ProductionAccessTest"}, actions=None, granularity=RuleGranularity.RESOURCE, ), Failure( rule="S3CrossAccountTrustRule", reason= "This one isn't whitelisted because granularity is ACTION and not RESOURCE", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"ProductionAccessTest"}, actions=None, granularity=RuleGranularity.ACTION, ), ] result.failed_rules = failed_rules RuleProcessor.remove_failures_of_whitelisted_resources(config=config, result=result) assert result.failed_rules == [ Failure( rule="S3CrossAccountTrustRule", reason= "This one isn't whitelisted because granularity is ACTION and not RESOURCE", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"ProductionAccessTest"}, actions=None, granularity=RuleGranularity.ACTION, ) ]
def test_resource_whitelisting_works_as_expected(template_two_roles_dict, expected_result_two_roles): mock_rule_to_resource_whitelist = {"CrossAccountTrustRule": {".*": {"RootRoleOne"}}} mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", rule_to_resource_whitelist=mock_rule_to_resource_whitelist, stack_name="mockstack", stack_whitelist={}, ) rules = [DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, mock_config) assert not result.valid assert result.failed_rules[0] == expected_result_two_roles[-1]
def test_non_matching_filters_are_reported_normally(bad_template): mock_config = Config( rules=["EC2SecurityGroupIngressOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_filters=[ Filter( rule_mode=RuleMode.ALLOWED, eval={"eq": [{ "ref": "config.stack_name" }, "anotherstack"]}, rules={"EC2SecurityGroupIngressOpenToWorldRule"}, ) ], ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template(bad_template, mock_config) assert not result.valid assert compare_lists_of_failures( result.failures, [ Failure( granularity=RuleGranularity.RESOURCE, reason= "Port(s) 46 open to public IPs: (11.0.0.0/8) in security group 'securityGroupIngress1'", risk_value=RuleRisk.MEDIUM, rule="EC2SecurityGroupIngressOpenToWorldRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"securityGroupIngress1"}, resource_types={"AWS::EC2::SecurityGroupIngress"}, ), Failure( granularity=RuleGranularity.RESOURCE, reason= "Port(s) 46 open to public IPs: (::/0) in security group 'securityGroupIngress2'", risk_value=RuleRisk.MEDIUM, rule="EC2SecurityGroupIngressOpenToWorldRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"securityGroupIngress2"}, resource_types={"AWS::EC2::SecurityGroupIngress"}, ), ], )
def test_remove_debug_rules(): original_failed_monitored_rules = [ Failure( rule="a", reason="something", rule_mode=RuleMode.MONITOR, granularity=RuleGranularity.STACK, risk_value=RuleRisk.HIGH, ), Failure( rule="b", reason="something", rule_mode=RuleMode.DEBUG, granularity=RuleGranularity.STACK, risk_value=RuleRisk.MEDIUM, ), Failure( rule="c", reason="something", rule_mode=RuleMode.MONITOR, granularity=RuleGranularity.STACK, risk_value=RuleRisk.LOW, ), ] list_with_no_debug_rules = [ original_failed_monitored_rules[0], original_failed_monitored_rules[2] ] processed_list = RuleProcessor.remove_debug_rules( rules=original_failed_monitored_rules) assert list_with_no_debug_rules == processed_list
def test_remove_failures_from_whitelisted_actions_only_removes_action_granularity( mock_rule_to_action_whitelist): config = Config( stack_name="teststack", rules=["S3CrossAccountTrustRule"], rule_to_action_whitelist=mock_rule_to_action_whitelist, ) result = Result() failed_rules = [ Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in BucketAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"BucketAccessPolicy"}, actions={"s3:Get*"}, granularity=RuleGranularity.ACTION, ), Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in BucketAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids=set(), actions=set(), granularity=RuleGranularity.STACK, ), ] result.failed_rules = failed_rules RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result) assert result.failed_rules == [ Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in BucketAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids=set(), actions=set(), granularity=RuleGranularity.STACK, ) ]
def test_can_whitelist_action_from_any_stack_if_granularity_is_action(): whitelist_for_all_stacks = { "S3CrossAccountTrustRule": { ".*": {"s3:ListBucket"} } } config = Config(stack_name="abcd", rules=["S3CrossAccountTrustRule"], rule_to_action_whitelist=whitelist_for_all_stacks) result = Result() failed_rules = [ Failure( rule="S3CrossAccountTrustRule", reason= "ProductionAccessTest has forbidden cross-account policy allow with 123456789 for an S3 bucket.", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions={"s3:ListBucket"}, granularity=RuleGranularity.ACTION, ), Failure( rule="S3CrossAccountTrustRule", reason= "This one isn't whitelisted because granularity is STACK and not ACTION", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions=set(), granularity=RuleGranularity.STACK, ), ] result.failed_rules = failed_rules RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result) assert result.failed_rules == [ Failure( rule="S3CrossAccountTrustRule", reason= "This one isn't whitelisted because granularity is STACK and not ACTION", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, actions=set(), granularity=RuleGranularity.STACK, ) ]
def test_externally_defined_rule_filter(filters, valid, template_security_group_firehose_ips): mock_config = Config( rules=["EC2SecurityGroupOpenToWorldRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={}, rules_filters=[] if not filters else filters, ) rules = [ DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules ] processor = RuleProcessor(*rules) result = processor.process_cf_template( template_security_group_firehose_ips, mock_config) assert result.valid == valid
def test_remove_failures_from_whitelisted_actions_uses_whitelist( mock_rule_to_action_whitelist): config = Config(stack_name="teststack", rules=["WildcardResourceRule"], rule_to_action_whitelist=mock_rule_to_action_whitelist) result = Result() result.failed_rules = [ Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in BucketAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"BucketAccessPolicy"}, actions={"s3:Get*"}, granularity=RuleGranularity.ACTION, ), Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in DynamoAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"DynamoAccessPolicy"}, actions={"dynamodb:Get"}, granularity=RuleGranularity.ACTION, ), ] RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result) assert result.failed_rules == [ Failure( rule="WildcardResourceRule", reason= "rolething is using a wildcard resource in DynamoAccessPolicy", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, resource_ids={"DynamoAccessPolicy"}, actions={"dynamodb:Get"}, granularity=RuleGranularity.ACTION, ) ]
def test_non_matching_filters_are_reported_normally(template_two_roles_dict, expected_result_two_roles): mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "CrossAccountTrustRule": RuleConfig( filters=[ Filter(rule_mode=RuleMode.WHITELISTED, eval={"eq": [{"ref": "config.stack_name"}, "anotherstack"]}) ], ) }, ) rules = [DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, mock_config) assert not result.valid assert result.failed_rules == expected_result_two_roles
def test_filter_do_not_report_anything(template_two_roles_dict): mock_config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", rules_config={ "CrossAccountTrustRule": RuleConfig( filters=[ Filter(rule_mode=RuleMode.WHITELISTED, eval={"eq": [{"ref": "config.stack_name"}, "mockstack"]}) ], ) }, ) rules = [DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, mock_config) assert result.valid
def test_load_filters_work_with_several_rules(template_two_roles_dict, test_files_location): config = Config( rules=["CrossAccountTrustRule", "PartialWildcardPrincipalRule"], aws_account_id="123456789", stack_name="mockstack", ) config.load_rules_config_file( open( f"{test_files_location}/config/rules_config_CrossAccountTrustRule.py" )) config.add_filters_from_dir(f"{test_files_location}/filters") rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, config) assert not result.valid assert compare_lists_of_failures( result.failures, [ Failure( granularity=RuleGranularity.RESOURCE, reason= "RootRoleTwo has forbidden cross-account trust relationship with arn:aws:iam::999999999:role/[email protected]", risk_value=RuleRisk.MEDIUM, rule="CrossAccountTrustRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"RootRoleTwo"}, resource_types={"AWS::IAM::Role"}, ), Failure( granularity=RuleGranularity.RESOURCE, reason= "RootRoleTwo should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at 'arn:aws:iam::123456789:root'", risk_value=RuleRisk.MEDIUM, rule="PartialWildcardPrincipalRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"RootRoleTwo"}, resource_types={"AWS::IAM::Role"}, ), ], )
def test_filter_works_as_expected_with_rules_config_file( template_two_roles_dict, expected_result_two_roles, test_files_location): config = Config( rules=["CrossAccountTrustRule"], aws_account_id="123456789", stack_name="mockstack", ) config.load_rules_config_file( open( f"{test_files_location}/config/rules_config_CrossAccountTrustRule.py" )) config.add_filters_from_dir(f"{test_files_location}/filters") rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(template_two_roles_dict, config) assert not result.valid assert compare_lists_of_failures(result.failures, expected_result_two_roles[-1:])
def test_with_templates(cf_path): with open(cf_path) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) config = Config(project_name=cf_path, service_name=cf_path, stack_name=cf_path, rules=DEFAULT_RULES.keys()) # Scan result cfmodel = pycfmodel.parse(cf_template).resolve() rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules] processor = RuleProcessor(*rules) result = processor.process_cf_template(cfmodel, config) # Use this to print the stack if there'IAMManagedPolicyWildcardActionRule an error if len(result.exceptions): print(cf_path) traceback.print_tb(result.exceptions[0].__traceback__) assert len(result.exceptions) == 0