diff mbox series

[1/3] classes/vex: remove

Message ID 20260331132430.781647-1-ross.burton@arm.com
State Under Review
Headers show
Series [1/3] classes/vex: remove | expand

Commit Message

Ross Burton March 31, 2026, 1:24 p.m. UTC
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 <ross.burton@arm.com>
---
 meta/classes/vex.bbclass | 303 ---------------------------------------
 1 file changed, 303 deletions(-)
 delete mode 100644 meta/classes/vex.bbclass

Comments

Marta Rybczynska March 31, 2026, 2:43 p.m. UTC | #1
On Tue, Mar 31, 2026 at 3:24 PM Ross Burton via lists.openembedded.org
<ross.burton=arm.com@lists.openembedded.org> wrote:

> 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")
>
>
For the record, I do not agree with this removal. SPDX3 has still not
reached mature usage outside of the LF ecosystem.

Kind regards,
Marta
Ross Burton March 31, 2026, 3:04 p.m. UTC | #2
On 31 Mar 2026, at 15:43, Marta Rybczynska via lists.openembedded.org <rybczynska=gmail.com@lists.openembedded.org> wrote:
> For the record, I do not agree with this removal. SPDX3 has still not reached mature usage outside of the LF ecosystem.

Is there an ecosystem of tooling that uses the Yocto-specific JSON format that vex.bbclass generates?

Ross
Marta Rybczynska March 31, 2026, 3:13 p.m. UTC | #3
On Tue, Mar 31, 2026 at 5:05 PM Ross Burton <Ross.Burton@arm.com> wrote:

> On 31 Mar 2026, at 15:43, Marta Rybczynska via lists.openembedded.org
> <rybczynska=gmail.com@lists.openembedded.org> wrote:
> > For the record, I do not agree with this removal. SPDX3 has still not
> reached mature usage outside of the LF ecosystem.
>
> Is there an ecosystem of tooling that uses the Yocto-specific JSON format
> that vex.bbclass generates?


Yes there are tools that support YP cve-check JSON format as input and, by
extension, they can use the vex.bbclass too.

Not sure how many of them want to manifest, this is usually internal
tooling.

Kind regards,
Marta
Ross Burton March 31, 2026, 3:19 p.m. UTC | #4
On 31 Mar 2026, at 16:13, Marta Rybczynska <rybczynska@gmail.com> wrote:
> On Tue, Mar 31, 2026 at 5:05 PM Ross Burton <Ross.Burton@arm.com> wrote:
> On 31 Mar 2026, at 15:43, Marta Rybczynska via lists.openembedded.org <rybczynska=gmail.com@lists.openembedded.org> wrote:
> > For the record, I do not agree with this removal. SPDX3 has still not reached mature usage outside of the LF ecosystem.
> 
> Is there an ecosystem of tooling that uses the Yocto-specific JSON format that vex.bbclass generates?
> 
> Yes there are tools that support YP cve-check JSON format as input and, by extension, they can use the vex.bbclass too.
> 
> Not sure how many of them want to manifest, this is usually internal tooling.

IMHO, if these users don’t want to move to SPDX, then they can copy the vex.bbclass from current master into their distro.

Ross
Daniel Turull April 1, 2026, 12:29 p.m. UTC | #5
Hi,

The kernel scripts to check CVEs uses the vex output as input.
https://git.openembedded.org/openembedded-core/tree/scripts/contrib/improve_kernel_cve_report.py

Daniel

From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> On Behalf Of Marta Rybczynska via lists.openembedded.org
Sent: Tuesday, 31 March 2026 16:43
To: ross.burton@arm.com
Cc: openembedded-core@lists.openembedded.org
Subject: Re: [OE-core] [PATCH 1/3] classes/vex: remove



On Tue, Mar 31, 2026 at 3:24 PM Ross Burton via lists.openembedded.org<http://lists.openembedded.org/> <ross.burton=arm.com@lists.openembedded.org<mailto:arm.com@lists.openembedded.org>> wrote:
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")

For the record, I do not agree with this removal. SPDX3 has still not reached mature usage outside of the LF ecosystem.

Kind regards,
Marta
diff mbox series

Patch

diff --git a/meta/classes/vex.bbclass b/meta/classes/vex.bbclass
deleted file mode 100644
index c57b8209c23..00000000000
--- 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)