From: Ross Burton Date: Tue, 31 Mar 2026 13:24:27 +0000 (+0100) Subject: classes/vex: remove X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da11f8cd740a0b4dfbbdf8aba52a5da7a7ca7a87;p=thirdparty%2Fopenembedded%2Fopenembedded-core.git classes/vex: remove This class existed as a provider of information for external CVE tooling, and uses a non-standard format that is OpenEmbedded-specific[1]. However, the SPDX 3 output can contain all of this needed information, in a format that is standardised. I'm unaware of any active users of this class beyond sbom-cve-check, which can also read the data from the SPDX if SPDX_INCLUDE_VEX has been set. So that we don't have to maintain this class for the lifetime of the Wrynose LTS, delete it. [1] oe-core 6352ad93a72 ("vex.bbclass: add a new class") Signed-off-by: Ross Burton Signed-off-by: Mathieu Dubois-Briand Signed-off-by: Richard Purdie --- diff --git a/meta/classes/vex.bbclass b/meta/classes/vex.bbclass deleted file mode 100644 index c57b8209c2..0000000000 --- a/meta/classes/vex.bbclass +++ /dev/null @@ -1,303 +0,0 @@ -# -# Copyright OpenEmbedded Contributors -# -# SPDX-License-Identifier: MIT -# - -# This class is used to generate metadata needed by external -# tools to check for vulnerabilities, for example CVEs. -# -# In order to use this class just inherit the class in the -# local.conf file and it will add the generate_vex task for -# every recipe. If an image is build it will generate a report -# in DEPLOY_DIR_IMAGE for all the packages used, it will also -# generate a file for all recipes used in the build. -# -# Variables use CVE_CHECK prefix to keep compatibility with -# the cve-check class -# -# Example: -# bitbake -c generate_vex openssl -# bitbake core-image-sato -# bitbake -k -c generate_vex universe -# -# The product name that the CVE database uses defaults to BPN, but may need to -# be overriden per recipe (for example tiff.bb sets CVE_PRODUCT=libtiff). -CVE_PRODUCT ??= "${BPN}" -CVE_VERSION ??= "${PV}" - -CVE_CHECK_SUMMARY_DIR ?= "${LOG_DIR}/cve" - -CVE_CHECK_SUMMARY_FILE_NAME_JSON = "cve-summary.json" -CVE_CHECK_SUMMARY_INDEX_PATH = "${CVE_CHECK_SUMMARY_DIR}/cve-summary-index.txt" - -CVE_CHECK_DIR ??= "${DEPLOY_DIR}/cve" -CVE_CHECK_RECIPE_FILE_JSON ?= "${CVE_CHECK_DIR}/${PN}_cve.json" -CVE_CHECK_MANIFEST_JSON ?= "${IMGDEPLOYDIR}/${IMAGE_NAME}.vex.json" - -# Skip CVE Check for packages (PN) -CVE_CHECK_SKIP_RECIPE ?= "" - -# Replace NVD DB check status for a given CVE. Each of CVE has to be mentioned -# separately with optional detail and description for this status. -# -# CVE_STATUS[CVE-1234-0001] = "not-applicable-platform: Issue only applies on Windows" -# CVE_STATUS[CVE-1234-0002] = "fixed-version: Fixed externally" -# -# Settings the same status and reason for multiple CVEs is possible -# via CVE_STATUS_GROUPS variable. -# -# CVE_STATUS_GROUPS = "CVE_STATUS_WIN CVE_STATUS_PATCHED" -# -# CVE_STATUS_WIN = "CVE-1234-0001 CVE-1234-0003" -# CVE_STATUS_WIN[status] = "not-applicable-platform: Issue only applies on Windows" -# CVE_STATUS_PATCHED = "CVE-1234-0002 CVE-1234-0004" -# CVE_STATUS_PATCHED[status] = "fixed-version: Fixed externally" -# -# All possible CVE statuses could be found in cve-check-map.conf -# CVE_CHECK_STATUSMAP[not-applicable-platform] = "Ignored" -# CVE_CHECK_STATUSMAP[fixed-version] = "Patched" -# -# CVE_CHECK_IGNORE is deprecated and CVE_STATUS has to be used instead. -# Keep CVE_CHECK_IGNORE until other layers migrate to new variables -CVE_CHECK_IGNORE ?= "" - -# Layers to be excluded -CVE_CHECK_LAYER_EXCLUDELIST ??= "" - -# Layers to be included -CVE_CHECK_LAYER_INCLUDELIST ??= "" - - -# set to "alphabetical" for version using single alphabetical character as increment release -CVE_VERSION_SUFFIX ??= "" - -python () { - if bb.data.inherits_class("cve-check", d): - raise bb.parse.SkipRecipe("Skipping recipe: found incompatible combination of cve-check and vex enabled at the same time.") - - from oe.cve_check import extend_cve_status - extend_cve_status(d) -} - -def generate_json_report(d, out_path, link_path): - if os.path.exists(d.getVar("CVE_CHECK_SUMMARY_INDEX_PATH")): - import json - from oe.cve_check import cve_check_merge_jsons, update_symlinks - - bb.note("Generating JSON CVE summary") - index_file = d.getVar("CVE_CHECK_SUMMARY_INDEX_PATH") - summary = {"version":"1", "package": []} - with open(index_file) as f: - filename = f.readline() - while filename: - with open(filename.rstrip()) as j: - data = json.load(j) - cve_check_merge_jsons(summary, data) - filename = f.readline() - - summary["package"].sort(key=lambda d: d['name']) - - with open(out_path, "w") as f: - json.dump(summary, f, indent=2) - - update_symlinks(out_path, link_path) - -python vex_save_summary_handler () { - import shutil - import datetime - from oe.cve_check import update_symlinks - - cvelogpath = d.getVar("CVE_CHECK_SUMMARY_DIR") - - bb.utils.mkdirhier(cvelogpath) - timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S') - - json_summary_link_name = os.path.join(cvelogpath, d.getVar("CVE_CHECK_SUMMARY_FILE_NAME_JSON")) - json_summary_name = os.path.join(cvelogpath, "cve-summary-%s.json" % (timestamp)) - generate_json_report(d, json_summary_name, json_summary_link_name) - bb.plain("Complete CVE JSON report summary created at: %s" % json_summary_link_name) -} - -addhandler vex_save_summary_handler -vex_save_summary_handler[eventmask] = "bb.event.BuildCompleted" - -python do_generate_vex () { - """ - Generate metadata needed for vulnerability checking for - the current recipe - """ - from oe.cve_check import get_patched_cves - - try: - patched_cves = get_patched_cves(d) - cves_status = [] - products = d.getVar("CVE_PRODUCT").split() - for product in products: - if ":" in product: - _, product = product.split(":", 1) - cves_status.append([product, False]) - - except FileNotFoundError: - bb.fatal("Failure in searching patches") - - cve_write_data_json(d, patched_cves, cves_status) -} - -addtask generate_vex before do_build - -python vex_cleanup () { - """ - Delete the file used to gather all the CVE information. - """ - bb.utils.remove(e.data.getVar("CVE_CHECK_SUMMARY_INDEX_PATH")) -} - -addhandler vex_cleanup -vex_cleanup[eventmask] = "bb.event.BuildCompleted" - -python vex_write_rootfs_manifest () { - """ - Create VEX/CVE manifest when building an image - """ - - import json - from oe.rootfs import image_list_installed_packages - from oe.cve_check import cve_check_merge_jsons, update_symlinks - - deploy_file_json = d.getVar("CVE_CHECK_RECIPE_FILE_JSON") - if os.path.exists(deploy_file_json): - bb.utils.remove(deploy_file_json) - - # Create a list of relevant recipies - recipies = set() - for pkg in list(image_list_installed_packages(d)): - pkg_info = os.path.join(d.getVar('PKGDATA_DIR'), - 'runtime-reverse', pkg) - pkg_data = oe.packagedata.read_pkgdatafile(pkg_info) - recipies.add(pkg_data["PN"]) - - bb.note("Writing rootfs VEX manifest") - deploy_dir = d.getVar("IMGDEPLOYDIR") - link_name = d.getVar("IMAGE_LINK_NAME") - - json_data = {"version":"1", "package": []} - text_data = "" - - save_pn = d.getVar("PN") - - for pkg in recipies: - # To be able to use the CVE_CHECK_RECIPE_FILE_JSON variable we have to evaluate - # it with the different PN names set each time. - d.setVar("PN", pkg) - - pkgfilepath = d.getVar("CVE_CHECK_RECIPE_FILE_JSON") - if os.path.exists(pkgfilepath): - with open(pkgfilepath) as j: - data = json.load(j) - cve_check_merge_jsons(json_data, data) - else: - bb.warn("Missing cve file for %s" % pkg) - - d.setVar("PN", save_pn) - - link_path = os.path.join(deploy_dir, "%s.vex.json" % link_name) - manifest_name = d.getVar("CVE_CHECK_MANIFEST_JSON") - - with open(manifest_name, "w") as f: - json.dump(json_data, f, indent=2) - - update_symlinks(manifest_name, link_path) - bb.plain("Image VEX JSON report stored in: %s" % manifest_name) -} - -ROOTFS_POSTPROCESS_COMMAND:prepend = "vex_write_rootfs_manifest; " -do_rootfs[recrdeptask] += "do_generate_vex " -do_populate_sdk[recrdeptask] += "do_generate_vex " - -def cve_write_data_json(d, cve_data, cve_status): - """ - Prepare CVE data for the JSON format, then write it. - Done for each recipe. - """ - - from oe.cve_check import get_cpe_ids - import json - - output = {"version":"1", "package": []} - nvd_link = "https://nvd.nist.gov/vuln/detail/" - - fdir_name = d.getVar("FILE_DIRNAME") - layer = fdir_name.split("/")[-3] - - include_layers = d.getVar("CVE_CHECK_LAYER_INCLUDELIST").split() - exclude_layers = d.getVar("CVE_CHECK_LAYER_EXCLUDELIST").split() - - if exclude_layers and layer in exclude_layers: - return - - if include_layers and layer not in include_layers: - return - - product_data = [] - for s in cve_status: - p = {"product": s[0], "cvesInRecord": "Yes"} - if s[1] == False: - p["cvesInRecord"] = "No" - product_data.append(p) - product_data = list({p['product']:p for p in product_data}.values()) - - package_version = "%s%s" % (d.getVar("EXTENDPE"), d.getVar("PV")) - cpes = get_cpe_ids(d.getVar("CVE_PRODUCT"), d.getVar("CVE_VERSION")) - package_data = { - "name" : d.getVar("PN"), - "layer" : layer, - "version" : package_version, - "products": product_data, - "cpes": cpes - } - - cve_list = [] - - for cve in sorted(cve_data): - issue_link = "%s%s" % (nvd_link, cve) - - cve_item = { - "id" : cve, - "status" : cve_data[cve]["abbrev-status"], - "link": issue_link, - } - if 'NVD-summary' in cve_data[cve]: - cve_item["summary"] = cve_data[cve]["NVD-summary"] - cve_item["scorev2"] = cve_data[cve]["NVD-scorev2"] - cve_item["scorev3"] = cve_data[cve]["NVD-scorev3"] - cve_item["scorev4"] = cve_data[cve]["NVD-scorev4"] - cve_item["vector"] = cve_data[cve]["NVD-vector"] - cve_item["vectorString"] = cve_data[cve]["NVD-vectorString"] - if 'status' in cve_data[cve]: - cve_item["detail"] = cve_data[cve]["status"] - if 'justification' in cve_data[cve]: - cve_item["description"] = cve_data[cve]["justification"] - if 'resource' in cve_data[cve]: - cve_item["patch-file"] = cve_data[cve]["resource"] - cve_list.append(cve_item) - - package_data["issue"] = cve_list - output["package"].append(package_data) - - deploy_file = d.getVar("CVE_CHECK_RECIPE_FILE_JSON") - - write_string = json.dumps(output, indent=2) - - cvelogpath = d.getVar("CVE_CHECK_SUMMARY_DIR") - index_path = d.getVar("CVE_CHECK_SUMMARY_INDEX_PATH") - bb.utils.mkdirhier(cvelogpath) - bb.utils.mkdirhier(os.path.dirname(deploy_file)) - fragment_file = os.path.basename(deploy_file) - fragment_path = os.path.join(cvelogpath, fragment_file) - with open(fragment_path, "w") as f: - f.write(write_string) - with open(deploy_file, "w") as f: - f.write(write_string) - with open(index_path, "a+") as f: - f.write("%s\n" % fragment_path)