This adds support for determining the revision and downloadLocation of meta-layers and adds them to the OE generated SPDX document.
This downloadLocation will result in a NOASSERTION entry if - the meta-layer is not in a git repo - the git repo is dirty - the git remote does not have a valid URL - the git remote does not contain the used revision as far as can be eluded from the local repo Variables to configure the behavior: - SPDX_LAYER_REMOTE (default: origin): select the name of the git remote to use for layers. Set to an empty string to always return NOASSERTION - SPDX_LAYER_REMOTE_layername: override SPDX_LAYER_REMOTE for a specific layer - SPDX_REQUIRE_LAYER_ASSERTION: set to true to fail a build if determining downloadLocation fails for any layer Signed-off-by: Daniel Wagenknecht <[email protected]> --- meta/classes/create-spdx-3.0.bbclass | 1 + meta/classes/spdx-common.bbclass | 3 ++ meta/lib/oe/sbom30.py | 12 +++++ meta/lib/oe/spdx30_tasks.py | 74 ++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 56fd01fd533..1ef6b15ac22 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -285,6 +285,7 @@ addtask do_create_recipe_sbom_setscene python spdx30_build_started_handler () { import oe.spdx30_tasks d = e.data.createCopy() + oe.spdx30_tasks.write_layers_spdx(d) oe.spdx30_tasks.write_bitbake_spdx(d) } diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index 40701730a69..b64537dfb48 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -89,6 +89,9 @@ SPDX_FILE_EXCLUDE_PATTERNS[doc] = "Space-separated list of Python regular \ (no filtering). Example: \ SPDX_FILE_EXCLUDE_PATTERNS = '\\.patch$ \\.diff$ /test/ \\.pyc$ \\.o$'" +SPDX_REQUIRE_LAYER_ASSERTION ??= "0" +SPDX_LAYER_REMOTE ??= "origin" + python () { from oe.cve_check import extend_cve_status extend_cve_status(d) diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py index 0f1f9281ad3..d2a3155b2b1 100644 --- a/meta/lib/oe/sbom30.py +++ b/meta/lib/oe/sbom30.py @@ -752,6 +752,16 @@ class ObjectSet(oe.spdx30.SHACLObjectSet): return bb_objset + def import_layers_objset(self): + deploy_dir_spdx = Path(self.d.getVar("DEPLOY_DIR_SPDX")) + layers_objset = load_jsonld( + self.d, deploy_dir_spdx / "layers.spdx.json", required=True + ) + self.doc.import_.extend(layers_objset.doc.import_) + self.update(layers_objset.objects) + + return layers_objset + def import_bitbake_build(self): def find_bitbake_build(objset): return objset.find_filter( @@ -793,6 +803,8 @@ class ObjectSet(oe.spdx30.SHACLObjectSet): [build], ) + layers = self.import_layers_objset() + if self.d.getVar("SPDX_INCLUDE_BUILD_VARIABLES") == "1": for varname in sorted(self.d.keys()): if varname.startswith("__"): diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index 1821dd7de4a..0a8f4b0e1a0 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -1220,6 +1220,80 @@ def create_package_spdx(d): oe.sbom30.write_recipe_jsonld_doc(d, common_objset, "common-package", deploydir) +def git_remote_has_rev(path, remote, rev): + try: + branchlist, _ = bb.process.run(f"git branch --remotes --list '{remote}/*' --contains {rev}", cwd=path) + except bb.process.ExecutionError: + return False + return len(branchlist) > 0 + +def get_layer_downloadLocation(d, l_path, l_name, l_branch, l_rev, l_ismodified): + from urllib.parse import urlparse, urlunparse + + repo = oe.buildcfg.get_metadata_git_toplevel(l_path) + + if not repo or not l_name or l_ismodified: + return "NOASSERTION" + + remoteName = d.getVar(f"SPDX_LAYER_REMOTE_{l_name}") or d.getVar(f"SPDX_LAYER_REMOTE") + if not remoteName: + return "NOASSERTION" + + # parse and reconstruct the url to drop potentially present username and password + remoteUrl = urlparse(oe.buildcfg.get_metadata_git_remote_url(repo, remoteName)) + if not remoteUrl or remoteUrl.scheme not in ["https", "http", "git", "ssh"]: + return "NOASSERTION" + remoteUrl = urlunparse(remoteUrl) + + # revision = d.getVar(f"SPDX_LAYER_CLAIM_REV_UNCHECKED_{l_name}") + # if not revision: + revision = l_rev + if revision == "<unknown>" or not git_remote_has_rev(repo, remoteName, revision): + return "NOASSERTION" + + relpath = os.path.relpath(l_path, repo) + + return f"git+{remoteUrl}@{revision}{'#' + relpath if relpath else ''}" + + +def write_layers_spdx(d): + d.setVar("PN", "layers") + d.setVar("BB_TASKHASH", "layers") + oe.spdx_common.load_spdx_license_data(d) + deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) + + layer_objset = oe.sbom30.ObjectSet.new_objset(d, "layers") + + layers = oe.buildcfg.get_layer_revisions(d) + for (l_path, l_name, l_branch, l_rev, l_ismodified) in layers: + downloadLocation = get_layer_downloadLocation(d, l_path, l_name, l_branch, l_rev, l_ismodified) + + + if oe.utils.vartrue("SPDX_REQUIRE_LAYER_ASSERTION", True, False, d) and downloadLocation == "NOASSERTION": + bb.fatal(f"Layer {l_name} does not have a valid downloadLocation") + layer = oe.spdx30.software_Package( + _id=layer_objset.new_spdxid("layer", l_name), + creationInfo=layer_objset.doc.creationInfo, + name=l_name, + software_packageVersion=l_rev, + software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.specification, + software_downloadLocation=downloadLocation, + software_sourceInfo=json.dumps( + { + "branch": l_branch, + "is-modified": (len(l_ismodified) > 0), + }, + separators=(",", ":"), + ), + ) + + layer_objset.add_root(layer) + layer_objset.set_element_alias(layer) + + oe.sbom30.write_jsonld_doc(d, layer_objset, deploy_dir_spdx / "layers.spdx.json") + + + def write_bitbake_spdx(d): # Set PN to "bitbake" so that SPDX IDs can be generated d.setVar("PN", "bitbake") -- 2.54.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#245764): https://lists.openembedded.org/g/openembedded-core/message/245764 Mute This Topic: https://lists.openembedded.org/mt/121240838/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
