예제 #1
0
    def write_config_file(self,
                          parsed_namespace,
                          output_file_paths,
                          exit_after=False):
        """
        Write the given settings to output files. Overrides write_config_file from the class ArgumentParser for
        correcting types of some attributes (example: check, skip_check)

        :param parsed_namespace: namespace object created within parse_known_args()
        :param output_file_paths: any number of file paths to write the config to
        :param exit_after: whether to exit the program after writing the config files
        """
        for output_file_path in output_file_paths:
            # validate the output file path
            try:
                with self._config_file_open_func(output_file_path,
                                                 "w") as output_file:
                    pass
            except IOError as e:
                raise ValueError("Couldn't open {} for writing: {}".format(
                    output_file_path, e))
        if output_file_paths:
            # generate the config file contents
            config_items = self.get_items_for_config_file_output(
                self._source_to_settings, parsed_namespace)
            # convert check, skip_check, soft_fail_on and hard_fail_on to list
            if 'check' in config_items.keys():
                config_items['check'] = config_items['check'][0].split(",")
            if 'skip-check' in config_items.keys():
                config_items['skip-check'] = config_items['skip-check'][
                    0].split(",")
            if 'soft-fail-on' in config_items.keys():
                config_items['soft-fail-on'] = config_items['soft-fail-on'][
                    0].split(",")
            if 'hard-fail-on' in config_items.keys():
                config_items['hard-fail-on'] = config_items['hard-fail-on'][
                    0].split(",")
            # convert strings to booleans
            for k in config_items.keys():
                config_items[k] = convert_str_to_bool(config_items[k])

            file_contents = self._config_file_parser.serialize(config_items)
            for output_file_path in output_file_paths:
                with self._config_file_open_func(output_file_path,
                                                 "w") as output_file:
                    output_file.write(file_contents)
            message = "Wrote config file to " + ", ".join(output_file_paths)
            if exit_after:
                self.exit(0, message)
            else:
                print(message)
예제 #2
0
def tostring(original, **_):
    # Indicates a safe string, all good
    if original.startswith('"') and original.endswith('"'):
        return original[1:-1]
    # Otherwise, need to check for valid types (number or bool)
    bool_value = convert_str_to_bool(original)
    if isinstance(bool_value, bool):
        return bool_value
    else:
        try:
            if "." in original:
                return str(float(original))
            else:
                return str(int(original))
        except ValueError:
            return FUNCTION_FAILED  # no change
