--- /dev/null
+# SPDX-License-Identifier: MIT
+
+# It is recommended to enable this class through the sbom-cve-check fragment:
+# bitbake-config-build enable-fragment core/yocto/sbom-cve-check
+#
+# Or it is possible to add this line in local.conf:
+# OE_FRAGMENTS += "core/yocto/sbom-cve-check"
+
+require recipes-devtools/sbom-cve-check/sbom-cve-check-config.inc
+
+SBOM_CVE_CHECK_DEPLOYDIR = "${WORKDIR}/sbom-cve-check/image-deploy"
+
+SBOM_CVE_CHECK_EXTRA_ARGS[doc] = "Allow to specify extra arguments to sbom-cve-check. \
+ For example to add export flags for filtering (e.g., only export vulnerable CVEs). \
+"
+SBOM_CVE_CHECK_EXTRA_ARGS ??= ""
+
+SBOM_CVE_CHECK_EXPORT_VARS[doc] = "List of variables that declare export files to generate. \
+ Each variable must have a 'type' and an 'ext' flag set. \
+ The 'type' flag contains the value that is passed to the --export-type command flags. \
+ The 'ext' flag contains the filename extension (suffix). The output filename is going \
+ to be ${IMAGE_NAME}${ext} \
+"
+SBOM_CVE_CHECK_EXPORT_VARS ?= "SBOM_CVE_CHECK_EXPORT_SPDX3 SBOM_CVE_CHECK_EXPORT_CVECHECK"
+
+SBOM_CVE_CHECK_EXPORT_SPDX3[doc] = "Export configuration to generate an SPDX3 SBOM file, \
+ with the following name: ${IMAGE_NAME}.sbom-cve-check.spdx.json \
+"
+SBOM_CVE_CHECK_EXPORT_SPDX3[type] ?= "spdx3"
+SBOM_CVE_CHECK_EXPORT_SPDX3[ext] ?= ".sbom-cve-check.spdx.json"
+
+SBOM_CVE_CHECK_EXPORT_CVECHECK[doc] = "Export configuration to generate a JSON manifest \
+ in the same format as the cve-check class, with the following name: \
+ ${IMAGE_NAME}.sbom-cve-check.json \
+"
+SBOM_CVE_CHECK_EXPORT_CVECHECK[type] ?= "yocto-cve-check-manifest"
+SBOM_CVE_CHECK_EXPORT_CVECHECK[ext] ?= ".sbom-cve-check.yocto.json"
+
+python do_sbom_cve_check() {
+ """
+ Task: Run sbom-cve-check analysis on SBOM.
+ """
+ import os
+ import bb
+ from oe.cve_check import update_symlinks
+
+ if not bb.data.inherits_class("create-spdx-3.0", d):
+ bb.fatal("Cannot execute sbom-cve-check missing create-spdx-3.0 inherit.")
+
+ sbom_path = d.expand("${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.spdx.json")
+ vex_manifest_path = d.expand("${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.vex.json")
+ dl_db_dir = d.getVar("SBOM_CVE_CHECK_DEPLOY_DB_DIR")
+ deploy_dir = d.getVar("SBOM_CVE_CHECK_DEPLOYDIR")
+ img_link_name = d.getVar("IMAGE_LINK_NAME")
+ img_name = d.getVar("IMAGE_NAME")
+
+ export_files = []
+ for export_var in d.getVar("SBOM_CVE_CHECK_EXPORT_VARS").split():
+ export_ext = d.getVarFlag(export_var, "ext")
+ export_path = f"{deploy_dir}/{img_name}{export_ext}"
+ export_link = f"{deploy_dir}/{img_link_name}{export_ext}"
+ export_type = d.getVarFlag(export_var, "type")
+ export_files.append((export_type, export_path, export_link))
+
+ cmd_env = os.environ.copy()
+ cmd_env["SBOM_CVE_CHECK_DATABASES_DIR"] = dl_db_dir
+
+ cmd_args = [
+ d.expand("${STAGING_BINDIR_NATIVE}/sbom-cve-check"),
+ "--sbom-path",
+ sbom_path,
+ "--disable-auto-updates"
+ ]
+
+ # Assume that SPDX_INCLUDE_VEX is set globally to "all", and not only for the
+ # image recipe, which is very unlikely. This is not an issue to include the
+ # VEX manifest even if not needed.
+ if bb.data.inherits_class("vex", d) and d.getVar("SPDX_INCLUDE_VEX") != "all":
+ cmd_args.extend(["--yocto-vex-manifest", vex_manifest_path])
+
+ for export_file in export_files:
+ cmd_args.extend(
+ ["--export-type", export_file[0], "--export-path", export_file[1]]
+ )
+
+ cmd_args.extend(d.getVar("SBOM_CVE_CHECK_EXTRA_ARGS").split())
+
+ try:
+ bb.note("Running: {}".format(" ".join(cmd_args)))
+ bb.process.run(cmd_args, env=cmd_env)
+ except bb.process.ExecutionError as e:
+ bb.error(f"sbom-cve-check failed: {e}")
+ return
+
+ for export_file in export_files:
+ bb.note(f"sbom-cve-check exported: {export_file[1]}")
+ update_symlinks(export_file[1], export_file[2])
+}
+
+addtask do_sbom_cve_check after do_create_image_sbom_spdx before do_build
+
+SSTATETASKS += "do_sbom_cve_check"
+do_sbom_cve_check[cleandirs] = "${SBOM_CVE_CHECK_DEPLOYDIR}"
+do_sbom_cve_check[sstate-inputdirs] = "${SBOM_CVE_CHECK_DEPLOYDIR}"
+do_sbom_cve_check[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
+do_sbom_cve_check[depends] += " \
+ python3-sbom-cve-check-native:do_populate_sysroot \
+ sbom-cve-check-update-cvelist-native:do_unpack \
+ sbom-cve-check-update-nvd-native:do_unpack \
+"
+
+python do_sbom_cve_check_setscene() {
+ sstate_setscene(d)
+}
+addtask do_sbom_cve_check_setscene