def create_match_yaml_parser_error(parser_error, filename): """Create a Match for a parser error""" lineno = parser_error.problem_mark.line + 1 colno = parser_error.problem_mark.column + 1 msg = parser_error.problem return Match( lineno, colno, lineno, colno + 1, filename, ParseError(), message=msg)
def create_match_file_error(filename, msg): """Create a Match for a parser error""" return Match(linenumber=1, columnnumber=1, linenumberend=1, columnnumberend=2, filename=filename, rule=ParseError(), message=msg)
def create_match_json_parser_error(parser_error, filename): """Create a Match for a parser error""" if sys.version_info[0] == 3: lineno = parser_error.lineno colno = parser_error.colno msg = parser_error.msg elif sys.version_info[0] == 2: lineno = 1 colno = 1 msg = parser_error.message return Match( lineno, colno, lineno, colno + 1, filename, ParseError(), message=msg)
def create_match_json_parser_error(parser_error, filename): """Create a Match for a parser error""" lineno = parser_error.lineno colno = parser_error.colno msg = parser_error.msg return Match(lineno, colno, lineno, colno + 1, filename, ParseError(), message=msg)
def get_template_rules(filename, args): """ Get Template Configuration items and set them as default values""" global __CACHED_RULES #pylint: disable=global-statement ignore_bad_template = False if args.ignore_bad_template: ignore_bad_template = True else: # There is no collection at this point so we need to handle this # check directly if not ParseError().is_enabled( include_experimental=False, ignore_rules=args.ignore_checks, include_rules=args.include_checks, mandatory_rules=args.mandatory_checks, ): ignore_bad_template = True (template, errors) = cfnlint.decode.decode(filename) if errors: if len(errors ) == 1 and ignore_bad_template and errors[0].rule.id == 'E0000': return (template, [], []) return (template, [], errors) args.template_args = template if __CACHED_RULES: __CACHED_RULES.configure( ignore_rules=args.ignore_checks, include_rules=args.include_checks, configure_rules=args.configure_rules, include_experimental=args.include_experimental, mandatory_rules=args.mandatory_checks, ) else: __CACHED_RULES = cfnlint.core.get_rules( args.append_rules, args.ignore_checks, args.include_checks, args.configure_rules, args.include_experimental, args.mandatory_checks, args.custom_rules, ) return (template, __CACHED_RULES, [])
def decode(filename, ignore_bad_template): """ Decode filename into an object """ template = None matches = [] try: template = cfn_yaml.load(filename) except IOError as e: if e.errno == 2: LOGGER.error('Template file not found: %s', filename) matches.append( create_match_file_error( filename, 'Template file not found: %s' % filename)) elif e.errno == 21: LOGGER.error('Template references a directory, not a file: %s', filename) matches.append( create_match_file_error( filename, 'Template references a directory, not a file: %s' % filename)) elif e.errno == 13: LOGGER.error('Permission denied when accessing template file: %s', filename) matches.append( create_match_file_error( filename, 'Permission denied when accessing template file: %s' % filename)) if matches: return (None, matches) except UnicodeDecodeError as err: LOGGER.error('Cannot read file contents: %s', filename) matches.append( create_match_file_error(filename, 'Cannot read file contents: %s' % filename)) except cfn_yaml.CfnParseError as err: err.match.Filename = filename matches = [err.match] except ParserError as err: matches = [create_match_yaml_parser_error(err, filename)] except ScannerError as err: if err.problem in [ 'found character \'\\t\' that cannot start any token', 'found unknown escape character' ]: try: template = cfn_json.load(filename) except cfn_json.JSONDecodeError as json_err: json_err.match.filename = filename matches = [json_err.match] except JSONDecodeError as json_err: matches = [create_match_json_parser_error(json_err, filename)] except Exception as json_err: # pylint: disable=W0703 if ignore_bad_template: LOGGER.info('Template %s is malformed: %s', filename, err.problem) LOGGER.info('Tried to parse %s as JSON but got error: %s', filename, str(json_err)) else: LOGGER.error('Template %s is malformed: %s', filename, err.problem) LOGGER.error('Tried to parse %s as JSON but got error: %s', filename, str(json_err)) return (None, [ create_match_file_error( filename, 'Tried to parse %s as JSON but got error: %s' % (filename, str(json_err))) ]) else: matches = [create_match_yaml_parser_error(err, filename)] except YAMLError as err: matches = [create_match_file_error(filename, err)] if not isinstance(template, dict) and not matches: # Template isn't a dict which means nearly nothing will work matches = [ Match(1, 1, 1, 1, filename, ParseError(), message='Template needs to be an object.') ] return (template, matches)
def print_matches(self, matches, rules=None, filenames=None): """Output all the matches""" if not rules: rules = RulesCollection() # These "base" rules are not passed into formatters rules.extend([ParseError(), TransformError(), RuleError()]) results = [] for match in matches: results.append( sarif.Result( rule_id=match.rule.id, message=sarif.Message(text=match.message), level=self._to_sarif_level(match.rule.severity), locations=[ sarif.Location( physical_location=sarif.PhysicalLocation( artifact_location=sarif.ArtifactLocation( uri=match.filename, uri_base_id=self.uri_base_id, ), region=sarif.Region( start_column=match.columnnumber, start_line=match.linenumber, end_column=match.columnnumberend, end_line=match.linenumberend, ), )) ], )) # Output only the rules that have matches matched_rules = set(r.rule_id for r in results) rules_map = {r.id: r for r in list(rules)} rules = [ sarif.ReportingDescriptor( id=rule_id, short_description=sarif.MultiformatMessageString( text=rules_map[rule_id].shortdesc), full_description=sarif.MultiformatMessageString( text=rules_map[rule_id].description), help_uri=rules_map[rule_id].source_url if rules_map[rule_id] else None) for rule_id in matched_rules ] run = sarif.Run( tool=sarif.Tool(driver=sarif.ToolComponent( name='cfn-lint', short_description=sarif.MultiformatMessageString( text=('Validates AWS CloudFormation templates against' ' the resource specification and additional' ' checks.')), information_uri= 'https://github.com/aws-cloudformation/cfn-lint', rules=rules, version=cfnlint.version.__version__, ), ), original_uri_base_ids={ self.uri_base_id: sarif.ArtifactLocation( description=sarif.MultiformatMessageString( 'The directory in which cfn-lint was run.')) }, results=results, ) log = sarif.SarifLog(version=self.version, schema_uri=self.schema, runs=[run]) # IMPORTANT: 'warning' is the default level in SARIF and will be # stripped by serialization. return to_json(log)