public inbox for openembedded-core@lists.openembedded.org
 help / color / mirror / Atom feed
From: Joshua Watt <jpewhacker@gmail.com>
To: openembedded-core@lists.openembedded.org
Cc: Joshua Watt <JPEWhacker@gmail.com>
Subject: [OE-core][PATCH v5 06/13] spdx30: Include patch file information in VEX
Date: Wed,  4 Mar 2026 09:44:17 -0700	[thread overview]
Message-ID: <20260304164835.3072507-7-JPEWhacker@gmail.com> (raw)
In-Reply-To: <20260304164835.3072507-1-JPEWhacker@gmail.com>

Modifies the SPDX VEX output to include the patches that fix a
particular vulnerability. This is done by adding a `patchedBy`
relationship from the `VexFixedVulnAssessmentRelationship` to the `File`
that provides the fix.

If the file can be located without fetching (e.g. is a file:// in
SRC_URI), the checksum will be included.

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
---
 meta/lib/oe/sbom30.py       | 60 ++++++++++++++-------------
 meta/lib/oe/spdx30_tasks.py | 81 ++++++++++++++++++++++++++++---------
 2 files changed, 92 insertions(+), 49 deletions(-)

diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py
index 50a72fce39..21f084dc16 100644
--- a/meta/lib/oe/sbom30.py
+++ b/meta/lib/oe/sbom30.py
@@ -620,37 +620,38 @@ class ObjectSet(oe.spdx30.SHACLObjectSet):
         )
         spdx_file.extension.append(OELicenseScannedExtension())
 
-    def new_file(self, _id, name, path, *, purposes=[]):
-        sha256_hash = bb.utils.sha256_file(path)
+    def new_file(self, _id, name, path, *, purposes=[], hashfile=True):
+        if hashfile:
+            sha256_hash = bb.utils.sha256_file(path)
 
-        for f in self.by_sha256_hash.get(sha256_hash, []):
-            if not isinstance(f, oe.spdx30.software_File):
-                continue
+            for f in self.by_sha256_hash.get(sha256_hash, []):
+                if not isinstance(f, oe.spdx30.software_File):
+                    continue
 
-            if purposes:
-                new_primary = purposes[0]
-                new_additional = []
+                if purposes:
+                    new_primary = purposes[0]
+                    new_additional = []
 
-                if f.software_primaryPurpose:
-                    new_additional.append(f.software_primaryPurpose)
-                new_additional.extend(f.software_additionalPurpose)
+                    if f.software_primaryPurpose:
+                        new_additional.append(f.software_primaryPurpose)
+                    new_additional.extend(f.software_additionalPurpose)
 
-                new_additional = sorted(
-                    list(set(p for p in new_additional if p != new_primary))
-                )
+                    new_additional = sorted(
+                        list(set(p for p in new_additional if p != new_primary))
+                    )
 
-                f.software_primaryPurpose = new_primary
-                f.software_additionalPurpose = new_additional
+                    f.software_primaryPurpose = new_primary
+                    f.software_additionalPurpose = new_additional
 
-            if f.name != name:
-                for e in f.extension:
-                    if isinstance(e, OEFileNameAliasExtension):
-                        e.aliases.append(name)
-                        break
-                else:
-                    f.extension.append(OEFileNameAliasExtension(aliases=[name]))
+                if f.name != name:
+                    for e in f.extension:
+                        if isinstance(e, OEFileNameAliasExtension):
+                            e.aliases.append(name)
+                            break
+                    else:
+                        f.extension.append(OEFileNameAliasExtension(aliases=[name]))
 