예제 #3
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    default_config_paths = get_default_config_paths(sys.argv[1:])
    parser = ExtArgumentParser(
        description='Infrastructure as code static analysis',
        default_config_files=default_config_paths,
        config_file_parser_class=configargparse.YAMLConfigFileParser,
        add_env_var_help=True)
    add_parser_args(parser)
    config = parser.parse_args(argv)
    # bridgecrew uses both the urllib3 and requests libraries, while checkov uses the requests library.
    # Allow the user to specify a CA bundle to be used by both libraries.
    bc_integration.setup_http_manager(config.ca_certificate)

    # if a repo is passed in it'll save it.  Otherwise a default will be created based on the file or dir
    config.repo_id = bc_integration.persist_repo_id(config)
    # if a bc_api_key is passed it'll save it.  Otherwise it will check ~/.bridgecrew/credentials
    config.bc_api_key = bc_integration.persist_bc_api_key(config)

    excluded_paths = config.skip_path or []

    runner_filter = RunnerFilter(
        framework=config.framework,
        skip_framework=config.skip_framework,
        checks=config.check,
        skip_checks=config.skip_check,
        download_external_modules=convert_str_to_bool(
            config.download_external_modules),
        external_modules_download_path=config.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(config.evaluate_variables),
        runners=checkov_runners,
        excluded_paths=excluded_paths,
        all_external=config.run_all_external_checks)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter,
                                         *DEFAULT_RUNNERS)

    runnerDependencyHandler = RunnerDependencyHandler(runner_registry)
    runnerDependencyHandler.validate_runner_deps()

    if config.show_config:
        print(parser.format_values())
        return

    if config.bc_api_key == '':
        parser.error(
            'The --bc-api-key flag was specified but the value was blank. If this value was passed as a secret, '
            'you may need to double check the mapping.')
    elif config.bc_api_key:
        logger.debug(f'Using API key ending with {config.bc_api_key[-8:]}')

        if config.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        if len(config.repo_id.split('/')) != 2:
            parser.error(
                "--repo-id argument format should be 'organization/repository_name' E.g "
                "bridgecrewio/checkov")

        source = os.getenv('BC_SOURCE', 'cli')
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source}, version = {source_version}')
        try:
            bc_integration.setup_bridgecrew_credentials(
                bc_api_key=config.bc_api_key,
                repo_id=config.repo_id,
                skip_fixes=config.skip_fixes,
                skip_suppressions=config.skip_suppressions,
                skip_policy_download=config.skip_policy_download,
                source=source,
                source_version=source_version,
                repo_branch=config.branch)
            platform_excluded_paths = bc_integration.get_excluded_paths() or []
            runner_filter.excluded_paths = runner_filter.excluded_paths + platform_excluded_paths
        except Exception as e:
            logger.error(
                'An error occurred setting up the Bridgecrew platform integration. Please check your API token'
                ' and try again.',
                exc_info=True)
            return
    else:
        logger.debug('No API key found. Scanning locally only.')

    guidelines = {}
    if not config.no_guide:
        guidelines = bc_integration.get_guidelines()

    if config.check and config.skip_check:
        if any(item in runner_filter.checks
               for item in runner_filter.skip_checks):
            parser.error(
                "The check ids specified for '--check' and '--skip-check' must be mutually exclusive."
            )
            return

    integration_feature_registry.run_pre_scan()

    if config.list:
        print_checks(framework=config.framework)
        return

    baseline = None
    if config.baseline:
        baseline = Baseline()
        baseline.from_json(config.baseline)

    external_checks_dir = get_external_checks_dir(config)
    url = None
    created_baseline_path = None

    if config.directory:
        exit_codes = []
        for root_folder in config.directory:
            file = config.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines)
            if baseline:
                baseline.compare_and_reduce_reports(scan_reports)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(
                    root_folder, excluded_paths=runner_filter.excluded_paths)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(config.branch)

            if config.create_baseline:
                overall_baseline = Baseline()
                for report in scan_reports:
                    overall_baseline.add_findings_from_report(report)
                created_baseline_path = os.path.join(
                    os.path.abspath(root_folder), '.checkov.baseline')
                with open(created_baseline_path, 'w') as f:
                    json.dump(overall_baseline.to_dict(), f, indent=4)
            exit_codes.append(
                runner_registry.print_reports(
                    scan_reports,
                    config,
                    url=url,
                    created_baseline_path=created_baseline_path,
                    baseline=baseline))
        exit_code = 1 if 1 in exit_codes else 0
        return exit_code
    elif config.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=config.file,
            guidelines=guidelines,
            repo_root_for_plan_enrichment=config.repo_root_for_plan_enrichment)
        if baseline:
            baseline.compare_and_reduce_reports(scan_reports)
        if config.create_baseline:
            overall_baseline = Baseline()
            for report in scan_reports:
                overall_baseline.add_findings_from_report(report)
            created_baseline_path = os.path.join(
                os.path.abspath(os.path.commonprefix(config.file)),
                '.checkov.baseline')
            with open(created_baseline_path, 'w') as f:
                json.dump(overall_baseline.to_dict(), f, indent=4)

        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in config.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(
                root_folder,
                files,
                excluded_paths=runner_filter.excluded_paths)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(config.branch)
        return runner_registry.print_reports(
            scan_reports,
            config,
            url=url,
            created_baseline_path=created_baseline_path,
            baseline=baseline)
    elif config.docker_image:
        if config.bc_api_key is None:
            parser.error(
                "--bc-api-key argument is required when using --docker-image")
            return
        if config.dockerfile_path is None:
            parser.error(
                "--dockerfile-path argument is required when using --docker-image"
            )
            return
        if config.branch is None:
            parser.error(
                "--branch argument is required when using --docker-image")
            return
        bc_integration.commit_repository(config.branch)
        image_scanner.scan(config.docker_image, config.dockerfile_path)
    else:
        print(f"{banner}")

        bc_integration.onboarding()
