xref: /openbmc/openbmc/poky/scripts/cve-json-to-text.py (revision c9537f57ab488bf5d90132917b0184e2527970a5)
1#!/bin/env python3
2# SPDX-FileCopyrightText: OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5
6# CVE results conversion script: JSON format to text
7# Derived from cve-report.py from Oniro (MIT, by Huawei Inc)
8
9import sys
10import getopt
11
12infile = "in.json"
13outfile = "out.txt"
14
15
16def show_syntax_and_exit(code):
17    """
18    Show the program syntax and exit with an errror
19    Arguments:
20        code: the error code to return
21    """
22    print("Syntax: %s [-h] [-i inputJSONfile][-o outputfile]" % sys.argv[0])
23    sys.exit(code)
24
25
26def exit_error(code, message):
27    """
28    Show the error message and exit with an errror
29    Arguments:
30        code: the error code to return
31        message: the message to show
32    """
33    print("Error: %s" % message)
34    sys.exit(code)
35
36
37def parse_args(argv):
38    """
39    Parse the program arguments, put options in global variables
40    Arguments:
41        argv: program arguments
42    """
43    global infile, outfile
44    try:
45        opts, args = getopt.getopt(
46            argv, "hi:o:", ["help", "input", "output"]
47        )
48    except getopt.GetoptError:
49        show_syntax_and_exit(1)
50    for opt, arg in opts:
51        if opt in ("-h"):
52            show_syntax_and_exit(0)
53        elif opt in ("-i"):
54            infile = arg
55        elif opt in ("-o"):
56            outfile = arg
57
58def load_json(filename):
59    """
60    Load the JSON file, return the resulting dictionary
61    Arguments:
62        filename: the file to open
63    Returns:
64        Parsed file as a dictionary
65    """
66    import json
67
68    out = {}
69    try:
70        with open(filename, "r") as f:
71            out = json.load(f)
72    except FileNotFoundError:
73        exit_error(1, "Input file (%s) not found" % (filename))
74    except json.decoder.JSONDecodeError as error:
75        exit_error(1, "Malformed JSON file: %s" % str(error))
76    return out
77
78
79def process_data(filename, data):
80    """
81    Write the resulting CSV with one line for each package
82    Arguments:
83        filename: the file to write to
84        data: dictionary from parsing the JSON file
85    Returns:
86        None
87    """
88    if not "version" in data or data["version"] != "1":
89        exit_error(1, "Unrecognized format version number")
90    if not "package" in data:
91        exit_error(1, "Mandatory 'package' key not found")
92
93    lines = ""
94    total_issue_count = 0
95    for package in data["package"]:
96        package_info = ""
97        keys_in_package = {"name", "layer", "version", "issue"}
98        if keys_in_package - package.keys():
99            exit_error(
100                1,
101                "Missing a mandatory key in package: %s"
102                % (keys_in_package - package.keys()),
103            )
104
105        package_info += "LAYER: %s\n" % package["layer"]
106        package_info += "PACKAGE NAME: %s\n" % package["name"]
107        package_info += "PACKAGE VERSION: %s\n" % package["version"]
108
109        for issue in package["issue"]:
110            keys_in_issue = {"id", "status", "detail"}
111            if keys_in_issue - issue.keys():
112                print("Warning: Missing keys %s in 'issue' for the package '%s'"
113                    % (keys_in_issue - issue.keys(), package["name"]))
114
115            lines += package_info
116            lines += "CVE: %s\n" % issue["id"]
117            lines += "CVE STATUS: %s\n" % issue["status"]
118            lines += "CVE DETAIL: %s\n" % issue["detail"]
119            if "description" in issue:
120                lines += "CVE DESCRIPTION: %s\n" % issue["description"]
121            if "summary" in issue:
122                lines += "CVE SUMMARY: %s\n" % issue["summary"]
123            if "scorev2" in issue:
124                lines += "CVSS v2 BASE SCORE: %s\n" % issue["scorev2"]
125            if "scorev3" in issue:
126                lines += "CVSS v3 BASE SCORE: %s\n" % issue["scorev3"]
127            if "scorev4" in issue:
128                lines += "CVSS v4 BASE SCORE: %s\n" % issue["scorev4"]
129            if "vector" in issue:
130                lines += "VECTOR: %s\n" % issue["vector"]
131            if "vectorString" in issue:
132                lines += "VECTORSTRING: %s\n" % issue["vectorString"]
133            lines += "MORE INFORMATION: https://nvd.nist.gov/vuln/detail/%s\n" % issue["id"]
134            lines += "\n"
135
136    with open(filename, "w") as f:
137        f.write(lines)
138
139def main(argv):
140    parse_args(argv)
141    data = load_json(infile)
142    process_data(outfile, data)
143
144
145if __name__ == "__main__":
146    main(sys.argv[1:])
147