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