def test__generate_evaluation_regex(self): definition_type1, var_name1 = 'locals', 'dummy' definition_type2, var_name2 = 'variable', 'customer_name' self.assertEqual( BaseVariableEvaluation._generate_evaluation_regex( definition_type1, var_name1), "((?:\$\{)?local\.dummy(?:\})?)") self.assertEqual( BaseVariableEvaluation._generate_evaluation_regex( definition_type2, var_name2), "((?:\$\{)?var\.customer_name(?:\})?)")
def test__is_variable_only_expression(self): entry_expression1 = "${local.dummy_with_comma}" assignment_regex1 = '((?:\\$\\{)?local\\.dummy_with_comma(?:\\})?)' entry_expression2 = "var.customer_name" assignment_regex2 = '((?:\\$\\{)?var\\.customer_name(?:\\})?)' entry_expression3 = "${var.customer_name}_with_more_stuff" assignment_regex3 = '((?:\\$\\{)?var\\.customer_name(?:\\})?)' self.assertTrue( BaseVariableEvaluation._is_variable_only_expression( assignment_regex1, entry_expression1)) self.assertTrue( BaseVariableEvaluation._is_variable_only_expression( assignment_regex2, entry_expression2)) self.assertFalse( BaseVariableEvaluation._is_variable_only_expression( assignment_regex3, entry_expression3))
def run_block(self, entities, definition_context, full_file_path, report, scanned_file, block_type, runner_filter=None): registry = self.block_type_registries[block_type] if registry: for entity in entities: entity_evaluations = None context_parser = parser_registry.context_parsers[block_type] definition_path = context_parser.get_entity_context_path(entity) entity_id = ".".join(definition_path) entity_context_path = [block_type] + definition_path for _, entity_context in dpath.search(definition_context[full_file_path], entity_context_path, yielded=True): entity_lines_range = [entity_context.get('start_line'), entity_context.get('end_line')] entity_code_lines = entity_context.get('code_lines') skipped_checks = entity_context.get('skipped_checks') variables_evaluations = definition_context[full_file_path].get('evaluations') if variables_evaluations: entity_evaluations = BaseVariableEvaluation.reduce_entity_evaluations(variables_evaluations, entity_context_path) results = registry.scan(scanned_file, entity, skipped_checks, runner_filter) for check, check_result in results.items(): record = Record(check_id=check.id, check_name=check.name, check_result=check_result, code_block=entity_code_lines, file_path=scanned_file, file_line_range=entity_lines_range, resource=entity_id, evaluations=entity_evaluations, check_class=check.__class__.__module__) report.add_record(record=record)
def run_block(self, entities, definition_context, full_file_path, root_folder, report, scanned_file, block_type, runner_filter=None, entity_context_path_header=None): registry = self.block_type_registries[block_type] if not registry: return for entity in entities: entity_evaluations = None context_parser = parser_registry.context_parsers[block_type] definition_path = context_parser.get_entity_context_path(entity) entity_id = ".".join(definition_path) if entity_context_path_header is None: entity_context_path = [block_type] + definition_path else: entity_context_path = entity_context_path_header + block_type + definition_path # Entity can exist only once per dir, for file as well try: entity_context = dict_utils.getInnerDict(definition_context[full_file_path], entity_context_path) entity_lines_range = [entity_context.get('start_line'), entity_context.get('end_line')] entity_code_lines = entity_context.get('code_lines') skipped_checks = entity_context.get('skipped_checks') except KeyError: # TODO: Context info isn't working for modules entity_lines_range = None entity_code_lines = None skipped_checks = None if full_file_path in self.evaluations_context: variables_evaluations = {} for var_name, context_info in self.evaluations_context.get(full_file_path, {}).items(): variables_evaluations[var_name] = dataclasses.asdict(context_info) entity_evaluations = BaseVariableEvaluation.reduce_entity_evaluations(variables_evaluations, entity_context_path) results = registry.scan(scanned_file, entity, skipped_checks, runner_filter) absolut_scanned_file_path = self._strip_module_referrer(file_path=full_file_path) # This duplicates a call at the start of scan, but adding this here seems better than kludging with some tuple return type (entity_type, _, entity_config) = registry.extract_entity_details(entity) tags = get_resource_tags(entity_type, entity_config) for check, check_result in results.items(): record = Record(check_id=check.id, check_name=check.name, check_result=check_result, code_block=entity_code_lines, file_path=scanned_file, file_line_range=entity_lines_range, resource=entity_id, evaluations=entity_evaluations, check_class=check.__class__.__module__, file_abs_path=absolut_scanned_file_path, entity_tags=tags) report.add_record(record=record)
def run_block(self, entities, definition_context, full_file_path, root_folder, report, scanned_file, block_type, runner_filter=None, entity_context_path_header=None, module_referrer: Optional[str] = None): registry = self.block_type_registries[block_type] if not registry: return for entity in entities: entity_evaluations = None context_parser = parser_registry.context_parsers[block_type] definition_path = context_parser.get_entity_context_path(entity) entity_id = ".".join( definition_path) # example: aws_s3_bucket.my_bucket caller_file_path = None caller_file_line_range = None if module_referrer is not None: referrer_id = self._find_id_for_referrer( full_file_path, self.tf_definitions) if referrer_id: entity_id = f"{referrer_id}.{entity_id}" # ex: module.my_module.aws_s3_bucket.my_bucket abs_caller_file = module_referrer[:module_referrer. rindex("#")] caller_file_path = f"/{os.path.relpath(abs_caller_file, root_folder)}" try: caller_context = dpath.get( definition_context[abs_caller_file], # HACK ALERT: module data is currently double-nested in # definition context. If fixed, remove the # addition of "module." at the beginning. "module." + referrer_id, separator=".") except KeyError: logging.debug("Unable to find caller context for: %s", abs_caller_file) caller_context = None if caller_context: caller_file_line_range = [ caller_context.get('start_line'), caller_context.get('end_line') ] else: logging.debug( f"Unable to find referrer ID for full path: %s", full_file_path) if entity_context_path_header is None: entity_context_path = [block_type] + definition_path else: entity_context_path = entity_context_path_header + block_type + definition_path # Entity can exist only once per dir, for file as well try: entity_context = dict_utils.getInnerDict( definition_context[full_file_path], entity_context_path) entity_lines_range = [ entity_context.get('start_line'), entity_context.get('end_line') ] entity_code_lines = entity_context.get('code_lines') skipped_checks = entity_context.get('skipped_checks') except KeyError: # TODO: Context info isn't working for modules entity_lines_range = None entity_code_lines = None skipped_checks = None if full_file_path in self.evaluations_context: variables_evaluations = {} for var_name, context_info in self.evaluations_context.get( full_file_path, {}).items(): variables_evaluations[var_name] = dataclasses.asdict( context_info) entity_evaluations = BaseVariableEvaluation.reduce_entity_evaluations( variables_evaluations, entity_context_path) results = registry.scan(scanned_file, entity, skipped_checks, runner_filter) absolut_scanned_file_path, _ = self._strip_module_referrer( file_path=full_file_path) # This duplicates a call at the start of scan, but adding this here seems better than kludging with some tuple return type (entity_type, entity_name, entity_config) = registry.extract_entity_details(entity) tags = get_resource_tags(entity_type, entity_config) for check, check_result in results.items(): record = Record(check_id=check.id, check_name=check.name, check_result=check_result, code_block=entity_code_lines, file_path=scanned_file, file_line_range=entity_lines_range, resource=entity_id, evaluations=entity_evaluations, check_class=check.__class__.__module__, file_abs_path=absolut_scanned_file_path, entity_tags=tags, caller_file_path=caller_file_path, caller_file_line_range=caller_file_line_range) breadcrumb = self.breadcrumbs.get(record.file_path, {}).get( '.'.join([entity_type, entity_name])) if breadcrumb: record = GraphRecord(record, breadcrumb) report.add_record(record=record)