def test_load_inner_registry_module(self): parser = Parser() directory = os.path.join(self.resources_dir, "registry_security_group_inner_module") self.external_module_path = os.path.join(self.tmp_path, DEFAULT_EXTERNAL_MODULES_DIR) out_definitions = {} parser.parse_directory(directory=directory, out_definitions=out_definitions, out_evaluations_context={}, download_external_modules=True, external_modules_download_path=self.external_module_path) self.assertEqual(11, len(list(out_definitions.keys()))) expected_remote_module_path = f'{self.external_module_path}/github.com/terraform-aws-modules/terraform-aws-security-group/v4.0.0' expected_inner_remote_module_path = f'{expected_remote_module_path}/modules/http-80' expected_main_file = os.path.join(directory, 'main.tf') expected_inner_main_file = os.path.join(directory, expected_inner_remote_module_path, 'main.tf') expected_file_names = [ expected_main_file, os.path.join(directory, expected_inner_remote_module_path, f'auto_values.tf[{expected_main_file}#0]'), os.path.join(directory, expected_inner_remote_module_path, f'main.tf[{expected_main_file}#0]'), os.path.join(directory, expected_inner_remote_module_path, f'outputs.tf[{expected_main_file}#0]'), os.path.join(directory, expected_inner_remote_module_path, f'variables.tf[{expected_main_file}#0]'), os.path.join(directory, expected_inner_remote_module_path, f'versions.tf[{expected_main_file}#0]'), os.path.join(directory, expected_remote_module_path, f'main.tf[{expected_inner_main_file}#0]'), os.path.join(directory, expected_remote_module_path, f'outputs.tf[{expected_inner_main_file}#0]'), os.path.join(directory, expected_remote_module_path, f'rules.tf[{expected_inner_main_file}#0]'), os.path.join(directory, expected_remote_module_path, f'variables.tf[{expected_inner_main_file}#0]'), os.path.join(directory, expected_remote_module_path, f'versions.tf[{expected_inner_main_file}#0]'), ] for expected_file_name in expected_file_names: if expected_file_name not in list(out_definitions.keys()): self.fail(f"expected file {expected_file_name} to be in out_definitions")
def go(dir_name): dir_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), f"resources/parser_scenarios/{dir_name}") assert os.path.exists(dir_path) expected_data = TestParserScenarios.load_expected_data("expected.json", dir_path) assert expected_data is not None, f"{dir_name}: expected.json file not found" evaluation_data = TestParserScenarios.load_expected_data("eval.json", dir_path) actual_data = {} actual_eval_data = {} errors = {} parser = Parser() parser.parse_directory(dir_path, actual_data, actual_eval_data, errors, download_external_modules=True) assert not errors, f"{dir_name}: Unexpected errors: {errors}" definition_string = json.dumps(actual_data, indent=2, default=json_encoder) definition_encoded = json.loads(definition_string) assert definition_encoded == expected_data, \ f"{dir_name}: Data mismatch:\n" \ f" Expected: \n{json.dumps(expected_data, indent=2, default=json_encoder)}\n\n" \ f" Actual: \n{definition_string}" if evaluation_data is not None: definition_string = json.dumps(actual_eval_data, indent=2, default=json_encoder) definition_encoded = json.loads(definition_string) assert definition_encoded == evaluation_data, \ f"{dir_name}: Evaluation data mismatch:\n" \ f" Expected: \n{json.dumps(evaluation_data, indent=2, default=json_encoder)}\n\n" \ f" Actual: \n{definition_string}"
def test_malformed_output_blocks(self): parser = Parser() directory = os.path.join(self.resources_dir, "malformed_outputs") self.external_module_path = os.path.join(directory, DEFAULT_EXTERNAL_MODULES_DIR) out_definitions = {} parser.parse_directory(directory=directory, out_definitions=out_definitions, out_evaluations_context={}, download_external_modules=True, external_modules_download_path=DEFAULT_EXTERNAL_MODULES_DIR) file_path, entity_definitions = next(iter(out_definitions.items())) self.assertEqual(2, len(list(out_definitions[file_path]['output'])))
def test_invalid_module_sources(self): parser = Parser() directory = os.path.join(self.resources_dir, "failing_module_address") self.external_module_path = os.path.join(directory, DEFAULT_EXTERNAL_MODULES_DIR) out_definitions = {} parser.parse_directory(directory=directory, out_definitions=out_definitions, out_evaluations_context={}, download_external_modules=True, external_modules_download_path=DEFAULT_EXTERNAL_MODULES_DIR) # check that only the original file was parsed successfully without getting bad external modules self.assertEqual(1, len(list(out_definitions.keys())))
def test_load_registry_module(self): parser = Parser() directory = os.path.join(self.resources_dir, "registry_security_group") self.external_module_path = os.path.join(directory, DEFAULT_EXTERNAL_MODULES_DIR) out_definitions = {} parser.parse_directory(directory=directory, out_definitions=out_definitions, out_evaluations_context={}, download_external_modules=True, external_modules_download_path=DEFAULT_EXTERNAL_MODULES_DIR) external_aws_modules_path = os.path.join(self.external_module_path, 'github.com/terraform-aws-modules/terraform-aws-security-group/v3.18.0') assert os.path.exists(external_aws_modules_path)
def test_load_local_module(self): # given parser = Parser() directory = os.path.join(self.resources_dir, "local_module") out_definitions = {} # when parser.parse_directory( directory=directory, out_definitions=out_definitions, out_evaluations_context={} ) # then self.assertEqual(len(out_definitions), 3) # root file + 2x module file self.assertEqual(len(parser.loaded_files_map), 2) # root file + 1x module file
def test_external_definitions_context(self): current_dir = os.path.dirname(os.path.realpath(__file__)) tf_dir_path = current_dir + "/resources/valid_tf_only_passed_checks" external_definitions_context = { f'{current_dir}/resources/valid_tf_only_passed_checks/example.tf': { 'resource': { 'aws_s3_bucket': { 'foo-bucket': { 'start_line': 1, 'end_line': 34, 'code_lines': [(1, 'resource "aws_s3_bucket" "foo-bucket" {\n'), (2, ' region = var.region\n'), (3, ' bucket = local.bucket_name\n'), (4, ' force_destroy = true\n'), (5, ' tags = {\n'), (6, ' Name = "foo-${data.aws_caller_identity.current.account_id}"\n' ), (7, ' }\n'), (8, ' versioning {\n'), (9, ' enabled = true\n'), (10, ' mfa_delete = true\n'), (11, ' }\n'), (12, ' logging {\n'), (13, ' target_bucket = "${aws_s3_bucket.log_bucket.id}"\n' ), (14, ' target_prefix = "log/"\n'), (15, ' }\n'), (16, ' server_side_encryption_configuration {\n'), (17, ' rule {\n'), (18, ' apply_server_side_encryption_by_default {\n' ), (19, ' kms_master_key_id = "${aws_kms_key.mykey.arn}"\n' ), (20, ' sse_algorithm = "aws:kms"\n'), (21, ' }\n'), (22, ' }\n'), (23, ' }\n'), (24, ' acl = "private"\n'), (25, ' tags = "${merge\n'), (26, ' (\n'), (27, ' var.common_tags,\n'), (28, ' map(\n'), (29, ' "name", "VM Virtual Machine",\n'), (30, ' "group", "foo"\n'), (31, ' )\n'), (32, ' )\n'), (33, ' }"\n'), (34, '}\n')], 'skipped_checks': [] } }, 'null_resource': { 'example': { 'start_line': 36, 'end_line': 46, 'code_lines': [(36, 'resource "null_resource" "example" {\n'), (37, ' tags = "${merge\n'), (38, '(\n'), (39, 'var.common_tags,\n'), (40, 'map(\n'), (41, '"name", "VM Base Post Provisioning Library",\n' ), (42, '"group", "aut",\n'), (43, '"dependency", "${var.input_dependency_value}")\n' ), (44, ')\n'), (45, '}"\n'), (46, '}\n')], 'skipped_checks': [] } } }, 'data': { 'aws_caller_identity': { 'current': { 'start_line': 47, 'end_line': 0, 'code_lines': [], 'skipped_checks': [] } } }, 'provider': { 'kubernetes': { 'default': { 'start_line': 49, 'end_line': 55, 'code_lines': [(49, 'provider "kubernetes" {\n'), (50, ' version = "1.10.0"\n'), (51, ' host = module.aks_cluster.kube_config.0.host\n' ), (52, ' client_certificate = base64decode(module.aks_cluster.kube_config.0.client_certificate)\n' ), (53, 'client_key = base64decode(module.aks_cluster.kube_config.0.client_key)\n' ), (54, 'cluster_ca_certificate = base64decode(module.aks_cluster.kube_config.0.cluster_ca_certificate)\n' ), (55, '}\n')], 'skipped_checks': [] } } }, 'module': { 'module': { 'new_relic': { 'start_line': 57, 'end_line': 67, 'code_lines': [(57, 'module "new_relic" {\n'), (58, 'source = "s3::https://s3.amazonaws.com/my-artifacts/new-relic-k8s-0.2.5.zip"\n' ), (59, 'kubernetes_host = module.aks_cluster.kube_config.0.host\n' ), (60, 'kubernetes_client_certificate = base64decode(module.aks_cluster.kube_config.0.client_certificate)\n' ), (61, 'kubernetes_client_key = base64decode(module.aks_cluster.kube_config.0.client_key)\n' ), (62, 'kubernetes_cluster_ca_certificate = base64decode(module.aks_cluster.kube_config.0.cluster_ca_certificate)\n' ), (63, 'cluster_name = module.naming_conventions.aks_name\n' ), (64, 'new_relic_license = data.vault_generic_secret.new_relic_license.data["license"]\n' ), (65, 'cluster_ca_bundle_b64 = module.aks_cluster.kube_config.0.cluster_ca_certificate\n' ), (66, 'module_depends_on = [null_resource.delay_aks_deployments]\n' ), (67, '}')], 'skipped_checks': [] } } } }, f'{current_dir}/resources/valid_tf_only_passed_checks/example_skip_acl.tf': { 'resource': { 'aws_s3_bucket': { 'foo-bucket': { 'start_line': 1, 'end_line': 26, 'code_lines': [(1, 'resource "aws_s3_bucket" "foo-bucket" {\n'), (2, ' region = var.region\n'), (3, ' bucket = local.bucket_name\n'), (4, ' force_destroy = true\n'), (5, ' #checkov:skip=CKV_AWS_20:The bucket is a public static content host\n' ), (6, ' #bridgecrew:skip=CKV_AWS_52: foo\n'), (7, ' tags = {\n'), (8, ' Name = "foo-${data.aws_caller_identity.current.account_id}"\n' ), (9, ' }\n'), (10, ' versioning {\n'), (11, ' enabled = true\n'), (12, ' }\n'), (13, ' logging {\n'), (14, ' target_bucket = "${aws_s3_bucket.log_bucket.id}"\n' ), (15, ' target_prefix = "log/"\n'), (16, ' }\n'), (17, ' server_side_encryption_configuration {\n'), (18, ' rule {\n'), (19, ' apply_server_side_encryption_by_default {\n' ), (20, ' kms_master_key_id = "${aws_kms_key.mykey.arn}"\n' ), (21, ' sse_algorithm = "aws:kms"\n'), (22, ' }\n'), (23, ' }\n'), (24, ' }\n'), (25, ' acl = "public-read"\n'), (26, '}\n')], 'skipped_checks': [{ 'id': 'CKV_AWS_20', 'suppress_comment': 'The bucket is a public static content host' }, { 'id': 'CKV_AWS_52', 'suppress_comment': ' foo' }] } } }, 'data': { 'aws_caller_identity': { 'current': { 'start_line': 27, 'end_line': 0, 'code_lines': [], 'skipped_checks': [] } } } } } tf_definitions = { '/Users/nkor/dev/checkov_v2/tests/terraform/runner/resources/valid_tf_only_passed_checks/example.tf': { 'resource': [{ 'aws_s3_bucket': { 'foo-bucket': { 'region': ['${var.region}'], 'bucket': ['${local.bucket_name}'], 'force_destroy': [True], 'versioning': [{ 'enabled': [True], 'mfa_delete': [True] }], 'logging': [{ 'target_bucket': ['${aws_s3_bucket.log_bucket.id}'], 'target_prefix': ['log/'] }], 'server_side_encryption_configuration': [{ 'rule': [{ 'apply_server_side_encryption_by_default': [{ 'kms_master_key_id': ['${aws_kms_key.mykey.arn}'], 'sse_algorithm': ['aws:kms'] }] }] }], 'acl': ['private'], 'tags': [ '${merge\n (\n var.common_tags,\n map(\n "name", "VM Virtual Machine",\n "group", "foo"\n )\n )\n }' ] } } }], 'data': [{ 'aws_caller_identity': { 'current': {} } }], 'provider': [{ 'kubernetes': { 'version': ['1.10.0'], 'host': ['${module.aks_cluster.kube_config[0].host}'], 'client_certificate': [ '${base64decode(module.aks_cluster.kube_config[0].client_certificate)}' ], 'client_key': [ '${base64decode(module.aks_cluster.kube_config[0].client_key)}' ], 'cluster_ca_certificate': [ '${base64decode(module.aks_cluster.kube_config[0].cluster_ca_certificate)}' ] } }], 'module': [{ 'new_relic': { 'source': [ 's3::https://s3.amazonaws.com/my-artifacts/new-relic-k8s-0.2.5.zip' ], 'kubernetes_host': ['${module.aks_cluster.kube_config[0].host}'], 'kubernetes_client_certificate': [ '${base64decode(module.aks_cluster.kube_config[0].client_certificate)}' ], 'kubernetes_client_key': [ '${base64decode(module.aks_cluster.kube_config[0].client_key)}' ], 'kubernetes_cluster_ca_certificate': [ '${base64decode(module.aks_cluster.kube_config[0].cluster_ca_certificate)}' ], 'cluster_name': ['${module.naming_conventions.aks_name}'], 'new_relic_license': [ '${data.vault_generic_secret.new_relic_license.data["license"]}' ], 'cluster_ca_bundle_b64': [ '${module.aks_cluster.kube_config[0].cluster_ca_certificate}' ], 'module_depends_on': [['${null_resource.delay_aks_deployments}']] } }] }, '/Users/nkor/dev/checkov_v2/tests/terraform/runner/resources/valid_tf_only_passed_checks/example_skip_acl.tf': { 'resource': [{ 'aws_s3_bucket': { 'foo-bucket': { 'region': ['${var.region}'], 'bucket': ['${local.bucket_name}'], 'force_destroy': [True], 'tags': [{ 'Name': 'foo-${data.aws_caller_identity.current.account_id}' }], 'versioning': [{ 'enabled': [True] }], 'logging': [{ 'target_bucket': ['${aws_s3_bucket.log_bucket.id}'], 'target_prefix': ['log/'] }], 'server_side_encryption_configuration': [{ 'rule': [{ 'apply_server_side_encryption_by_default': [{ 'kms_master_key_id': ['${aws_kms_key.mykey.arn}'], 'sse_algorithm': ['aws:kms'] }] }] }], 'acl': ['public-read'] } } }], 'data': [{ 'aws_caller_identity': { 'current': {} } }] } } runner = Runner() parser = Parser() runner.tf_definitions = tf_definitions runner.set_external_data(tf_definitions, external_definitions_context, breadcrumbs={}) parser.parse_directory(tf_dir_path, tf_definitions) report = Report('terraform') runner.check_tf_definition(root_folder=tf_dir_path, report=report, runner_filter=RunnerFilter()) self.assertGreaterEqual(len(report.passed_checks), 1)