def __init__(self, banner, runner_filter, *runners): self.logger = logging.getLogger(__name__) self.runner_filter = runner_filter self.runners = runners self.banner = banner self.scan_reports = [] self.filter_runner_framework() self.bc_platform = BcPlatformIntegration()
def test_overriding_pc_api_url(self): instance = BcPlatformIntegration() instance.setup_bridgecrew_credentials( repo_id="bridgecrewio/checkov", prisma_api_url="https://api0.prismacloud.io", source=get_source_type('disabled')) self.assertEqual(instance.api_url, "https://api0.prismacloud.io/bridgecrew") self.assertEqual(instance.prisma_api_url, "https://api0.prismacloud.io")
def test_pre_scan_with_cloned_checks(self): instance = BcPlatformIntegration() instance.skip_policy_download = False instance.platform_integration_configured = True custom_policies_integration = CustomPoliciesIntegration(instance) # mock _get_policies_from_platform method custom_policies_integration._get_policies_from_platform = types.MethodType(_get_policies_from_platform, custom_policies_integration) custom_policies_integration.pre_scan() self.assertEqual(1, len(custom_policies_integration.policies)) self.assertEqual(1, len(custom_policies_integration.bc_cloned_checks))
def mock_bc_integration() -> BcPlatformIntegration: bc_integration = BcPlatformIntegration() bc_integration.bc_api_key = "abcd1234-abcd-1234-abcd-1234abcd1234" bc_integration.setup_bridgecrew_credentials( repo_id="bridgecrewio/checkov", skip_fixes=True, skip_suppressions=True, skip_policy_download=True, source=SourceType("Github", False), source_version="1.0", repo_branch="master", ) return bc_integration
def test_repo_match(self): integration = BcPlatformIntegration() integration.repo_id = 'org/repo' suppressions_integration = SuppressionsIntegration(integration) suppressions_integration._init_repo_regex() self.assertTrue(suppressions_integration._repo_matches('org/repo')) self.assertTrue(suppressions_integration._repo_matches('xyz_org/repo')) self.assertTrue( suppressions_integration._repo_matches('80001234_org/repo')) self.assertFalse(suppressions_integration._repo_matches('org/repo1')) self.assertFalse( suppressions_integration._repo_matches('xyz_org/repo1')) self.assertFalse( suppressions_integration._repo_matches('80001234_org/repo1'))
def test_policy_suppression(self): instance = BcPlatformIntegration() suppressions_integration = SuppressionsIntegration(instance) suppression = { "suppressionType": "Policy", "id": "7caab873-7400-47f9-8b3f-82b33d0463ed", "policyId": "BC_AWS_GENERAL_31", "comment": "No justification comment provided.", "checkovPolicyId": "CKV_AWS_79", } record1 = Record(check_id='CKV_AWS_79', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource=None, evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) record2 = Record(check_id='CKV_AWS_1', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource=None, evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) self.assertTrue(suppressions_integration._check_suppression(record1, suppression)) self.assertFalse(suppressions_integration._check_suppression(record2, suppression))
def test_policy_id_regex(self): suppressions_integration = SuppressionsIntegration( BcPlatformIntegration()) matching_ids = [ 'bcorg_aws_1234567891011', 'bcORrg_aws_1234567891011', 'bcORrg_AWS_1234567891011', 'bcorg12_aws_1234567891011', 'bcorgabcdefgh_azure_1234567891011' ] non_matching_ids = [ 'bcorg_aws_123456789101', 'bcorg_aws123_1234567891011', 'bcorg_1234567891011', 'bcorgabcdefghazure_1234567891011', '_bcorg_aws_1234567891011', ] for id in matching_ids: self.assertIsNotNone( suppressions_integration.custom_policy_id_regex.match(id)) for id in non_matching_ids: self.assertIsNone( suppressions_integration.custom_policy_id_regex.match(id))
def test_account_suppression_cli_repo(self): instance = BcPlatformIntegration() instance.repo_id = 'org/repo' suppressions_integration = SuppressionsIntegration(instance) suppressions_integration._init_repo_regex() suppression = { "suppressionType": "Accounts", "policyId": "BC_AWS_S3_13", "comment": "testing checkov", "accountIds": ["bcorg_org/repo", "bcorg_not/valid"], "checkovPolicyId": "CKV_AWS_18", } record1 = Record(check_id='CKV_AWS_18', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource=None, evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) record2 = Record(check_id='CKV_AWS_1', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource=None, evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) self.assertTrue( suppressions_integration._check_suppression(record1, suppression)) self.assertFalse( suppressions_integration._check_suppression(record2, suppression))
def test_resource_suppression(self): instance = BcPlatformIntegration() instance.repo_id = 'org/repo' suppressions_integration = SuppressionsIntegration(instance) suppression = { "suppressionType": "Resources", "policyId": "BC_AWS_S3_13", "comment": "No justification comment provided.", "resources": [ { "accountId": "org/repo", "resourceId": "/terraform/aws/s3.tf:aws_s3_bucket.operations", } ], "checkovPolicyId": "CKV_AWS_18", } record1 = Record(check_id='CKV_AWS_18', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path=',.', entity_tags=None) record1.repo_file_path = '/terraform/aws/s3.tf' record2 = Record(check_id='CKV_AWS_13', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.no', evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) record2.repo_file_path = '/terraform/aws/s3.tf' record3 = Record(check_id='CKV_AWS_1', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) record3.repo_file_path = '/terraform/aws/s3.tf' self.assertTrue(suppressions_integration._check_suppression(record1, suppression)) self.assertFalse(suppressions_integration._check_suppression(record2, suppression)) self.assertFalse(suppressions_integration._check_suppression(record3, suppression))
def test_guidelines_received(self): guideline1 = 'https://some.guideline.com/111' guideline2 = 'https://another.guideline.com/AWS/asdasd' def request_callback(_): resp_body = {'guidelines': {'CKV_AWS_1': guideline1, 'CKV_AWS_2': guideline2}} headers = {'Content-Type': 'application/json'} return 200, headers, json.dumps(resp_body) responses.add_callback('GET', '/guidelines', callback=request_callback, content_type='application/json') guidelines = BcPlatformIntegration().get_guidelines() self.assertTrue(isinstance(guidelines, dict)) self.assertEqual(len(guidelines), 2) self.assertEqual(guidelines['CKV_AWS_1'], guideline1) self.assertEqual(guidelines['CKV_AWS_2'], guideline2)
def test_integration_valid(self): instance = BcPlatformIntegration() instance.skip_suppressions = False instance.platform_integration_configured = True suppressions_integration = SuppressionsIntegration(instance) self.assertTrue(suppressions_integration.is_valid()) instance.skip_suppressions = True self.assertFalse(suppressions_integration.is_valid()) instance.platform_integration_configured = False self.assertFalse(suppressions_integration.is_valid()) instance.skip_suppressions = False self.assertFalse(suppressions_integration.is_valid())
def test_integration_valid(self): instance = BcPlatformIntegration() instance.skip_policy_download = False instance.platform_integration_configured = True custom_policies_integration = CustomPoliciesIntegration(instance) self.assertTrue(custom_policies_integration.is_valid()) instance.skip_policy_download = True self.assertFalse(custom_policies_integration.is_valid()) instance.platform_integration_configured = False self.assertFalse(custom_policies_integration.is_valid()) instance.skip_policy_download = False self.assertFalse(custom_policies_integration.is_valid())
def test_integration_valid(self): instance = BcPlatformIntegration() instance.skip_fixes = False instance.platform_integration_configured = True fixes_integration = FixesIntegration(instance) self.assertTrue(fixes_integration.is_valid()) instance.skip_fixes = True self.assertFalse(fixes_integration.is_valid()) instance.platform_integration_configured = False self.assertFalse(fixes_integration.is_valid()) instance.skip_fixes = False self.assertFalse(fixes_integration.is_valid())
def test_overriding_bc_source(self): instance = BcPlatformIntegration() self.assertEqual(instance.bc_source, "foo")
def test_overriding_bc_api_url(self): instance = BcPlatformIntegration() self.assertEqual(instance.bc_api_url, "foo")
def run(banner=checkov_banner): parser = argparse.ArgumentParser( description='Infrastructure as code static analysis') add_parser_args(parser) args = parser.parse_args() bc_integration = BcPlatformIntegration() runner_filter = RunnerFilter(framework=args.framework, checks=args.check, skip_checks=args.skip_check) 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()) 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("No argument given. Try ` --help` for further information")
def test_real_guidelines(self): guidelines = BcPlatformIntegration().get_guidelines() self.assertGreater(len(guidelines.keys()), 0)
def test_guidelines_not_received(self): guidelines = BcPlatformIntegration().get_guidelines() self.assertEqual(guidelines, {})
def test_no_overriding_api_url(self): instance = BcPlatformIntegration() self.assertEqual(instance.api_url, "https://www.bridgecrew.cloud")
def test_suppression_valid(self): instance = BcPlatformIntegration() instance.repo_id = 'org/repo' instance.bc_id_mapping = {'BC_AWS_1': 'CKV_AWS_20'} suppressions_integration = SuppressionsIntegration(instance) suppression = { "suppressionType": "Accounts", "policyId": "BC_AWS_1", "creationDate": 1608816140086, "comment": "No justification comment provided.", "accountIds": ["org/repo"] } self.assertTrue( suppressions_integration._suppression_valid_for_run(suppression)) suppression = { "suppressionType": "Resources", "policyId": "BC_AWS_1", "creationDate": 1608816140086, "comment": "No justification comment provided.", "resources": { "accountId": "org/repo", "resourceId": "/s3.tf" } } self.assertTrue( suppressions_integration._suppression_valid_for_run(suppression)) suppression = { "suppressionType": "Tags", "policyId": "BC_AWS_1", "creationDate": 1610035761349, "comment": "No justification comment provided.", "tags": [{ "value": "test_1", "key": "test_num" }] } self.assertTrue( suppressions_integration._suppression_valid_for_run(suppression)) suppression = { "suppressionType": "Policy", "policyId": "BC_AWS_1", "creationDate": 1602670330384, "comment": "No justification comment provided." } self.assertTrue( suppressions_integration._suppression_valid_for_run(suppression)) suppression = { "suppressionType": "Accounts", "policyId": "BC_AWS_1", "creationDate": 1608816140086, "comment": "No justification comment provided.", "accountIds": ["other/repo"] } self.assertFalse( suppressions_integration._suppression_valid_for_run(suppression)) suppression = { "suppressionType": "Tags", "policyId": "NOT_A_POLICY", "creationDate": 1610035761349, "comment": "No justification comment provided.", "tags": [{ "value": "test_1", "key": "test_num" }] } self.assertFalse( suppressions_integration._suppression_valid_for_run(suppression)) # custom policy suppression = { "suppressionType": "Tags", "policyId": "bcorg_aws_1234567891011", "creationDate": 1610035761349, "comment": "No justification comment provided.", "tags": [{ "value": "test_1", "key": "test_num" }] } self.assertTrue( suppressions_integration._suppression_valid_for_run(suppression))
def test_tag_suppression(self): instance = BcPlatformIntegration() suppressions_integration = SuppressionsIntegration(instance) suppression = { "suppressionType": "Tags", "policyId": "BC_AWS_S3_16", "comment": "No justification comment provided.", "tags": [{ "value": "value1", "key": "tag1" }, { "value": "value2", "key": "tag2" }], "checkovPolicyId": "CKV_AWS_21", } record1 = Record(check_id='CKV_AWS_21', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path=',.', entity_tags={'tag1': 'value1'}) record2 = Record(check_id='CKV_AWS_1', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.no', evaluations=None, check_class=None, file_abs_path='.', entity_tags={'tag1': 'value1'}) record3 = Record(check_id='CKV_AWS_21', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path='.', entity_tags={ 'tag1': 'value2222', 'tag2': 'value2' }) record4 = Record(check_id='CKV_AWS_21', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path='.', entity_tags={ 'tag1': 'value2222', 'tag2': 'value1111' }) record5 = Record(check_id='CKV_AWS_21', check_name=None, check_result=None, code_block=None, file_path=None, file_line_range=None, resource='aws_s3_bucket.operations', evaluations=None, check_class=None, file_abs_path='.', entity_tags=None) self.assertTrue( suppressions_integration._check_suppression(record1, suppression)) self.assertFalse( suppressions_integration._check_suppression(record2, suppression)) self.assertTrue( suppressions_integration._check_suppression(record3, suppression)) self.assertFalse( suppressions_integration._check_suppression(record4, suppression)) self.assertFalse( suppressions_integration._check_suppression(record5, suppression))
def test_overriding_pc_api_url(self): instance = BcPlatformIntegration() self.assertEqual(instance.api_url, "prisma/bridgecrew") self.assertEqual(instance.prisma_url, "prisma")
def test_default_bc_source(self): instance = BcPlatformIntegration() self.assertEqual(instance.bc_source, "cli")
def run(banner=checkov_banner): parser = argparse.ArgumentParser( description='Infrastructure as code static analysis') parser.add_argument('-v', '--version', help='version', action='store_true') parser.add_argument( '-d', '--directory', action='append', help= 'IaC root directory (can not be used together with --file). Can be repeated' ) parser.add_argument( '-f', '--file', action='append', help='IaC file(can not be used together with --directory)') parser.add_argument( '--external-checks-dir', action='append', help='Directory for custom checks to be loaded. Can be repeated') parser.add_argument('-l', '--list', help='List checks', action='store_true') parser.add_argument( '-o', '--output', nargs='?', choices=['cli', 'json', 'junitxml', 'github_failed_only'], default='cli', help='Report output format') parser.add_argument( '--framework', help= 'filter scan to run only on a specific infrastructure code frameworks', choices=['cloudformation', 'terraform', 'kubernetes', 'all'], default='all') parser.add_argument( '-c', '--check', help= 'filter scan to run only on a specific check identifier(whitelist), You can ' 'specify multiple checks separated by comma delimiter', default=None) parser.add_argument( '--skip-check', help= 'filter scan to run on all check but a specific check identifier(blacklist), You can ' 'specify multiple checks separated by comma delimiter', default=None) parser.add_argument('-s', '--soft-fail', help='Runs checks but suppresses error code', action='store_true') parser.add_argument('--bc-api-key', help='Bridgecrew API key') parser.add_argument( '--repo-id', help= 'Identity string of the repository, with form <repo_owner>/<repo_name>' ) parser.add_argument( '-b', '--branch', help= "Selected branch of the persisted repository. Only has effect when using the --bc-api-key flag", default='master') args = parser.parse_args() bc_integration = BcPlatformIntegration() runner_filter = RunnerFilter(framework=args.framework, checks=args.check, skip_checks=args.skip_check) runner_registry = RunnerRegistry(banner, runner_filter, tf_runner(), cfn_runner(), k8_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) 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() return if args.directory: for root_folder in args.directory: file = args.file scan_reports = runner_registry.run( root_folder=root_folder, external_checks_dir=args.external_checks_dir, files=file) 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=args.external_checks_dir, files=args.file) 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("No argument given. Try ` --help` for further information")
def test_skip_mapping_false(self): instance = BcPlatformIntegration() instance.get_id_mapping() self.assertNotEquals(None, instance.ckv_to_bc_id_mapping)
def test_skip_mapping(self): instance = BcPlatformIntegration() instance.setup_http_manager() instance.get_id_mapping() self.assertEqual(None,instance.ckv_to_bc_id_mapping)
def test_skip_mapping_true(self): instance = BcPlatformIntegration() instance.bc_skip_mapping = True instance.setup_http_manager() instance.get_id_mapping() self.assertDictEqual({}, instance.ckv_to_bc_id_mapping)
def test_skip_mapping_default(self): # Default is False so mapping is obtained instance = BcPlatformIntegration() instance.setup_http_manager() instance.get_id_mapping() self.assertIsNotNone(instance.ckv_to_bc_id_mapping)
def test_skip_mapping_false(self): instance = BcPlatformIntegration() instance.setup_http_manager() instance.get_id_mapping() self.assertIsNotNone(instance.ckv_to_bc_id_mapping)
class RunnerRegistry(object): runners = [] scan_reports = [] banner = "" def __init__(self, banner, runner_filter, *runners): self.logger = logging.getLogger(__name__) self.runner_filter = runner_filter self.runners = runners self.banner = banner self.scan_reports = [] self.filter_runner_framework() self.bc_platform = BcPlatformIntegration() @abstractmethod def extract_entity_details(self, entity): raise NotImplementedError() def run(self, root_folder=None, external_checks_dir=None, files=None, guidelines=None, collect_skip_comments=True, bc_integration=None): for runner in self.runners: integration_feature_registry.run_pre_scan() scan_report = runner.run( root_folder, external_checks_dir=external_checks_dir, files=files, runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments) integration_feature_registry.run_post_scan(scan_report) if guidelines: RunnerRegistry.enrich_report_with_guidelines( scan_report, guidelines) self.scan_reports.append(scan_report) return self.scan_reports def print_reports(self, scan_reports, args, url=None): if args.output == 'cli': print(f"{self.banner}\n") exit_codes = [] report_jsons = [] junit_reports = [] for report in scan_reports: if not report.is_empty(): if args.output == "json": report_jsons.append(report.get_dict(is_quiet=args.quiet)) elif args.output == "junitxml": junit_reports.append(report) # report.print_junit_xml() elif args.output == 'github_failed_only': report.print_failed_github_md() else: report.print_console(is_quiet=args.quiet, is_compact=args.compact) if url: print("More details: {}".format(url)) exit_codes.append(report.get_exit_code(args.soft_fail)) if args.output == "junitxml": if len(junit_reports) == 1: junit_reports[0].print_junit_xml() else: master_report = Report(None) for report in junit_reports: master_report.skipped_checks += report.skipped_checks master_report.passed_checks += report.passed_checks master_report.failed_checks += report.failed_checks master_report.print_junit_xml() if args.output == "json": if len(report_jsons) == 1: print(json.dumps(report_jsons[0], indent=4)) else: print(json.dumps(report_jsons, indent=4)) if args.output == "cli": self.bc_platform.get_report_to_platform(args, scan_reports) exit_code = 1 if 1 in exit_codes else 0 exit(exit_code) def filter_runner_framework(self): if not self.runner_filter: return if self.runner_filter.framework is None: return if self.runner_filter.framework == 'all': return filtered_runners = [] for runner in self.runners: if runner.check_type in self.runner_filter.framework: filtered_runners.append(runner) self.runners = filtered_runners return @staticmethod def enrich_report_with_guidelines(scan_report, guidelines): for record in scan_report.failed_checks + scan_report.passed_checks + scan_report.skipped_checks: if record.check_id in guidelines: record.set_guideline(guidelines[record.check_id])