-            return f
+                return f
 
         spdx_file = oe.spdx30.software_File(
             _id=_id,
@@ -661,12 +662,13 @@ class ObjectSet(oe.spdx30.SHACLObjectSet):
             spdx_file.software_primaryPurpose = purposes[0]
             spdx_file.software_additionalPurpose = purposes[1:]
 
-        spdx_file.verifiedUsing.append(
-            oe.spdx30.Hash(
-                algorithm=oe.spdx30.HashAlgorithm.sha256,
-                hashValue=sha256_hash,
+        if hashfile:
+            spdx_file.verifiedUsing.append(
+                oe.spdx30.Hash(
+                    algorithm=oe.spdx30.HashAlgorithm.sha256,
+                    hashValue=sha256_hash,
+                )
             )
-        )
 
         return self.add(spdx_file)
 
diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py
index a8fffbb085..aec47d4f81 100644
--- a/meta/lib/oe/spdx30_tasks.py
+++ b/meta/lib/oe/spdx30_tasks.py
@@ -568,44 +568,63 @@ def create_recipe_spdx(d):
     if include_vex != "none":
         patched_cves = oe.cve_check.get_patched_cves(d)
         for cve, patched_cve in patched_cves.items():
-            decoded_status = {
-                "mapping": patched_cve["abbrev-status"],
-                "detail": patched_cve["status"],
-                "description": patched_cve.get("justification", None),
-            }
+            mapping = patched_cve["abbrev-status"]
+            detail = patched_cve["status"]
+            description = patched_cve.get("justification", None)
+            resources = patched_cve.get("resource", [])
 
             # If this CVE is fixed upstream, skip it unless all CVEs are
             # specified.
-            if (
-                include_vex != "all"
-                and "detail" in decoded_status
-                and decoded_status["detail"]
-                in (
-                    "fixed-version",
-                    "cpe-stable-backport",
-                )
+            if include_vex != "all" and detail in (
+                "fixed-version",
+                "cpe-stable-backport",
             ):
                 bb.debug(1, "Skipping %s since it is already fixed upstream" % cve)
                 continue
 
             spdx_cve = recipe_objset.new_cve_vuln(cve)
 
-            cve_by_status.setdefault(decoded_status["mapping"], {})[cve] = (
+            cve_by_status.setdefault(mapping, {})[cve] = (
                 spdx_cve,
-                decoded_status["detail"],
-                decoded_status["description"],
+                detail,
+                description,
+                resources,
             )
 
     all_cves = set()
     for status, cves in cve_by_status.items():
         for cve, items in cves.items():
-            spdx_cve, detail, description = items
+            spdx_cve, detail, description, resources = items
             spdx_cve_id = oe.sbom30.get_element_link_id(spdx_cve)
 
             all_cves.add(spdx_cve)
 
             if status == "Patched":
-                recipe_objset.new_vex_patched_relationship([spdx_cve_id], [recipe])
+                spdx_vex = recipe_objset.new_vex_patched_relationship(
+                    [spdx_cve_id], [recipe]
+                )
+                patches = []
+                for idx, filepath in enumerate(resources):
+                    patches.append(
+                        recipe_objset.new_file(
+                            recipe_objset.new_spdxid(
+                                "patch", str(idx), os.path.basename(filepath)
+                            ),
+                            os.path.basename(filepath),
+                            filepath,
+                            purposes=[oe.spdx30.software_SoftwarePurpose.patch],
+                            hashfile=os.path.isfile(filepath),
+                        )
+                    )
+
+                if patches:
+                    recipe_objset.new_scoped_relationship(
+                        spdx_vex,
+                        oe.spdx30.RelationshipType.patchedBy,
+                        oe.spdx30.LifecycleScopeType.build,
+                        patches,
+                    )
+
             elif status == "Unpatched":
                 recipe_objset.new_vex_unpatched_relationship([spdx_cve_id], [recipe])
             elif status == "Ignored":
@@ -751,12 +770,14 @@ def create_spdx(d):
 
     # Collect all VEX statements from the recipe
     vex_statements = {}
+    vex_patches = {}
     for rel in recipe_objset.foreach_filter(
         oe.spdx30.Relationship,
         relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability,
     ):
         for cve in rel.to:
             vex_statements[cve] = []
+            vex_patches[cve] = []
 
     for cve in vex_statements.keys():
         for rel in recipe_objset.foreach_filter(
@@ -764,6 +785,13 @@ def create_spdx(d):
             from_=cve,
         ):
             vex_statements[cve].append(rel)
+            if rel.relationshipType == oe.spdx30.RelationshipType.fixedIn:
+                for patch_rel in recipe_objset.foreach_filter(
+                    oe.spdx30.Relationship,
+                    relationshipType=oe.spdx30.RelationshipType.patchedBy,
+                    from_=rel,
+                ):
+                    vex_patches[cve].extend(patch_rel.to)
 
     # Write out the package SPDX data now. It is not complete as we cannot
     # write the runtime data, so write it to a staging area and a later task
@@ -889,7 +917,9 @@ def create_spdx(d):
 
             # Add concluded license relationship if manually set
             # Only add when license analysis has been explicitly performed
-            concluded_license_str = d.getVar("SPDX_CONCLUDED_LICENSE:%s" % package) or d.getVar("SPDX_CONCLUDED_LICENSE")
+            concluded_license_str = d.getVar(
+                "SPDX_CONCLUDED_LICENSE:%s" % package
+            ) or d.getVar("SPDX_CONCLUDED_LICENSE")
             if concluded_license_str:
                 concluded_spdx_license = add_license_expression(
                     d, build_objset, concluded_license_str, license_data
@@ -915,9 +945,20 @@ def create_spdx(d):
             for cve, vexes in vex_statements.items():
                 for vex in vexes:
                     if vex.relationshipType == oe.spdx30.RelationshipType.fixedIn:
-                        pkg_objset.new_vex_patched_relationship(
+                        spdx_vex = pkg_objset.new_vex_patched_relationship(
                             [oe.sbom30.get_element_link_id(cve)], [spdx_package]
                         )
+                        if vex_patches[cve]:
+                            pkg_objset.new_scoped_relationship(
+                                spdx_vex,
+                                oe.spdx30.RelationshipType.patchedBy,
+                                oe.spdx30.LifecycleScopeType.build,
+                                [
+                                    oe.sbom30.get_element_link_id(p)
+                                    for p in vex_patches[cve]
+                                ],
+                            )
+
                     elif vex.relationshipType == oe.spdx30.RelationshipType.affects:
                         pkg_objset.new_vex_unpatched_relationship(
                             [oe.sbom30.get_element_link_id(cve)], [spdx_package]
-- 
2.53.0



  parent reply	other threads:[~2026-03-04 16:48 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-20 15:40 [OE-core][PATCH 0/9] Add SPDX 3 Recipe Information Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 1/9] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 2/9] gcc-source: " Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 3/9] spdx3: Add recipe SPDX data Joshua Watt
2026-02-22  7:59   ` Mathieu Dubois-Briand
2026-02-20 15:40 ` [OE-core][PATCH 4/9] spdx3: Add recipe SBoM task Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 5/9] spdx3: Add is-native property Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 6/9] spdx30: Include patch file information in VEX Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 7/9] spdx: De-duplicate CreationInfo Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 8/9] spdx: Ignore ASSUME_PROVIDED recipes Joshua Watt
2026-02-20 15:40 ` [OE-core][PATCH 9/9] spdx_common: Check for dependent task in task flags Joshua Watt
2026-02-24 23:00 ` [OE-core][PATCH v2 0/8] Add SPDX 3 Recipe Information Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 1/8] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 2/8] gcc-source: " Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 3/8] spdx3: Add recipe SPDX data Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 4/8] spdx3: Add recipe SBoM task Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 5/8] spdx3: Add is-native property Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 6/8] spdx30: Include patch file information in VEX Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 7/8] spdx: De-duplicate CreationInfo Joshua Watt
2026-02-24 23:00   ` [OE-core][PATCH v2 8/8] spdx_common: Check for dependent task in task flags Joshua Watt
2026-02-26 12:52   ` [OE-core][PATCH v2 0/8] Add SPDX 3 Recipe Information Mathieu Dubois-Briand
2026-02-26 14:27     ` Benjamin Robin
2026-02-26 15:09       ` Benjamin Robin
2026-02-26 15:41         ` Joshua Watt
2026-02-26 17:33   ` [OE-core][PATCH v3 " Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 1/8] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 2/8] gcc-source: " Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 3/8] spdx3: Add recipe SPDX data Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 4/8] spdx3: Add recipe SBoM task Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 5/8] spdx3: Add is-native property Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 6/8] spdx30: Include patch file information in VEX Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 7/8] spdx: De-duplicate CreationInfo Joshua Watt
2026-02-26 17:33     ` [OE-core][PATCH v3 8/8] spdx_common: Check for dependent task in task flags Joshua Watt
2026-02-27  7:32     ` [OE-core][PATCH v3 0/8] Add SPDX 3 Recipe Information Mathieu Dubois-Briand
2026-03-03  0:43     ` [OE-core][PATCH v4 0/9] " Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 1/9] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 2/9] gcc-source: " Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 3/9] spdx3: Add recipe SPDX data Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 4/9] spdx3: Add recipe SBoM task Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 5/9] spdx3: Add is-native property Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 6/9] spdx30: Include patch file information in VEX Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 7/9] spdx: De-duplicate CreationInfo Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 8/9] spdx_common: Check for dependent task in task flags Joshua Watt
2026-03-03  0:43       ` [OE-core][PATCH v4 9/9] spdx30: Skip install package CVE information Joshua Watt
2026-03-03 10:17       ` [OE-core][PATCH v4 0/9] Add SPDX 3 Recipe Information Antonin Godard
2026-03-03 14:08       ` Mathieu Dubois-Briand
2026-03-04 16:44       ` [OE-core][PATCH v5 00/13] " Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 01/13] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 02/13] gcc-source: " Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 03/13] spdx3: Add recipe SPDX data Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 04/13] spdx3: Add recipe SBoM task Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 05/13] spdx3: Add is-native property Joshua Watt
2026-03-04 16:44         ` Joshua Watt [this message]
2026-03-04 16:44         ` [OE-core][PATCH v5 07/13] spdx: De-duplicate CreationInfo Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 08/13] spdx_common: Check for dependent task in task flags Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 09/13] spdx30: Skip install package CVE information Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 10/13] dummy-sdk-package: Disable SPDX Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 11/13] spdx: Remove fatal errors for missing providers Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 12/13] spdx3: Use common variable for vardeps Joshua Watt
2026-03-04 16:44         ` [OE-core][PATCH v5 13/13] glibc-testsuite: Do not generate SPDX Joshua Watt
2026-03-05 19:59         ` [OE-core][PATCH v5 00/13] Add SPDX 3 Recipe Information Mathieu Dubois-Briand
2026-03-10 18:38         ` [OE-core][PATCH v6 00/15] " Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 01/15] llvm-project-source: Use allarch.bbclass Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 02/15] gcc-source: " Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 03/15] spdx3: Add recipe SPDX data Joshua Watt
2026-03-12 11:43             ` Richard Purdie
2026-03-12 14:11               ` Joshua Watt
2026-03-12 17:50                 ` Richard Purdie
2026-03-10 18:38           ` [OE-core][PATCH v6 04/15] spdx3: Add recipe SBoM task Joshua Watt
2026-03-12 11:50             ` Richard Purdie
2026-03-12 14:12               ` Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 05/15] spdx3: Add is-native property Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 06/15] spdx30: Include patch file information in VEX Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 07/15] spdx: De-duplicate CreationInfo Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 08/15] spdx_common: Check for dependent task in task flags Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 09/15] spdx30: Skip install package CVE information Joshua Watt
2026-03-12 11:55             ` Richard Purdie
2026-03-12 14:15               ` Joshua Watt
2026-03-12 15:52                 ` Richard Purdie
2026-03-12 16:11                   ` Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 10/15] dummy-sdk-package: Disable SPDX Joshua Watt
2026-03-12 11:59             ` Richard Purdie
2026-03-12 14:24               ` Joshua Watt
2026-03-12 15:58                 ` Richard Purdie
2026-03-12 16:06                   ` Joshua Watt
2026-03-12 16:43                     ` Joshua Watt
2026-03-12 18:02                       ` Joshua Watt
2026-03-12 20:34                         ` Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 11/15] spdx: Remove fatal errors for missing providers Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 12/15] spdx3: Use common variable for vardeps Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 13/15] glibc-testsuite: Do not generate SPDX Joshua Watt
2026-03-10 18:38           ` [OE-core][PATCH v6 14/15] spdx: Remove do_collect_spdx_deps task Joshua Watt
2026-03-11 13:55           ` [OE-core][PATCH v6 00/15] Add SPDX 3 Recipe Information Mathieu Dubois-Briand
2026-03-11 16:39             ` Joshua Watt
2026-03-11 19:33               ` Mathieu Dubois-Briand
2026-03-11 22:56                 ` Joshua Watt
2026-03-18 13:44           ` [OE-core][PATCH v7 00/12] " Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 01/12] spdx3: Add recipe SPDX data Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 02/12] spdx3: Add recipe SBoM task Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 03/12] spdx3: Add is-native property Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 04/12] spdx30: Include patch file information in VEX Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 05/12] spdx: De-duplicate CreationInfo Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 06/12] spdx_common: Check for dependent task in task flags Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 07/12] spdx30: Remove package VEX Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 08/12] spdx: Remove fatal errors for missing providers Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 09/12] spdx3: Use common variable for vardeps Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 10/12] glibc-testsuite: Do not generate SPDX Joshua Watt
2026-03-18 13:44             ` [OE-core][PATCH v7 11/12] spdx: Remove do_collect_spdx_deps task Joshua Watt
2026-03-18 13:49             ` [OE-core][PATCH v7 00/12] Add SPDX 3 Recipe Information Joshua Watt
2026-03-19  7:07               ` Mathieu Dubois-Briand
2026-03-19 12:02                 ` Mathieu Dubois-Briand
2026-03-19 21:55                 ` Joshua Watt
2026-03-19 22:14                   ` Richard Purdie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260304164835.3072507-7-JPEWhacker@gmail.com \
    --to=jpewhacker@gmail.com \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox