@@ -45,6 +45,17 @@ SPDX_INCLUDE_VEX[doc] = "Controls what VEX information is in the output. Set to
including those already fixed upstream (warning: This can be large and \
slow)."
+SPDX_PACKAGE_INCLUDE_VEX ?= "0"
+SPDX_PACKAGE_INCLUDE_VEX[doc] = "Link VEX information to the binary package outputs. \
+ Normally, VEX information is only linked to the common recipe that `generates` the \
+ binary packages, but setting this to '1' will cause it to also be linked into the \
+ generated binary packages. This is off by default because linking the VEX data to \
+ each package causes the SPDX output to grow very large, and the same information \
+ can be determined by following the `generates` relationship back to the recipe. \
+ Before recipe packages were introduced, this was the only way VEX data was \
+ expressed; you may need to enable this if your downstream tools do not \
+ understand how to trace back to the recipe to find VEX information."
+
SPDX_INCLUDE_TIMESTAMPS ?= "0"
SPDX_INCLUDE_TIMESTAMPS[doc] = "Include time stamps in SPDX output. This is \
useful if you want to know when artifacts were produced and when builds \
@@ -771,27 +771,28 @@ 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():
+ if (d.getVar("SPDX_PACKAGE_INCLUDE_VEX") or "") == "1":
for rel in recipe_objset.foreach_filter(
- oe.spdx30.security_VexVulnAssessmentRelationship,
- from_=cve,
+ oe.spdx30.Relationship,
+ relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability,
):
- 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)
+ for cve in rel.to:
+ vex_statements[cve] = []
+ vex_patches[cve] = []
+
+ for cve in vex_statements.keys():
+ for rel in recipe_objset.foreach_filter(
+ oe.spdx30.security_VexVulnAssessmentRelationship,
+ 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
@@ -429,3 +429,15 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase):
value, ["enabled", "disabled"],
f"Unexpected PACKAGECONFIG value '{value}' for {key}"
)
+
+ def test_package_vex(self):
+ objset = self.check_recipe_spdx(
+ "core-image-minimal",
+ "{DEPLOY_DIR_IMAGE}/core-image-minimal-{MACHINE}.rootfs.spdx.json",
+ extraconf="""\
+ SPDX_PACKAGE_INCLUDE_VEX = "1"
+ """,
+ )
+
+ # Document should be fully linked
+ self.check_objset_missing_ids(objset)
Skips adding the install package CVE information by default. This information grows exponentially, since it ends up be N_CVES * N_PACKAGES. The CVE information for a given installed package can be determined by following the "generates" link between the install package and the recipe and looking at the CVE information for the recipe, meaning that the CVE information is only included once in the SPDX document. If users still need the legacy method of including CVE information for each package, then then can set SPDX_PACKAGE_INCLUDE_VEX = "1" Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> --- meta/classes/create-spdx-3.0.bbclass | 11 ++++++++ meta/lib/oe/spdx30_tasks.py | 39 ++++++++++++++-------------- meta/lib/oeqa/selftest/cases/spdx.py | 12 +++++++++ 3 files changed, 43 insertions(+), 19 deletions(-)