예제 #4
0
파일: main.py 프로젝트: sirlatrom/checkov
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)
    runner_filter = RunnerFilter(
        framework=args.framework,
        checks=args.check,
        skip_checks=args.skip_check,
        download_external_modules=convert_str_to_bool(
            args.download_external_modules),
        external_modules_download_path=args.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(args.evaluate_variables))
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(),
                                         cfn_runner(), k8_runner(),
                                         sls_runner(), arm_runner(),
                                         tf_plan_runner())
    if args.version:
        print(version)
        return
    if args.bc_api_key:
        if args.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error(
                "--repo-id argument format should be 'organization/repository_name' E.g "
                "bridgecrewio/checkov")
        bc_integration.setup_bridgecrew_credentials(bc_api_key=args.bc_api_key,
                                                    repo_id=args.repo_id)

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error(
            "--check and --skip-check can not be applied together. please use only one of them"
        )
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    if args.directory:
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                bc_integration.commit_repository(args.branch)
            runner_registry.print_reports(scan_reports, args)
        return
    elif args.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=args.file,
            guidelines=guidelines)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            bc_integration.commit_repository(args.branch)
        runner_registry.print_reports(scan_reports, args)
    else:
        print(f"{banner}")

        bc_integration.onboarding()
예제 #5
0
def _handle_single_var_pattern(orig_variable: str,
                               var_value_and_file_map: Dict[str, Tuple[Any,
                                                                       str]],
                               locals_values: Dict[str, Any],
                               resource_list: Optional[List[Dict[str, Any]]],
                               module_list: Optional[List[Dict[str, Any]]],
                               module_data_retrieval: Callable[[str],
                                                               Dict[str, Any]],
                               eval_map_by_var_name: Dict[str,
                                                          EvaluationContext],
                               context, orig_variable_full,
                               root_directory: str) -> Any:
    ternary_info = _is_ternary(orig_variable)
    if ternary_info:
        return _process_ternary(orig_variable, ternary_info[0],
                                ternary_info[1])

    if orig_variable.startswith("module."):
        if not module_list:
            return orig_variable

        # Reference to module outputs, example: 'module.bucket.bucket_name'
        ref_tokens = orig_variable.split(".")
        if len(ref_tokens) != 3:
            return orig_variable  # fail safe, can the length ever be something other than 3?

        try:
            ref_list = jmespath.search(
                f"[].{ref_tokens[1]}.{RESOLVED_MODULE_ENTRY_NAME}[]",
                module_list)
            #                                ^^^^^^^^^^^^^ module name

            if not ref_list or not isinstance(ref_list, list):
                return orig_variable

            for ref in ref_list:
                module_data = module_data_retrieval(ref)
                if not module_data:
                    continue

                result = _handle_indexing(
                    ref_tokens[2], lambda r: jmespath.search(
                        f"output[].{ref_tokens[2]}.value[] | [0]", module_data)
                )
                if result:
                    logging.debug("Resolved module ref:  %s --> %s",
                                  orig_variable, result)
                    return result
        except ValueError:
            pass
        return orig_variable

    elif orig_variable == "True":
        return True
    elif orig_variable == "False":
        return False

    elif orig_variable.startswith("var."):
        var_name = orig_variable[4:]
        var_value_and_file = _handle_indexing(
            var_name,
            lambda r: var_value_and_file_map.get(r),
            value_is_a_tuple=True)
        if var_value_and_file is not None:
            var_value, var_file = var_value_and_file
            eval_context = eval_map_by_var_name.get(var_name)
            if eval_context is None:
                eval_map_by_var_name[var_name] = EvaluationContext(
                    os.path.relpath(var_file, root_directory), var_value,
                    [VarReference(var_name, orig_variable_full, context)])
            else:
                eval_context.definitions.append(
                    VarReference(var_name, orig_variable_full, context))
            return var_value
    elif orig_variable.startswith("local."):
        var_value = _handle_indexing(orig_variable[6:],
                                     lambda r: locals_values.get(r))
        if var_value is not None:
            return var_value
    elif orig_variable.startswith("to") and orig_variable.endswith(")"):
        # https://www.terraform.io/docs/configuration/functions/tobool.html
        if orig_variable.startswith("tobool("):
            bool_variable = orig_variable[7:-1].lower()
            bool_value = convert_str_to_bool(bool_variable)
            if isinstance(bool_value, bool):
                return bool_value
            else:
                return orig_variable
        # https://www.terraform.io/docs/configuration/functions/tolist.html
        elif orig_variable.startswith("tolist("):
            altered_value = _eval_string(orig_variable[7:-1])
            if altered_value is None:
                return orig_variable
            return altered_value if isinstance(altered_value,
                                               list) else list(altered_value)
        # NOTE: tomap as handled outside this loop (see below)
        # https://www.terraform.io/docs/configuration/functions/tonumber.html
        elif orig_variable.startswith("tonumber("):
            num_variable = orig_variable[9:-1]
            if num_variable.startswith('"') and num_variable.endswith('"'):
                num_variable = num_variable[1:-1]
            try:
                if "." in num_variable:
                    return float(num_variable)
                else:
                    return int(num_variable)
            except ValueError:
                return orig_variable
        # https://www.terraform.io/docs/configuration/functions/toset.html
        elif orig_variable.startswith("toset("):
            altered_value = _eval_string(orig_variable[6:-1])
            if altered_value is None:
                return orig_variable
            return set(altered_value)
        # https://www.terraform.io/docs/configuration/functions/tostring.html
        elif orig_variable.startswith("tostring("):
            altered_value = orig_variable[9:-1]
            # Indicates a safe string, all good
            if altered_value.startswith('"') and altered_value.endswith('"'):
                return altered_value[1:-1]
            # Otherwise, need to check for valid types (number or bool)
            bool_value = convert_str_to_bool(altered_value)
            if isinstance(bool_value, bool):
                return bool_value
            else:
                try:
                    if "." in altered_value:
                        return str(float(altered_value))
                    else:
                        return str(int(altered_value))
                except ValueError:
                    return orig_variable  # no change
    elif orig_variable.startswith("merge(") and orig_variable.endswith(")"):
        altered_value = orig_variable[6:-1]
        args = split_merge_args(altered_value)
        if args is None:
            return orig_variable
        merged_map = {}
        for arg in args:
            if arg.startswith("{"):
                value = _map_string_to_native(arg)
                if value is None:
                    return orig_variable
            else:
                value = _handle_single_var_pattern(
                    arg, var_value_and_file_map, locals_values, resource_list,
                    module_list, module_data_retrieval, eval_map_by_var_name,
                    context, arg, root_directory)
            if isinstance(value, dict):
                merged_map.update(value)
            else:
                return orig_variable  # don't know what this is, blow out
        return merged_map
    # TODO - format() support, still in progress
    # elif orig_variable.startswith("format(") and orig_variable.endswith(")"):
    #     format_tokens = orig_variable[7:-1].split(",")
    #     return format_tokens[0].format([_to_native_value(t) for t in format_tokens[1:]])

    elif _RESOURCE_REF_PATTERN.match(orig_variable):
        # Reference to resources, example: 'aws_s3_bucket.example.bucket'
        # TODO: handle index into map/list
        try:
            result = jmespath.search(f"[].{orig_variable}[] | [0]",
                                     resource_list)
        except ValueError:
            pass
        else:
            if result is not None:
                return result

    return orig_variable  # fall back to no change
