summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/classes/create-spdx-2.2.bbclass138
-rw-r--r--meta/lib/oe/sbom.py2
2 files changed, 105 insertions, 35 deletions
diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index 13d13fe1fcf..950e853d4d2 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -25,6 +25,7 @@ SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy"
SPDX_INCLUDE_SOURCES ??= "0"
SPDX_ARCHIVE_SOURCES ??= "0"
SPDX_ARCHIVE_PACKAGED ??= "0"
+SPDX_INCLUDE_LOCAL_FILES ??= "0"
SPDX_UUID_NAMESPACE ??= "sbom.openembedded.org"
SPDX_NAMESPACE_PREFIX ??= "http://spdx.org/spdxdoc"
@@ -412,47 +413,116 @@ def add_download_packages(d, doc, recipe):
import bb.process
import oe.spdx
import oe.sbom
+ import bb.utils
+
+ uri_cache = {}
+ path_cache = {}
+
+ def add_package(package):
+ nonlocal doc
+ doc.packages.append(package)
+ doc.add_relationship(doc, "DESCRIBES", package)
+ # In the future, we might be able to do more fancy dependencies,
+ # but this should be sufficient for now
+ doc.add_relationship(package, "BUILD_DEPENDENCY_OF", recipe)
+
+ def add_local_file(localpath, idx):
+ nonlocal uri_cache
+ nonlocal path_cache
+
+ parent = os.path.dirname(localpath)
+
+ if parent not in uri_cache:
+ try:
+ stdout, _ = bb.process.run(["git", "branch", "-qr", "--format=%(refname)", "--contains", "HEAD"], cwd=parent)
+ branches = stdout.splitlines()
+ branches.sort()
+ for b in branches:
+ if b.startswith("refs/remotes"):
+ remote = b.split("/")[2]
+ break
+ else:
+ # No valid remote found
+ uri_cache[parent] = None
+ return
+
+ stdout, _ = bb.process.run(["git", "remote", "get-url", remote], cwd=parent)
+ uri_prefix = "git+" + stdout.strip()
+
+ stdout, _ = bb.process.run(["git", "rev-parse", "HEAD"], cwd=parent)
+ uri_prefix = uri_prefix + "@" + stdout.strip()
+
+ stdout, _ = bb.process.run(["git", "rev-parse", "--show-prefix"], cwd=parent)
+
+ path_cache[parent] = os.path.join(stdout.strip().rstrip("/"))
+ uri_cache[parent] = uri_prefix
+ except bb.process.ExecutionError:
+ uri_cache[parent] = None
+
+ package = oe.spdx.SPDXPackage()
+ package.SPDXID = oe.sbom.get_download_spdxid(d, idx)
+ if uri_cache[parent] is not None:
+ package.name = path_cache[parent] + "/" + os.path.basename(localpath)
+ package.downloadLocation = uri_cache[parent] + "#" + package.name
+ else:
+ package.name = localpath
+
+ c = oe.spdx.SPDXChecksum()
+ c.algorithm = "SHA256"
+ c.checksumValue = bb.utils.sha256_file(localpath)
+ package.checksums.append(c)
+
+ add_package(package)
+
for download_idx, src_uri in enumerate(d.getVar('SRC_URI').split()):
f = bb.fetch2.FetchData(src_uri, d)
for name in f.names:
- package = oe.spdx.SPDXPackage()
- package.name = "%s-source-%d" % (d.getVar("PN"), download_idx + 1)
- package.SPDXID = oe.sbom.get_download_spdxid(d, download_idx + 1)
-
if f.type == "file":
- continue
+ if d.getVar("SPDX_INCLUDE_LOCAL_FILES") == "0":
+ continue
- uri = f.type
- proto = getattr(f, "proto", None)
- if proto is not None:
- uri = uri + "+" + proto
- uri = uri + "://" + f.host + f.path
-
- if f.method.supports_srcrev():
- uri = uri + "@" + f.revisions[name]
-
- if f.method.supports_checksum(f):
- for checksum_id in CHECKSUM_LIST:
- if checksum_id.upper() not in oe.spdx.SPDXPackage.ALLOWED_CHECKSUMS:
- continue
-
- expected_checksum = getattr(f, "%s_expected" % checksum_id)
- if expected_checksum is None:
- continue
-
- c = oe.spdx.SPDXChecksum()
- c.algorithm = checksum_id.upper()
- c.checksumValue = expected_checksum
- package.checksums.append(c)
-
- package.downloadLocation = uri
- doc.packages.append(package)
- doc.add_relationship(doc, "DESCRIBES", package)
- # In the future, we might be able to do more fancy dependencies,
- # but this should be sufficient for now
- doc.add_relationship(package, "BUILD_DEPENDENCY_OF", recipe)
+ localpath = f.method.localpath(f, d)
+ if os.path.isdir(localpath):
+ file_idx = 1
+ for (root, dirs, files) in os.walk(localpath):
+ files.sort()
+ for fn in files:
+ add_local_file(os.path.join(root, fn), "%d.%d" % (download_idx + 1, file_idx))
+ file_idx += 1
+ else:
+ add_local_file(localpath, download_idx + 1)
+ else:
+ package = oe.spdx.SPDXPackage()
+ package.name = "%s-source-%d" % (d.getVar("PN"), download_idx + 1)
+ package.SPDXID = oe.sbom.get_download_spdxid(d, download_idx + 1)
+
+ uri = f.type
+ proto = getattr(f, "proto", None)
+ if proto is not None:
+ uri = uri + "+" + proto
+ uri = uri + "://" + f.host + f.path
+
+ if f.method.supports_srcrev():
+ uri = uri + "@" + f.revisions[name]
+
+ if f.method.supports_checksum(f):
+ for checksum_id in CHECKSUM_LIST:
+ if checksum_id.upper() not in oe.spdx.SPDXPackage.ALLOWED_CHECKSUMS:
+ continue
+
+ expected_checksum = getattr(f, "%s_expected" % checksum_id)
+ if expected_checksum is None:
+ continue
+
+ c = oe.spdx.SPDXChecksum()
+ c.algorithm = checksum_id.upper()
+ c.checksumValue = expected_checksum
+ package.checksums.append(c)
+
+ package.downloadLocation = uri
+ add_package(package)
python do_create_spdx() {
from datetime import datetime, timezone
diff --git a/meta/lib/oe/sbom.py b/meta/lib/oe/sbom.py
index 22ed5070ea0..71a95b393b3 100644
--- a/meta/lib/oe/sbom.py
+++ b/meta/lib/oe/sbom.py
@@ -15,7 +15,7 @@ def get_recipe_spdxid(d):
def get_download_spdxid(d, idx):
- return "SPDXRef-Download-%s-%d" % (d.getVar("PN"), idx)
+ return "SPDXRef-Download-%s-%s" % (d.getVar("PN"), idx)
def get_package_spdxid(pkg):