Skip to content
Snippets Groups Projects
Forked from Eclipse Projects / Oniro Core / Oniro
458 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
cve-report.py 5.14 KiB
# SPDX-FileCopyrightText: Huawei Inc.
#
# SPDX-License-Identifier: Apache-2.0

# CVE-check example script
# Reporting based on the cve-check JSON format: conversion to CSV and summary

import sys
import getopt

infile = "in.json"
outfile = "out.csv"
show_all = False
show_summary = False
to_csv = False


def show_syntax_and_exit(code):
    """
    Show the program syntax and exit with an errror
    Arguments:
        code: the error code to return
    """
    print("Syntax: %s [-h] [-a] [-s] [-c] [-i inputfile][-o outputfile]" % sys.argv[0])
    print("Default files: in.json and out.csv")
    print(
        "Use -c or --to-csv to generate a CSV report, output file is then needed, out.csv by default"
    )
    print("Use -a or --all to list all issues, otherwise we filter only unpatched ones")
    print("Use -s or --summary to show a summary of the issues")
    sys.exit(code)


def exit_error(code, message):
    """
    Show the error message and exit with an errror
    Arguments:
        code: the error code to return
        message: the message to show
    """
    print("Error: %s" % message)
    sys.exit(code)


def parse_args(argv):
    """
    Parse the program arguments, put options in global variables
    Arguments:
        argv: program arguments
    """
    global infile, outfile, show_all, show_summary, to_csv
    try:
        opts, args = getopt.getopt(
            argv, "hi:o:asc", ["help", "input", "output", "summary", "to-csv"]
        )
    except getopt.GetoptError:
        show_syntax_and_exit(1)
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            show_syntax_and_exit(0)
        elif opt in ("-a", "--all"):
            show_all = True
        elif opt in ("-i", "--input"):
            infile = arg
        elif opt in ("-c", "--to-csv"):
            to_csv = True
        elif opt in ("-o", "--output"):
            outfile = arg
        elif opt in ("-s", "--summary"):
            show_summary = True


def load_json(filename):
    """
    Load the JSON file, return the resulting dictionary
    Arguments:
        filename: the file to open
    Returns:
        Parsed file as a dictionary
    """
    import json

    out = {}
    try:
        with open(filename, "r") as f:
            out = json.load(f)
    except FileNotFoundError:
        exit_error(1, "Input file (%s) not found" % (filename))
    except json.decoder.JSONDecodeError as error:
        exit_error(1, "Malformed JSON file: %s" % str(error))
    return out


def process_data(filename, data, unpatched_only, do_summary, do_csv):
    """
    Write the resulting CSV with one line for each package
    Arguments:
        filename: the file to write to
        data: dictionary from parsing the JSON file
        unpatched_only: True if we want only unpatched issues, False otherwise
    Returns:
        Parsed file as a dictionary
    """
    if not "version" in data or data["version"] != "1":
        exit_error(1, "Unrecognized format version number")
    if not "package" in data:
        exit_error(1, "Mandatory 'package' key not found")

    lines = ""
    total_issue_count = 0
    for package in data["package"]:
        keys_in_package = {"name", "layer", "version", "issue"}
        if keys_in_package - package.keys():
            exit_error(
                1,
                "Missing a mandatory key in package: %s"
                % (keys_in_package - package.keys()),
            )

        package_name = package["name"]
        layer = package["layer"]
        package_version = package["version"]
        package_summary = "Issues for package %s (version %s):\n\t" % (
            package_name,
            package_version,
        )
        issue_count = 0

        for issue in package["issue"]:
            keys_in_issue = {"id", "scorev2", "scorev3", "vector", "status"}
            if keys_in_issue - issue.keys():
                exit_error(
                    1,
                    "Missing mandatory keys %s in 'issue' for the package '%s'"
                    % (keys_in_issue - issue.keys(), package_name),
                )

            cve_id = issue["id"]
            scorev2 = issue["scorev2"]
            scorev3 = issue["scorev3"]
            vector = issue["vector"]
            status = issue["status"]
            if (unpatched_only == False) or (status == "Unpatched"):
                lines += "%s;%s;%s;%s;%s;%s;%s\n" % (
                    layer,
                    package_name,
                    package_version,
                    cve_id,
                    scorev2,
                    scorev3,
                    vector,
                )
                package_summary += "%s " % (cve_id)
                issue_count += 1

        if do_summary and issue_count > 0:
            package_summary += "\n\tCount: %d\n" % (issue_count)
            print(package_summary)

        total_issue_count += issue_count

    if do_csv:
        with open(filename, "w") as f:
            f.write(lines)

    if do_summary:
        print("Global issue count: %d" % (total_issue_count))


def main(argv):
    parse_args(argv)
    data = load_json(infile)
    process_data(outfile, data, not show_all, show_summary, to_csv)


if __name__ == "__main__":
    main(sys.argv[1:])