예제 #6
0
def tobool(original, **_):
    # https://www.terraform.io/docs/configuration/functions/tobool.html
    bool_value = convert_str_to_bool(original)
    return bool_value if isinstance(bool_value, bool) else FUNCTION_FAILED
예제 #7
0
파일: main.py 프로젝트: vpnj012k/checkov
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)
    # Disable runners with missing system dependencies
    args.skip_framework = runnerDependencyHandler.disable_incompatible_runners(
        args.skip_framework)

    runner_filter = RunnerFilter(
        framework=args.framework,
        skip_framework=args.skip_framework,
        checks=args.check,
        skip_checks=args.skip_check,
        download_external_modules=convert_str_to_bool(
            args.download_external_modules),
        external_modules_download_path=args.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(args.evaluate_variables),
        runners=checkov_runners)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(),
                                         cfn_runner(), k8_runner(),
                                         sls_runner(), arm_runner(),
                                         tf_plan_runner(), helm_runner())
    if args.version:
        print(version)
        return
    if args.bc_api_key:
        if args.repo_id is None:
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error(
                "--repo-id argument format should be 'organization/repository_name' E.g "
                "bridgecrewio/checkov")

        source = os.getenv('BC_SOURCE', 'cli')
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source}, version = {source_version}')
        try:
            bc_integration.setup_bridgecrew_credentials(
                bc_api_key=args.bc_api_key,
                repo_id=args.repo_id,
                skip_fixes=args.skip_fixes,
                skip_suppressions=args.skip_suppressions,
                source=source,
                source_version=source_version)
        except Exception as e:
            logger.error(
                'An error occurred setting up the Bridgecrew platform integration. Please check your API token and try again.',
                exc_info=True)
            return

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error(
            "--check and --skip-check can not be applied together. please use only one of them"
        )
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    url = None

    if args.directory:
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines,
                bc_integration=bc_integration)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(args.branch)

            runner_registry.print_reports(scan_reports, args, url)
        return
    elif args.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=args.file,
            guidelines=guidelines,
            bc_integration=bc_integration)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(args.branch)
        runner_registry.print_reports(scan_reports, args, url)
    else:
        print(f"{banner}")

        bc_integration.onboarding()
