Ejemplo n.º 1
0
def test_prompt_terraform_gcp_resource(capsys: CaptureFixture[str]):
    test_name = "GCPTestPromptUnitTest"
    choices = [
        "add",
        f"{test_name}",
        "iam",
        "Tests for the GCP Prompt Unit Test",
        "terraform",
        "gcp",
        "resource",
        "google_project_iam_policy",
    ]

    mock_click = click
    mock_click.prompt = MagicMock(name="prompt", side_effect=choices)
    resp = prompt.Prompt()
    check = prompt.Check(resp.responses)
    check.action()

    captured = capsys.readouterr()

    expected = [
        f"Creating Check {test_name}.py",
        f"Creating Unit Test Stubs for {test_name}",
        "Successfully created",
        f"checkov/terraform/checks/resource/gcp/{test_name}.py",
        "Next steps:",
    ]

    for exp in expected:
        assert exp in captured.out
Ejemplo n.º 2
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()