Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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)
Beispiel #5
0
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, [])
Beispiel #6
0
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)
Beispiel #7
0
    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)