예제 #8
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    default_config_paths = get_default_config_paths(sys.argv[1:])
    parser = ExtArgumentParser(
        description='Infrastructure as code static analysis',
        default_config_files=default_config_paths,
        config_file_parser_class=configargparse.YAMLConfigFileParser,
        add_env_var_help=True)
    add_parser_args(parser)
    argcomplete.autocomplete(parser)
    config = parser.parse_args(argv)

    if config.add_check:
        resp = prompt.Prompt()
        check = prompt.Check(resp.responses)
        check.action()
        return

    # Check if --output value is None. If so, replace with ['cli'] for default cli output.
    if config.output is None:
        config.output = ['cli']

    logger.debug(f'Checkov version: {version}')
    logger.debug(f'Python executable: {sys.executable}')
    logger.debug(f'Python version: {sys.version}')
    logger.debug(f'Checkov executable (argv[0]): {sys.argv[0]}')
    logger.debug(parser.format_values(sanitize=True))

    # bridgecrew uses both the urllib3 and requests libraries, while checkov uses the requests library.
    # Allow the user to specify a CA bundle to be used by both libraries.
    bc_integration.setup_http_manager(config.ca_certificate)

    # if a repo is passed in it'll save it.  Otherwise a default will be created based on the file or dir
    config.repo_id = bc_integration.persist_repo_id(config)
    # if a bc_api_key is passed it'll save it.  Otherwise it will check ~/.bridgecrew/credentials
    config.bc_api_key = bc_integration.persist_bc_api_key(config)

    excluded_paths = config.skip_path or []

    if config.var_file:
        config.var_file = [os.path.abspath(f) for f in config.var_file]

    runner_filter = RunnerFilter(
        framework=config.framework,
        skip_framework=config.skip_framework,
        checks=config.check,
        skip_checks=config.skip_check,
        download_external_modules=convert_str_to_bool(
            config.download_external_modules),
        external_modules_download_path=config.external_modules_download_path,
        evaluate_variables=convert_str_to_bool(config.evaluate_variables),
        runners=checkov_runners,
        excluded_paths=excluded_paths,
        all_external=config.run_all_external_checks,
        var_files=config.var_file)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter,
                                         *DEFAULT_RUNNERS)

    runnerDependencyHandler = RunnerDependencyHandler(runner_registry)
    runnerDependencyHandler.validate_runner_deps()

    if config.show_config:
        print(parser.format_values())
        return

    if config.bc_api_key == '':
        parser.error(
            'The --bc-api-key flag was specified but the value was blank. If this value was passed as a '
            'secret, you may need to double check the mapping.')
    elif config.bc_api_key:
        logger.debug(f'Using API key ending with {config.bc_api_key[-8:]}')

        if config.repo_id is None and not config.list:
            # if you are only listing policies, then the API key will be used to fetch policies, but that's it,
            # so the repo is not required
            parser.error(
                "--repo-id argument is required when using --bc-api-key")
        elif config.repo_id:
            repo_id_sections = config.repo_id.split('/')
            if len(repo_id_sections) < 2 or any(
                    len(section) == 0 for section in repo_id_sections):
                parser.error(
                    "--repo-id argument format should be 'organization/repository_name' E.g "
                    "bridgecrewio/checkov")

        source_env_val = os.getenv('BC_SOURCE', 'cli')
        source = get_source_type(source_env_val)
        if source == SourceTypes[BCSourceType.DISABLED]:
            logger.warning(
                f'Received unexpected value for BC_SOURCE: {source_env_val}; Should be one of {{{",".join(SourceTypes.keys())}}} setting source to DISABLED'
            )
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source.name}, version = {source_version}')

        if config.list:
            # This speeds up execution by not setting up upload credentials (since we won't upload anything anyways)
            logger.debug('Using --list; setting source to DISABLED')
            source = SourceTypes[BCSourceType.DISABLED]

        try:
            bc_integration.bc_api_key = config.bc_api_key
            bc_integration.setup_bridgecrew_credentials(
                repo_id=config.repo_id,
                skip_fixes=config.skip_fixes,
                skip_suppressions=config.skip_suppressions,
                skip_policy_download=config.skip_policy_download,
                source=source,
                source_version=source_version,
                repo_branch=config.branch)
            platform_excluded_paths = bc_integration.get_excluded_paths() or []
            runner_filter.excluded_paths = runner_filter.excluded_paths + platform_excluded_paths
        except Exception:
            if bc_integration.prisma_url:
                message = 'An error occurred setting up the Bridgecrew platform integration. Please check your API ' \
                          'token and PRISMA_API_URL environment variable and try again. The PRISMA_API_URL value ' \
                          'should be similar to: `https://api0.prismacloud.io`'
            else:
                message = 'An error occurred setting up the Bridgecrew platform integration. Please check your API ' \
                          'token and try again.'
            if logger.isEnabledFor(logging.DEBUG):
                logger.debug(message, exc_info=True)
            else:
                logger.error(message)
            return
    else:
        logger.debug('No API key found. Scanning locally only.')

    if config.check and config.skip_check:
        if any(item in runner_filter.checks
               for item in runner_filter.skip_checks):
            parser.error(
                "The check ids specified for '--check' and '--skip-check' must be mutually exclusive."
            )
            return

    integration_feature_registry.run_pre_scan()

    guidelines = {}
    BC_SKIP_MAPPING = os.getenv("BC_SKIP_MAPPING", "FALSE")
    if config.no_guide or BC_SKIP_MAPPING.upper() == "TRUE":
        bc_integration.bc_skip_mapping = True
    else:
        guidelines = bc_integration.get_guidelines()

        ckv_to_bc_mapping = bc_integration.get_ckv_to_bc_id_mapping()
        if ckv_to_bc_mapping:
            all_checks = BaseCheckRegistry.get_all_registered_checks()
            for check in all_checks:
                check.bc_id = ckv_to_bc_mapping.get(check.id)

    if config.list:
        print_checks(frameworks=config.framework,
                     use_bc_ids=config.output_bc_ids)
        return

    baseline = None
    if config.baseline:
        baseline = Baseline()
        baseline.from_json(config.baseline)

    external_checks_dir = get_external_checks_dir(config)
    url = None
    created_baseline_path = None

    if config.directory:
        exit_codes = []
        for root_folder in config.directory:
            file = config.file
            scan_reports = runner_registry.run(
                root_folder=root_folder,
                external_checks_dir=external_checks_dir,
                files=file,
                guidelines=guidelines)
            if baseline:
                baseline.compare_and_reduce_reports(scan_reports)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(
                    root_folder, excluded_paths=runner_filter.excluded_paths)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(config.branch)

            if config.create_baseline:
                overall_baseline = Baseline()
                for report in scan_reports:
                    overall_baseline.add_findings_from_report(report)
                created_baseline_path = os.path.join(
                    os.path.abspath(root_folder), '.checkov.baseline')
                with open(created_baseline_path, 'w') as f:
                    json.dump(overall_baseline.to_dict(), f, indent=4)
            exit_codes.append(
                runner_registry.print_reports(
                    scan_reports,
                    config,
                    url=url,
                    created_baseline_path=created_baseline_path,
                    baseline=baseline))
        exit_code = 1 if 1 in exit_codes else 0
        return exit_code
    elif config.file:
        scan_reports = runner_registry.run(
            external_checks_dir=external_checks_dir,
            files=config.file,
            guidelines=guidelines,
            repo_root_for_plan_enrichment=config.repo_root_for_plan_enrichment)
        if baseline:
            baseline.compare_and_reduce_reports(scan_reports)
        if config.create_baseline:
            overall_baseline = Baseline()
            for report in scan_reports:
                overall_baseline.add_findings_from_report(report)
            created_baseline_path = os.path.join(
                os.path.abspath(os.path.commonprefix(config.file)),
                '.checkov.baseline')
            with open(created_baseline_path, 'w') as f:
                json.dump(overall_baseline.to_dict(), f, indent=4)

        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in config.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(
                root_folder,
                files,
                excluded_paths=runner_filter.excluded_paths)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(config.branch)
        return runner_registry.print_reports(
            scan_reports,
            config,
            url=url,
            created_baseline_path=created_baseline_path,
            baseline=baseline)
    elif config.docker_image:
        if config.bc_api_key is None:
            parser.error(
                "--bc-api-key argument is required when using --docker-image")
            return
        if config.dockerfile_path is None:
            parser.error(
                "--dockerfile-path argument is required when using --docker-image"
            )
            return
        if config.branch is None:
            parser.error(
                "--branch argument is required when using --docker-image")
            return
        bc_integration.commit_repository(config.branch)
        image_scanner.scan(config.docker_image, config.dockerfile_path)
    elif not config.quiet:
        print(f"{banner}")

        bc_integration.onboarding()
