summaryrefslogtreecommitdiffstats
path: root/meta/classes/create-spdx-image-3.0.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/create-spdx-image-3.0.bbclass')
-rw-r--r--meta/classes/create-spdx-image-3.0.bbclass307
1 files changed, 18 insertions, 289 deletions
diff --git a/meta/classes/create-spdx-image-3.0.bbclass b/meta/classes/create-spdx-image-3.0.bbclass
index 467719555d..1cad8537d1 100644
--- a/meta/classes/create-spdx-image-3.0.bbclass
+++ b/meta/classes/create-spdx-image-3.0.bbclass
@@ -9,37 +9,6 @@ SPDX_ROOTFS_PACKAGES = "${SPDXDIR}/rootfs-packages.json"
9SPDXIMAGEDEPLOYDIR = "${SPDXDIR}/image-deploy" 9SPDXIMAGEDEPLOYDIR = "${SPDXDIR}/image-deploy"
10SPDXROOTFSDEPLOY = "${SPDXDIR}/rootfs-deploy" 10SPDXROOTFSDEPLOY = "${SPDXDIR}/rootfs-deploy"
11 11
12def collect_build_package_inputs(d, objset, build, packages):
13 import oe.spdx_common
14 providers = oe.spdx_common.collect_package_providers(d)
15
16 build_deps = set()
17
18 for name in sorted(packages.keys()):
19 if name not in providers:
20 bb.fatal("Unable to find SPDX provider for '%s'" % name)
21
22 pkg_name, pkg_hashfn = providers[name]
23
24 # Copy all of the package SPDX files into the Sbom elements
25 pkg_spdx, _ = oe.sbom30.find_root_obj_in_jsonld(
26 d,
27 "packages",
28 pkg_name,
29 oe.spdx30.software_Package,
30 software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.install,
31 )
32 build_deps.add(pkg_spdx._id)
33
34 if build_deps:
35 objset.new_scoped_relationship(
36 [build],
37 oe.spdx30.RelationshipType.hasInputs,
38 oe.spdx30.LifecycleScopeType.build,
39 sorted(list(build_deps)),
40 )
41
42
43python spdx_collect_rootfs_packages() { 12python spdx_collect_rootfs_packages() {
44 import json 13 import json
45 from pathlib import Path 14 from pathlib import Path
@@ -58,44 +27,8 @@ python spdx_collect_rootfs_packages() {
58ROOTFS_POSTUNINSTALL_COMMAND =+ "spdx_collect_rootfs_packages" 27ROOTFS_POSTUNINSTALL_COMMAND =+ "spdx_collect_rootfs_packages"
59 28
60python do_create_rootfs_spdx() { 29python do_create_rootfs_spdx() {
61 import json 30 import oe.spdx30_tasks
62 from pathlib import Path 31 oe.spdx30_tasks.create_rootfs_spdx(d)
63 import oe.spdx30
64 import oe.sbom30
65 from datetime import datetime
66
67 deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX"))
68 deploydir = Path(d.getVar("SPDXROOTFSDEPLOY"))
69 root_packages_file = Path(d.getVar("SPDX_ROOTFS_PACKAGES"))
70 image_basename = d.getVar("IMAGE_BASENAME")
71 machine = d.getVar("MACHINE")
72
73 with root_packages_file.open("r") as f:
74 packages = json.load(f)
75
76 objset = oe.sbom30.ObjectSet.new_objset(d, "%s-%s" % (image_basename, machine))
77
78 rootfs = objset.add_root(oe.spdx30.software_Package(
79 _id=objset.new_spdxid("rootfs", image_basename),
80 creationInfo=objset.doc.creationInfo,
81 name=image_basename,
82 software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.archive,
83 ))
84 set_timestamp_now(d, rootfs, "builtTime")
85
86 rootfs_build = objset.add_root(objset.new_task_build("rootfs", "rootfs"))
87 set_timestamp_now(d, rootfs_build, "build_buildEndTime")
88
89 objset.new_scoped_relationship(
90 [rootfs_build],
91 oe.spdx30.RelationshipType.hasOutputs,
92 oe.spdx30.LifecycleScopeType.build,
93 [rootfs],
94 )
95
96 collect_build_package_inputs(d, objset, rootfs_build, packages)
97
98 oe.sbom30.write_recipe_jsonld_doc(d, objset, "rootfs", deploydir)
99} 32}
100addtask do_create_rootfs_spdx after do_rootfs before do_image 33addtask do_create_rootfs_spdx after do_rootfs before do_image
101SSTATETASKS += "do_create_rootfs_spdx" 34SSTATETASKS += "do_create_rootfs_spdx"
@@ -110,79 +43,8 @@ python do_create_rootfs_spdx_setscene() {
110addtask do_create_rootfs_spdx_setscene 43addtask do_create_rootfs_spdx_setscene
111 44
112python do_create_image_spdx() { 45python do_create_image_spdx() {
113 import oe.spdx30 46 import oe.spdx30_tasks
114 import oe.sbom30 47 oe.spdx30_tasks.create_image_spdx(d)
115 import json
116 from pathlib import Path
117
118 image_deploy_dir = Path(d.getVar('IMGDEPLOYDIR'))
119 manifest_path = Path(d.getVar("IMAGE_OUTPUT_MANIFEST"))
120 spdx_work_dir = Path(d.getVar('SPDXIMAGEWORK'))
121
122 image_basename = d.getVar('IMAGE_BASENAME')
123 machine = d.getVar("MACHINE")
124
125 objset = oe.sbom30.ObjectSet.new_objset(d, "%s-%s" % (image_basename, machine))
126
127 with manifest_path.open("r") as f:
128 manifest = json.load(f)
129
130 builds = []
131 for task in manifest:
132 imagetype = task["imagetype"]
133 taskname = task["taskname"]
134
135 image_build = objset.add_root(objset.new_task_build(taskname, "image/%s" % imagetype))
136 set_timestamp_now(d, image_build, "build_buildEndTime")
137 builds.append(image_build)
138
139 artifacts = []
140
141 for image in task["images"]:
142 image_filename = image["filename"]
143 image_path = image_deploy_dir / image_filename
144 a = objset.add_root(oe.spdx30.software_File(
145 _id=objset.new_spdxid("image", image_filename),
146 creationInfo=objset.doc.creationInfo,
147 name=image_filename,
148 verifiedUsing=[
149 oe.spdx30.Hash(
150 algorithm=oe.spdx30.HashAlgorithm.sha256,
151 hashValue=bb.utils.sha256_file(image_path),
152 )
153 ]
154 ))
155 set_purposes(d, a, "SPDX_IMAGE_PURPOSE:%s" % imagetype, "SPDX_IMAGE_PURPOSE")
156 set_timestamp_now(d, a, "builtTime")
157
158 artifacts.append(a)
159
160 if artifacts:
161 objset.new_scoped_relationship(
162 [image_build],
163 oe.spdx30.RelationshipType.hasOutputs,
164 oe.spdx30.LifecycleScopeType.build,
165 artifacts,
166 )
167
168 if builds:
169 rootfs_image, _ = oe.sbom30.find_root_obj_in_jsonld(
170 d,
171 "rootfs",
172 "%s-%s" % (image_basename, machine),
173 oe.spdx30.software_Package,
174 # TODO: Should use a purpose to filter here?
175 )
176 objset.new_scoped_relationship(
177 builds,
178 oe.spdx30.RelationshipType.hasInputs,
179 oe.spdx30.LifecycleScopeType.build,
180 [rootfs_image._id],
181 )
182
183 objset.add_aliases()
184 objset.link()
185 oe.sbom30.write_recipe_jsonld_doc(d, objset, "image", spdx_work_dir)
186} 48}
187addtask do_create_image_spdx after do_image_complete do_create_rootfs_spdx before do_build 49addtask do_create_image_spdx after do_image_complete do_create_rootfs_spdx before do_build
188SSTATETASKS += "do_create_image_spdx" 50SSTATETASKS += "do_create_image_spdx"
@@ -199,46 +61,8 @@ addtask do_create_image_spdx_setscene
199 61
200 62
201python do_create_image_sbom_spdx() { 63python do_create_image_sbom_spdx() {
202 import os 64 import oe.spdx30_tasks
203 from pathlib import Path 65 oe.spdx30_tasks.create_image_sbom_spdx(d)
204 import oe.spdx30
205 import oe.sbom30
206
207 image_name = d.getVar("IMAGE_NAME")
208 image_basename = d.getVar("IMAGE_BASENAME")
209 image_link_name = d.getVar("IMAGE_LINK_NAME")
210 imgdeploydir = Path(d.getVar("SPDXIMAGEDEPLOYDIR"))
211 machine = d.getVar("MACHINE")
212
213 spdx_path = imgdeploydir / (image_name + ".spdx.json")
214
215 root_elements = []
216
217 # TODO: Do we need to add the rootfs or are the image files sufficient?
218 rootfs_image, _ = oe.sbom30.find_root_obj_in_jsonld(
219 d,
220 "rootfs",
221 "%s-%s" % (image_basename, machine),
222 oe.spdx30.software_Package,
223 # TODO: Should use a purpose here?
224 )
225 root_elements.append(rootfs_image._id)
226
227 image_objset, _ = oe.sbom30.find_jsonld(d, "image", "%s-%s" % (image_basename, machine), required=True)
228 for o in image_objset.foreach_root(oe.spdx30.software_File):
229 root_elements.append(o._id)
230
231 objset, sbom = oe.sbom30.create_sbom(d, image_name, root_elements)
232
233 oe.sbom30.write_jsonld_doc(d, objset, spdx_path)
234
235 def make_image_link(target_path, suffix):
236 if image_link_name:
237 link = imgdeploydir / (image_link_name + suffix)
238 if link != target_path:
239 link.symlink_to(os.path.relpath(target_path, link.parent))
240
241 make_image_link(spdx_path, ".spdx.json")
242} 66}
243addtask do_create_image_sbom_spdx after do_create_rootfs_spdx do_create_image_spdx before do_build 67addtask do_create_image_sbom_spdx after do_create_rootfs_spdx do_create_image_spdx before do_build
244SSTATETASKS += "do_create_image_sbom_spdx" 68SSTATETASKS += "do_create_image_sbom_spdx"
@@ -268,149 +92,54 @@ POPULATE_SDK_POST_TARGET_COMMAND:append:task-populate-sdk-ext = " sdk_ext_target
268 92
269python sdk_host_create_spdx() { 93python sdk_host_create_spdx() {
270 from pathlib import Path 94 from pathlib import Path
95 import oe.spdx30_tasks
271 spdx_work_dir = Path(d.getVar('SPDXSDKWORK')) 96 spdx_work_dir = Path(d.getVar('SPDXSDKWORK'))
272 97
273 sdk_create_spdx(d, "host", spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME")) 98 oe.spdx30_tasks.sdk_create_spdx(d, "host", spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME"))
274} 99}
275 100
276python sdk_target_create_spdx() { 101python sdk_target_create_spdx() {
277 from pathlib import Path 102 from pathlib import Path
103 import oe.spdx30_tasks
278 spdx_work_dir = Path(d.getVar('SPDXSDKWORK')) 104 spdx_work_dir = Path(d.getVar('SPDXSDKWORK'))
279 105
280 sdk_create_spdx(d, "target", spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME")) 106 oe.spdx30_tasks.sdk_create_spdx(d, "target", spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME"))
281} 107}
282 108
283python sdk_ext_host_create_spdx() { 109python sdk_ext_host_create_spdx() {
284 from pathlib import Path 110 from pathlib import Path
111 import oe.spdx30_tasks
285 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK')) 112 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK'))
286 113
287 # TODO: This doesn't seem to work 114 # TODO: This doesn't seem to work
288 sdk_create_spdx(d, "host", spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME")) 115 oe.spdx30_tasks.sdk_create_spdx(d, "host", spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME"))
289} 116}
290 117
291python sdk_ext_target_create_spdx() { 118python sdk_ext_target_create_spdx() {
292 from pathlib import Path 119 from pathlib import Path
120 import oe.spdx30_tasks
293 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK')) 121 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK'))
294 122
295 # TODO: This doesn't seem to work 123 # TODO: This doesn't seem to work
296 sdk_create_spdx(d, "target", spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME")) 124 oe.spdx30_tasks.sdk_create_spdx(d, "target", spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME"))
297} 125}
298 126
299def sdk_create_spdx(d, sdk_type, spdx_work_dir, toolchain_outputname):
300 from pathlib import Path
301 from oe.sdk import sdk_list_installed_packages
302 import oe.spdx30
303 import oe.sbom30
304 from datetime import datetime
305
306 sdk_name = toolchain_outputname + "-" + sdk_type
307 sdk_packages = sdk_list_installed_packages(d, sdk_type == "target")
308
309 objset = oe.sbom30.ObjectSet.new_objset(d, sdk_name)
310
311 sdk_rootfs = objset.add_root(oe.spdx30.software_Package(
312 _id=objset.new_spdxid("sdk-rootfs", sdk_name),
313 creationInfo=objset.doc.creationInfo,
314 name=sdk_name,
315 software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.archive,
316 ))
317 set_timestamp_now(d, sdk_rootfs, "builtTime")
318
319 sdk_build = objset.add_root(objset.new_task_build("sdk-rootfs", "sdk-rootfs"))
320 set_timestamp_now(d, sdk_build, "build_buildEndTime")
321
322 objset.new_scoped_relationship(
323 [sdk_build],
324 oe.spdx30.RelationshipType.hasOutputs,
325 oe.spdx30.LifecycleScopeType.build,
326 [sdk_rootfs],
327 )
328
329 collect_build_package_inputs(d, objset, sdk_build, sdk_packages)
330
331 objset.add_aliases()
332 oe.sbom30.write_jsonld_doc(d, objset, spdx_work_dir / "sdk-rootfs.spdx.json")
333 127
334python sdk_create_sbom() { 128python sdk_create_sbom() {
335 from pathlib import Path 129 from pathlib import Path
130 import oe.spdx30_tasks
336 sdk_deploydir = Path(d.getVar("SDKDEPLOYDIR")) 131 sdk_deploydir = Path(d.getVar("SDKDEPLOYDIR"))
337 spdx_work_dir = Path(d.getVar('SPDXSDKWORK')) 132 spdx_work_dir = Path(d.getVar('SPDXSDKWORK'))
338 133
339 create_sdk_sbom(d, sdk_deploydir, spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME")) 134 oe.spdx30_tasks.create_sdk_sbom(d, sdk_deploydir, spdx_work_dir, d.getVar("TOOLCHAIN_OUTPUTNAME"))
340} 135}
341 136
342python sdk_ext_create_sbom() { 137python sdk_ext_create_sbom() {
343 from pathlib import Path 138 from pathlib import Path
139 import oe.spdx30_tasks
344 sdk_deploydir = Path(d.getVar("SDKEXTDEPLOYDIR")) 140 sdk_deploydir = Path(d.getVar("SDKEXTDEPLOYDIR"))
345 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK')) 141 spdx_work_dir = Path(d.getVar('SPDXSDKEXTWORK'))
346 142
347 create_sdk_sbom(d, sdk_deploydir, spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME")) 143 oe.spdx30_tasks.create_sdk_sbom(d, sdk_deploydir, spdx_work_dir, d.getVar("TOOLCHAINEXT_OUTPUTNAME"))
348} 144}
349 145
350def create_sdk_sbom(d, sdk_deploydir, spdx_work_dir, toolchain_outputname):
351 import oe.spdx30
352 import oe.sbom30
353 from pathlib import Path
354 from datetime import datetime
355
356 # Load the document written earlier
357 rootfs_objset = oe.sbom30.load_jsonld(d, spdx_work_dir / "sdk-rootfs.spdx.json", required=True)
358
359 # Create a new build for the SDK installer
360 sdk_build = rootfs_objset.new_task_build("sdk-populate", "sdk-populate")
361 set_timestamp_now(d, sdk_build, "build_buildEndTime")
362
363 rootfs = rootfs_objset.find_root(oe.spdx30.software_Package)
364 if rootfs is None:
365 bb.fatal("Unable to find rootfs artifact")
366
367 rootfs_objset.new_scoped_relationship(
368 [sdk_build],
369 oe.spdx30.RelationshipType.hasInputs,
370 oe.spdx30.LifecycleScopeType.build,
371 [rootfs]
372 )
373
374 files = set()
375 root_files = []
376
377 # NOTE: os.walk() doesn't return symlinks
378 for dirpath, dirnames, filenames in os.walk(sdk_deploydir):
379 for fn in filenames:
380 fpath = Path(dirpath) / fn
381 if not fpath.is_file() or fpath.is_symlink():
382 continue
383
384 relpath = str(fpath.relative_to(sdk_deploydir))
385
386 f = rootfs_objset.new_file(
387 rootfs_objset.new_spdxid("sdk-installer", relpath),
388 relpath,
389 fpath,
390 )
391 set_timestamp_now(d, f, "builtTime")
392
393 if fn.endswith(".manifest"):
394 f.software_primaryPurpose = oe.spdx30.software_SoftwarePurpose.manifest
395 elif fn.endswith(".testdata.json"):
396 f.software_primaryPurpose = oe.spdx30.software_SoftwarePurpose.configuration
397 else:
398 set_purposes(d, f, "SPDX_SDK_PURPOSE")
399 root_files.append(f)
400
401 files.add(f)
402
403 if files:
404 rootfs_objset.new_scoped_relationship(
405 [sdk_build],
406 oe.spdx30.RelationshipType.hasOutputs,
407 oe.spdx30.LifecycleScopeType.build,
408 files,
409 )
410 else:
411 bb.warn(f"No SDK output files found in {sdk_deploydir}")
412
413 objset, sbom = oe.sbom30.create_sbom(d, toolchain_outputname, sorted(list(files)), [rootfs_objset])
414
415 oe.sbom30.write_jsonld_doc(d, objset, sdk_deploydir / (toolchain_outputname + ".spdx.json"))
416