def check_definitions(self, root_folder, runner_filter, report): for file_abs_path, definition in self.definitions.items(): cf_file = f"/{os.path.relpath(file_abs_path, root_folder)}" if isinstance( definition, dict) and TemplateSections.RESOURCES in definition.keys(): for resource_name, resource in definition[ TemplateSections.RESOURCES].items(): resource_id = ContextParser.extract_cf_resource_id( resource, resource_name) # check that the resource can be parsed as a CF resource if resource_id: resource_context = self.context[file_abs_path][ TemplateSections.RESOURCES][resource_name] entity_lines_range = [ resource_context['start_line'], resource_context['end_line'] ] entity_code_lines = resource_context['code_lines'] if entity_lines_range and entity_code_lines: # TODO - Variable Eval Message! variable_evaluations = {} skipped_checks = ContextParser.collect_skip_comments( entity_code_lines) entity = {resource_name: resource} results = cfn_registry.scan( cf_file, entity, skipped_checks, runner_filter) tags = cfn_utils.get_resource_tags(entity) for check, check_result in results.items(): record = Record( check_id=check.id, bc_check_id=check.bc_id, check_name=check.name, check_result=check_result, code_block=entity_code_lines, file_path=cf_file, file_line_range=entity_lines_range, resource=resource_id, evaluations=variable_evaluations, check_class=check.__class__.__module__, file_abs_path=file_abs_path, entity_tags=tags) breadcrumb = self.breadcrumbs.get( record.file_path, {}).get(record.resource) if breadcrumb: record = GraphRecord(record, breadcrumb) record.set_guideline(check.guideline) report.add_record(record=record)
def get_graph_checks_report(self, root_folder, runner_filter: RunnerFilter): report = Report(self.check_type) checks_results = {} for r in self.external_registries + [graph_registry]: r.load_checks() registry_results = r.run_checks( self.graph_manager.get_reader_traversal(), runner_filter) checks_results = {**checks_results, **registry_results} for check, check_results in checks_results.items(): for check_result in check_results: entity = check_result['entity'] entity_context, entity_evaluations = self.get_entity_context_and_evaluations( entity) if entity_context: full_file_path = entity[CustomAttributes.FILE_PATH] copy_of_check_result = copy.deepcopy(check_result) for skipped_check in entity_context.get( 'skipped_checks', []): if skipped_check['id'] == check.id: copy_of_check_result[ 'result'] = CheckResult.SKIPPED copy_of_check_result[ 'suppress_comment'] = skipped_check[ 'suppress_comment'] break copy_of_check_result['entity'] = entity.get( CustomAttributes.CONFIG) record = Record( check_id=check.id, check_name=check.name, check_result=copy_of_check_result, code_block=entity_context.get('code_lines'), file_path= f"/{os.path.relpath(full_file_path, root_folder)}", file_line_range=[ entity_context.get('start_line'), entity_context.get('end_line') ], resource=".".join(entity_context['definition_path']), evaluations=entity_evaluations, check_class=check.__class__.__module__, file_abs_path=os.path.abspath(full_file_path)) breadcrumb = self.breadcrumbs.get(record.file_path, {}).get(record.resource) if breadcrumb: record = GraphRecord(record, breadcrumb) report.add_record(record=record) return report
def get_graph_checks_report(self, root_folder: str, runner_filter: RunnerFilter) -> Report: report = Report(self.check_type) checks_results = self.run_graph_checks_results(runner_filter) for check, check_results in checks_results.items(): for check_result in check_results: entity = check_result["entity"] entity_file_abs_path = entity.get(CustomAttributes.FILE_PATH) entity_file_path = scanned_file = f"/{os.path.relpath(entity_file_abs_path, root_folder)}" entity_name = entity.get( CustomAttributes.BLOCK_NAME).split(".")[1] entity_context = self.context[entity_file_abs_path][ TemplateSections.RESOURCES][entity_name] record = Record( check_id=check.id, check_name=check.name, check_result=check_result, code_block=entity_context.get("code_lines"), file_path=entity_file_path, file_line_range=[ entity_context.get("start_line"), entity_context.get("end_line") ], resource=entity.get(CustomAttributes.ID), evaluations={}, check_class=check.__class__.__module__, file_abs_path=entity_file_abs_path, entity_tags={} if not entity.get("Tags") else cfn_utils.parse_entity_tags(entity.get("Tags"))) record.set_guideline(check.guideline) if self.breadcrumbs: breadcrumb = self.breadcrumbs.get(record.file_path, {}).get(record.resource) if breadcrumb: record = GraphRecord(record, breadcrumb) report.add_record(record=record) return report
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)