예제 #9
0
def run(banner=checkov_banner, argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(description='Infrastructure as code static analysis')
    add_parser_args(parser)
    args = parser.parse_args(argv)

    # bridgecrew uses both the urllib3 and requests libraries, while checkov uses the requests library.
    # Allow the user to specify a CA bundle to be used by both libraries.
    bc_integration.setup_http_manager(args.ca_certificate)

    # Disable runners with missing system dependencies
    args.skip_framework = runnerDependencyHandler.disable_incompatible_runners(args.skip_framework)

    runner_filter = RunnerFilter(framework=args.framework, skip_framework=args.skip_framework, checks=args.check, skip_checks=args.skip_check,
                                 download_external_modules=convert_str_to_bool(args.download_external_modules),
                                 external_modules_download_path=args.external_modules_download_path,
                                 evaluate_variables=convert_str_to_bool(args.evaluate_variables), runners=checkov_runners)
    if outer_registry:
        runner_registry = outer_registry
        runner_registry.runner_filter = runner_filter
    else:
        runner_registry = RunnerRegistry(banner, runner_filter, tf_graph_runner(), cfn_runner(), k8_runner(), sls_runner(),
                                         arm_runner(), tf_plan_runner(), helm_runner(),dockerfile_runner())
    if args.version:
        print(version)
        return

    if args.bc_api_key == '':
        parser.error('The --bc-api-key flag was specified but the value was blank. If this value was passed as a secret, you may need to double check the mapping.')
    elif args.bc_api_key:
        logger.debug(f'Using API key ending with {args.bc_api_key[-8:]}')

        if args.repo_id is None:
            parser.error("--repo-id argument is required when using --bc-api-key")
        if len(args.repo_id.split('/')) != 2:
            parser.error("--repo-id argument format should be 'organization/repository_name' E.g "
                         "bridgecrewio/checkov")

        source = os.getenv('BC_SOURCE', 'cli')
        source_version = os.getenv('BC_SOURCE_VERSION', version)
        logger.debug(f'BC_SOURCE = {source}, version = {source_version}')
        try:
            bc_integration.setup_bridgecrew_credentials(bc_api_key=args.bc_api_key, repo_id=args.repo_id, 
                                                        skip_fixes=args.skip_fixes,
                                                        skip_suppressions=args.skip_suppressions,
                                                        source=source, source_version=source_version, repo_branch=args.branch)
        except Exception as e:
            logger.error('An error occurred setting up the Bridgecrew platform integration. Please check your API token and try again.', exc_info=True)
            return
    else:
        logger.debug('No API key found. Scanning locally only.')

    guidelines = {}
    if not args.no_guide:
        guidelines = bc_integration.get_guidelines()
    if args.check and args.skip_check:
        parser.error("--check and --skip-check can not be applied together. please use only one of them")
        return
    if args.list:
        print_checks(framework=args.framework)
        return
    external_checks_dir = get_external_checks_dir(args)
    url = None

    if args.directory:
        exit_codes = []
        for root_folder in args.directory:
            file = args.file
            scan_reports = runner_registry.run(root_folder=root_folder, external_checks_dir=external_checks_dir,
                                               files=file, guidelines=guidelines, bc_integration=bc_integration)
            if bc_integration.is_integration_configured():
                bc_integration.persist_repository(root_folder)
                bc_integration.persist_scan_results(scan_reports)
                url = bc_integration.commit_repository(args.branch)

            exit_codes.append(runner_registry.print_reports(scan_reports, args, url))

        exit_code = 1 if 1 in exit_codes else 0
        return exit_code
    elif args.file:
        scan_reports = runner_registry.run(external_checks_dir=external_checks_dir, files=args.file,
                                           guidelines=guidelines, bc_integration=bc_integration)
        if bc_integration.is_integration_configured():
            files = [os.path.abspath(file) for file in args.file]
            root_folder = os.path.split(os.path.commonprefix(files))[0]
            bc_integration.persist_repository(root_folder)
            bc_integration.persist_scan_results(scan_reports)
            url = bc_integration.commit_repository(args.branch)
        return runner_registry.print_reports(scan_reports, args, url)
    elif args.docker_image:
        if args.bc_api_key is None:
            parser.error("--bc-api-key argument is required when using --docker-image")
            return
        if args.dockerfile_path is None:
            parser.error("--dockerfile-path argument is required when using --docker-image")
            return
        if args.branch is None:
            parser.error("--branch argument is required when using --docker-image")
            return
        image_scanner.scan(args.docker_image, args.dockerfile_path)
    else:
        print(f"{banner}")

        bc_integration.onboarding()