def test_with_templates(self): dir_path = os.path.dirname(os.path.realpath(__file__)) test_templates = glob.glob(f"{dir_path}/test_templates/*.*") for template in test_templates: with open(template) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) config = Config( project_name=template, service_name=template, stack_name=template, rules=DEFAULT_RULES.keys() ) # Scan result result = Result() rules = [DEFAULT_RULES.get(rule)(config, result) for rule in config.rules] processor = RuleProcessor(*rules) processor.process_cf_template(cf_template, config, result) # Use this to print the stack if there's an error if len(result.exceptions): print(template) traceback.print_tb(result.exceptions[0].__traceback__) no_resource_templates = ["vulgar_bad_syntax.yml", "rubbish.json"] if template.split("/")[-1] in no_resource_templates: assert len(result.exceptions) == 1 else: assert len(result.exceptions) == 0
def template(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open( f"{dir_path}/test_templates/single_security_group_one_cidr_ingress.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def template(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open( f"{dir_path}/test_templates/s3_bucket_cross_account_and_normal.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def template(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open( f"{dir_path}/test_templates/rds_instance_plain_parameter.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def get_cfmodel(template: TextIOWrapper) -> CFModel: template_file = convert_json_or_yaml_to_dict(template.read()) if not template_file: raise FileEmptyException( f"{template.name} is empty and not a valid template.") cfmodel = pycfmodel.parse(template_file) return cfmodel
def template(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open( f"{dir_path}/test_templates/iam_role_with_wildcard_action_on_trust.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def cli(templates, logging_level, resolve_parameters, **kwargs): """ Analyse AWS Cloudformation templates passed by parameter. Exit codes: - 0 = all templates valid and scanned successfully - 1 = error / issue in scanning at least one template - 2 = at least one template is not valid according to CFRipper (template scanned successfully) - 3 = unknown / unhandled exception in scanning the templates """ try: setup_logging(logging_level) if kwargs["resolve"] and resolve_parameters: resolve_parameters = convert_json_or_yaml_to_dict( resolve_parameters.read()) results_of_templates = [ process_template(template=template, resolve_parameters=resolve_parameters, **kwargs) for template in templates ] sys.exit(2 if False in results_of_templates else 0) except FileEmptyException as file_empty: sys.exit(file_empty) except Exception as e: logging.exception( "Unhandled exception raised, please create an issue with the error message at " "https://github.com/Skyscanner/cfripper/issues") try: sys.exit(e.errno) except AttributeError: sys.exit(3)
def download_template_to_dictionary(self, s3_url): """ Download a CloudFormation template from S3 into a Dictionary. :param s3_url: The URL to download from. :return: Dictionary version of the CF Template. """ bucket_name, file_path = extract_bucket_name_and_path_from_url(s3_url) client = self.session.client("s3", region_name=self.region) response = client.get_object(Bucket=bucket_name, Key=file_path) file_contents = response["Body"].read().decode("utf-8") return convert_json_or_yaml_to_dict(file_contents)
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
def test_script(script_name, service_name, project_name, stack): event = { "stack_template_url": "https://fake/bucket/key", "project": project_name, "serviceName": service_name, "stack": stack, } mock_boto3_client_object = Mock() with open(f"{dir_path}/test_cf_scripts/{script_name}") as cf_script: mock_boto3_client_object.download_template_to_dictionary.return_value = convert_json_or_yaml_to_dict( cf_script.read() ) mock_boto3_client = Mock(return_value=mock_boto3_client_object) with patch("cfripper.main.Boto3Client", new=mock_boto3_client): from cfripper.main import handler event_result = handler(event, "None") print(f"{script_name} -- valid: {event_result['valid']}\n {event_result['reason']}")
def cli(templates, logging_level, resolve_parameters, **kwargs): """Analyse AWS Cloudformation templates passed by parameter.""" try: setup_logging(logging_level) if kwargs["resolve"] and resolve_parameters: resolve_parameters = convert_json_or_yaml_to_dict( resolve_parameters.read()) for template in templates: process_template(template=template, resolve_parameters=resolve_parameters, **kwargs) except Exception as e: logging.exception( "Unhandled exception raised, please create an issue wit the error message at " "https://github.com/Skyscanner/cfripper/issues") try: sys.exit(e.errno) except AttributeError: sys.exit(1)
def get_cfmodel_from(path: str) -> CFModel: with Path(FIXTURE_ROOT_PATH / path).open() as f: content = f.read() return parse(convert_json_or_yaml_to_dict(content))
def test_valid_yaml_as_bytes(self): yaml_content = bytes("hello: this is valid", "utf8") result = convert_json_or_yaml_to_dict(yaml_content) assert result["hello"] == "this is valid"
def test_invalid_yaml_as_bytes(patched_logger): result = convert_json_or_yaml_to_dict(bytes("Abc: g\nh:f", "utf8"), "bad-stack") assert result is None patched_logger.assert_called_once_with( "Could not parse JSON template for bad-stack")
def test_valid_yaml_as_bytes(): result = convert_json_or_yaml_to_dict(bytes("hello: this is valid", "utf8")) assert result["hello"] == "this is valid"
def template(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open(f"{dir_path}/test_templates/s3_read_plus_list.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def template_good(self): dir_path = os.path.dirname(os.path.realpath(__file__)) with open(f"{dir_path}/test_templates/cfn_authentication_good.json" ) as cf_script: cf_template = convert_json_or_yaml_to_dict(cf_script.read()) return pycfmodel.parse(cf_template)
def get_cfmodel(template: TextIOWrapper) -> CFModel: template = convert_json_or_yaml_to_dict(template.read()) cfmodel = pycfmodel.parse(template) return cfmodel