new file mode 100755
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+#
+# Compare two CVE reports and output a formatted rST CVE array (for release
+# notes).
+#
+# We consider that a CVE is "fixed" if either:
+# - the CVE status changes from Unpatched to Patched in the new report.
+# - the Unpatched CVE is unlisted in the new report.
+#
+# Reports can be found here: https://valkyrie.yocto.io/pub/non-release/?type=metrics
+
+import sys
+import json
+
+json_prev_path = sys.argv[1]
+json_next_path = sys.argv[2]
+
+data_prev, data_next = None, None
+
+with open(json_prev_path, 'r') as fd_prev, open(json_prev_path, 'r') as fd_next:
+ data_prev = json.load(fd_prev)["package"]
+ data_next = json.load(fd_next)["package"]
+
+patched_cves = {}
+
+for pkg_prev in data_prev:
+ pkg_name = pkg_prev["name"]
+
+ pkg_next = None
+ for p in data_next:
+ if p["name"] == pkg_name:
+ pkg_next = p
+ break
+
+ if pkg_next is not None:
+ prev_unpatched = [cve["id"] for cve in pkg_prev["issue"] if cve["status"] == "Unpatched"]
+ # next_patched = set([cve["id"] for cve in pkg_next["issue"] if cve["status"] == "Patched"])
+ pkg_patched_cves = []
+ for cve in prev_unpatched:
+ if cve in pkg_next["issue"] and pkg_next["issue"][cve]["status"] == "Patched":
+ pkg_patched_cves.append(cve)
+ if cve not in pkg_next["issue"]:
+ pkg_patched_cves.append(cve)
+
+ if pkg_patched_cves:
+ patched_cves[pkg_name] = sorted(pkg_patched_cves, key=lambda cve: (int(cve.split('-')[1]), int(cve.split('-')[2])))
+
+if not patched_cves:
+ print("No patched CVEs found")
+ exit(0)
+
+# Remove -native duplicates
+for pkg in list(patched_cves):
+ if pkg.endswith("-native") and pkg[:-len("-native")] in patched_cves:
+ patched_cves.pop(pkg)
+
+print(""".. list-table::
+ :widths: 30 70
+ :header-rows: 1
+
+ * - Recipe
+ - CVE IDs""")
+
+for pkg in sorted(patched_cves.keys()):
+ cves_rst = ", ".join([f":cve_nist:`{c[4:]}`" for c in patched_cves[pkg]])
+ print(f" * - ``{pkg}``")
+ print(f" - {cves_rst}")
The gen-cve-release-notes can be used to compare two cve-check reports and generate a list of "patched" CVEs, and output that in a rST table format. By "patched", it means that it meets one of the following condition: - the CVE status changes from Unpatched to Patched in the new report. - the Unpatched CVE is unlisted in the new report. Signed-off-by: Antonin Godard <antonin.godard@bootlin.com> --- documentation/tools/gen-cve-release-notes | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)