From patchwork Tue Oct 27 22:47:15 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102156 Received: from mail-oa1-f50.google.com (mail-oa1-f50.google.com [209.85.160.50]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.31666.1793141378093333518 for ; Tue, 27 Oct 2026 15:49:38 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=zg9g+QSa; spf=pass (domain: gmail.com, ip: 209.85.160.50, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f50.google.com with SMTP id 586e51a60fabf-46556b9e02cso225649fac.1 for ; Tue, 27 Oct 2026 15:49:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141377; x=1793746177; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gIS2bnYzcbQkMxQgoekph5CH8vdF5nI/voXUkG5onsE=; b=zg9g+QSaCm8eT/I0NzoksbH+kaY4dna2CoDfm4I7IT8Cjf1xztFi88xq5v/5EvUEgn v3JyMLK3Ot3YjISL4kjPeCZNyA9162zOqQA24L88LutCjtUa6Mi0dAk5fMozLPxnueB7 7NTh5v5txFrPy4QPeBGmpnJa46tbcJ6UAYPI4RJ3Ksnj41HeQSe3xhpEvaHIVqkAj0Ig bG2eFVtN4y06P44jlLri49KWUgOodAeNa/sMXq/+CjflQQKNguWPANXIODURN7EwrKDY R90KyT+7YQMkMb0NaGQ2AY2QvrWmUxot/kKV04FtJwOuwQ8WRJk7c7Deq0Kh1UPkZgGO R/kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141377; x=1793746177; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=gIS2bnYzcbQkMxQgoekph5CH8vdF5nI/voXUkG5onsE=; b=IYFdcWIUTsHQHPedE7tdLoeKAOayKIPd5cPe1kQcANr0VcFg8cxAXZdpLXl13xtuBP iPGUCcwjUVehXYbTkmaOICMe/kaE4qsXGR/r14jge1hUHjgiAr/JujbIAFA3lqhSV0hx 2yjnwk3vKGDoXaOO5lc3Oni02YpGzb8wJBfuuRoHK9+o/dLh7WmmJu6v6p9RceaiPlIH j38iGbpHO1uL8jRN18fG95+mlJc4r0kOveK6TlsQ0qGSoNPfpNkC1H5vRqwGJrXgw5Oq WBMkuCTTn4jI2oTHC0Xiv4zj9GOTThml+SDboNAWGGWLSbogb73Q3llk49rx75K8Z6Is /rig== X-Gm-Message-State: AFq9FYLK7ZAC/s8doBpWtxWOZ0hgwiUG0RlZf/uVISgoLjbnOq4GEfPC DDzfFg5vXjV9zwG5yIy3uqJj6noq9cftjnneoaPet2rbWINBbIBWHBATBviUaw== X-Gm-Gg: AYBFou1qeqo/c9h59Zz3Lx+kR1iugkcHitF5Fh7PM/2i7pkbf4hN3j9uTDseObeGfRs qWHMv6GS2+YNUnVk2AX1ciPilp7e4XFIwKl7EcxWB8+QBsZkTakKwy5mIsxRLCQvmbZrgpDyHZn +UO1r85s3lV3DrCbatSzFWjBHyn3dbS+OzlQS234ohWO2PE91+PtgM0KIaA/Y3MBsOmxZTAi/rl d082N748zgMSKL3kOa4fwO1NoTwVT+sucCpTkuoSBlD3TSWRWazTiqqR0kQiXf5+jsZHSP3f5mH FkwGBCN404/0nYyb2wPXo6Ul5xgJjnuZehfPcueC2hf6s22BX84vKLQZqZb19sUgbH9wON5bZYh oEEOpx7AIJYlUEAIlCR5UDKrsUNYFUnuxT1Ei5v9ECyd3CBrrBQjOkhLdsXxiaRmPaDLwURUQfu zqp5n1u3qpuB2lPGFhxN69hIO1mHPxzyg6OTU3sIAPicyTW3LoY18g86pU4MBnVKWW5USmn2bLH JoS6Lm7OhY2pmFi1TY9wkvX4QgH5Mc4Ol9N6ebpkDBwHQck8IYXJYHoFJmLKcdnh/0lo05CFVM= X-Received: by 2002:a05:6871:5290:b0:4a8:15a:b062 with SMTP id 586e51a60fabf-4a8bb678929mr451579fac.25.1793141377182; Tue, 27 Oct 2026 15:49:37 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:36 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 1/7] spdx: Skip dependencies that are not in the taskhash Date: Tue, 27 Oct 2026 16:47:15 -0600 Message-ID: <20261027224931.385138-2-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:41 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248765 If a dependency is not in the taskhash, it cannot be included in the SPDX data because the dependency may not trigger the recipe to rebuild if it changes (although aliases help with this), but more importantly bitbake may not restore the sstate object associated with the dependency which causes errors when constructing the final SBoM Signed-off-by: Joshua Watt --- meta/lib/oe/spdx30_tasks.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index 1d11d8d1d2..3dd87c2a75 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -306,13 +306,14 @@ def collect_dep_objsets(d, direct_deps, subdir, fn_prefix, obj_type, **attr_filt dep_obj, dep_objset = oe.sbom30.find_root_obj_in_jsonld( d, subdir, fn_prefix + dep.pn, obj_type, **attr_filter ) - # If the dependency is part of the taskhash, return it to be linked - # against. Otherwise, it cannot be linked against because this recipe - # will not rebuilt if dependency changes - if dep.in_taskhash: - dep_objsets.append(dep_objset) + # If the dependency is not part of the task hash, do not include it + # since the dependency may not be present in subsequent runs, and may + # not rebuild if it changes + if not dep.in_taskhash: + bb.debug(1, f"Skipping dependency {dep.pn} (not in taskhash)") + continue - # The object _can_ be linked against (by alias) + dep_objsets.append(dep_objset) dep_objs.add(dep_obj) return dep_objsets, dep_objs From patchwork Tue Oct 27 22:47:16 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102157 Received: from mail-oa1-f48.google.com (mail-oa1-f48.google.com [209.85.160.48]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.31416.1793141379286936838 for ; Tue, 27 Oct 2026 15:49:39 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=xeWq3ESH; spf=pass (domain: gmail.com, ip: 209.85.160.48, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f48.google.com with SMTP id 586e51a60fabf-4877837890fso223505fac.2 for ; Tue, 27 Oct 2026 15:49:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141378; x=1793746178; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GkHE/er36Hqv89KTCOB7k6z8xrYAAh2+zMxhj+bKTYE=; b=xeWq3ESHnV8t8M20ALbQnwCX+jACvwKnXLGvVpUKnUZeb64kS6uo4OzhMokWcywGOA CfYYZIzQarUF/lcoUzfanBgBHiKAJCIcLt6TM+avnUGP7YVvXDyR3iX/yhoGgdIeiW1c Bwq38GcT3OyfkxeY6jdOdODuPizmUaZbRxrF7Pm/K8ESbO4S6pxoQ0BmZAjZ1zXRUT+r GjEkqVakGquf1XNhDw3naeRAnwO0F/UT4b4ZaTYGHrX7T8iRQrZD8JUGrfQfRxI4Auqn NydtNL3c21ghRodhTMxcf1GQVJr/qg3iyi6qTboLnWx8Eei0gHbCNvQVUUYsTHjfgD2/ HnyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141378; x=1793746178; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=GkHE/er36Hqv89KTCOB7k6z8xrYAAh2+zMxhj+bKTYE=; b=NC7/QnVollljvj11+H6DnmXfj3UooDJNCWlS1XtmuKGKC1pnBl/inozZpIZrUOCWnO MYcSBR986gfctyI2M9yAD6YAoy3RJUonfhTwq+hwPJFtz/3r551sbl3x7s1StfBEn8to TgSibpa6nV6d2mzH24FrFxEsfTvhTTwzfwM9BBzGv3v11ugxGFLcsHwX70r4vkxMniYk aK8UVaJc+xeFSMLC7QSnxd8imlQzodCOsPTaNfbrysV84knrWjyJMoWv6sqQlScrq+tO E5NUlIRvg08M2PhQH1l3zIO/JoPmetq1w1kLoASLpoWdQx+etwQ2WJkUxrghUFoLG6iN z1Ew== X-Gm-Message-State: AFq9FYIogmTSQHnFwdhC2CFoSdgvNmsvqPpB+La1T72Dd6yJmLjZubr+ hGUvoM0kR80K+HjuPZd6O74rJLTDhWt3PSiIoWaUnYM7mJJCSzhCUwpb7JiZLA== X-Gm-Gg: AYBFou3GOjIFOhTshSstTJB+/32TaO/wJzOqrFNX8fPV7Bp/UVo1tqw5ODf41jrOjMX r4SRnK6bbQqnCo91JwAwMsqCe+2T/Jjll8ejHdb6cHHa6h082wOXMUo9UF6c0JtPw5HpeIlKVWX okc5AiO+MBQYl/5eCzedwJGbB0GNyTJc1HRktZxRxNAWFSH33Fnwc61D7VlfIC6X91/YxpyfuGH wTz4mcAd7gwJfij3cVv+BCdPJJ4pKgdyD0Trlm51MjT/2LJbF8GfDFr4DBEJfytVbsFuuIYOmXx V6pMiwX2e8xm9jpVaOAUu0rUb7sU5JV6OBwQuWMvx4L9HyjyKTujojLXGktn+qebRsaQ+dk4Fwb P6BN3zwJaYR3k3dioVGh38fNHm+xeFp2gm6QPp7e7VOfq13KsAMtsJ916bftlG4RsmQ6VeS58SD w5BdQ0fko3qULjkZzTpatcDLjam9cmmHBU6ESK5Q4zzS2irmd2POr0nTJA0P0JXP+HGGVKYrdMJ cg9a/16N9Mf1Br2JkiZkGpaIAE0HY2cqgaD/b1gvqJ4YcpeihpiTqgVQP4IEMk5RvS80hhyfdc= X-Received: by 2002:a05:6870:d8d4:b0:48f:e0e5:a1e3 with SMTP id 586e51a60fabf-4a8bb57e86fmr710213fac.40.1793141378213; Tue, 27 Oct 2026 15:49:38 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:37 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 2/7] spdx: Add ability for deploy tasks to create SPDX Date: Tue, 27 Oct 2026 16:47:16 -0600 Message-ID: <20261027224931.385138-3-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:41 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248766 Adds support for "deploy" tasks (like do_deploy) to write out SPDX documents that describe what has been deployed. Deploy tasks will automatically detect many dependencies on other recipes; specifically they will correctly detect dependencies on any do_create_spdx task, and also other deploy tasks that generate SPDX output. The only known notable exception are transitive (e.g. originating from other upstream tasks) dependencies on do_image_complete, and do_populate_sysroot. However, these are detected if a direct dependency of the deploy task (via translation of the task dependencies). This same dependency finding algorithm is now applied to the image generation SBoM; this means that if an image creation task depends on a task that generates a deploy SBoM, it will show up in the dependency graph of the image. A typical example is a wic file that consumes the kernel, u-boot, etc. will now correctly list those as a dependency, as long as their do_deploy step is added to SPDX_DEPLOY_TASKS. Signed-off-by: Joshua Watt --- .../create-spdx-image-3.0.bbclass | 4 +- meta/classes-recipe/deploy.bbclass | 1 + meta/classes-recipe/nospdx.bbclass | 1 + meta/classes/create-spdx-3.0.bbclass | 181 +++++++++++ meta/classes/spdx-common.bbclass | 1 + meta/lib/oe/sbom30.py | 46 +-- meta/lib/oe/spdx30_tasks.py | 282 +++++++++++++++--- meta/lib/oe/spdx_common.py | 2 +- 8 files changed, 453 insertions(+), 65 deletions(-) diff --git a/meta/classes-recipe/create-spdx-image-3.0.bbclass b/meta/classes-recipe/create-spdx-image-3.0.bbclass index cf79ef5b01..b60cdd826f 100644 --- a/meta/classes-recipe/create-spdx-image-3.0.bbclass +++ b/meta/classes-recipe/create-spdx-image-3.0.bbclass @@ -30,7 +30,7 @@ python do_create_rootfs_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_rootfs_spdx(d) } -addtask do_create_rootfs_spdx after do_rootfs before do_image +addtask do_create_rootfs_spdx after do_rootfs do_create_recipe_spdx before do_image SSTATETASKS += "do_create_rootfs_spdx" do_create_rootfs_spdx[sstate-inputdirs] = "${SPDXROOTFSDEPLOY}" do_create_rootfs_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" @@ -47,7 +47,7 @@ python do_create_image_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_image_spdx(d) } -addtask do_create_image_spdx after do_image_complete do_create_rootfs_spdx before do_build +addtask do_create_image_spdx after do_image_complete do_create_rootfs_spdx do_create_recipe_spdx before do_build SSTATETASKS += "do_create_image_spdx" SSTATE_SKIP_CREATION:task-create-image-spdx = "1" do_create_image_spdx[sstate-inputdirs] = "${SPDXIMAGEWORK}" diff --git a/meta/classes-recipe/deploy.bbclass b/meta/classes-recipe/deploy.bbclass index f56fe98d6d..f222a8560f 100644 --- a/meta/classes-recipe/deploy.bbclass +++ b/meta/classes-recipe/deploy.bbclass @@ -6,6 +6,7 @@ DEPLOYDIR = "${WORKDIR}/deploy-${PN}" SSTATETASKS += "do_deploy" +SPDX_DEPLOY_ARTIFACTS_DIR:task-deploy = "${DEPLOYDIR}" do_deploy[sstate-inputdirs] = "${DEPLOYDIR}" do_deploy[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" diff --git a/meta/classes-recipe/nospdx.bbclass b/meta/classes-recipe/nospdx.bbclass index 6ccb93ba01..723194da2d 100644 --- a/meta/classes-recipe/nospdx.bbclass +++ b/meta/classes-recipe/nospdx.bbclass @@ -12,3 +12,4 @@ deltask do_create_package_spdx deltask do_create_rootfs_spdx deltask do_create_image_spdx deltask do_create_image_sbom_spdx +deltask do_create_deploy_sbom diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 6d47aa1301..6077105094 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -163,6 +163,49 @@ SPDX_GIT_PURL_MAPPINGS[doc] = "A space separated list of domain:purl_type \ on gitlab.example.com to the pkg:gitlab PURL type. \ github.com is always mapped to pkg:github by default." +SPDX_DEPLOY_TASKS ?= "" +SPDX_DEPLOY_TASKS[doc] = "A space separated list of sstate tasks that produce \ + deployed output (usually written to DEPLOY_DIR_IMAGE). Tasks in this list \ + will produce SPDX documents that describe the deployed output. Items in \ + list have the format 'TASK(:FUNCTION)' where 'TASK' is the sstate task \ + (which must start with 'do_deploy'), and 'FUNCTION' is the optional \ + function to call to produce the deploy SPDX. If 'FUNCTION' is omitted \ + a default function is provided that uses SPDX_DEPLOY_ARTIFACTS and \ + SPDX_DEPLOY_ARTIFACTS_DIR to configure what deploy artifacts it describes \ + in the SPDX output.\ + \ + Dependencies of deploy tasks that produce SPDX data will be automatically \ + linked in as a build time dependency of the deploy task's SBoM. (for \ + example, if one do_deploy depends on another recipes do_deploy, this will \ + be reflected in the SPDX data)." + +SPDX_DEPLOY_SBOM ??= "1" +SPDX_DEPLOY_SBOM[doc] = "If '1' (the default) a task named \ + do_create_deploy_sbom will be created to automatically collect all deploy \ + SPDX documents (from SPDX_DEPLOY_TASKS) and combine them into a SBoM \ + which will be placed in DEPLOY_DIR_IMAGE. This task is added as a \ + dependency of do_build, so it will run whenever the recipe is built \ + directly. The name of the document can be set with SPDX_DEPLOY_SBOM_NAME. \ + If the recipe already has another task to create an SBoM, this should be \ + set to '0' to prevent multiple SBoMs from being created." + +SPDX_DEPLOY_SBOM_NAME ?= "${PN}-deploy-sbom" +SPDX_DEPLOY_SBOM_NAME[doc] = "The name of the output deploy SBoM when using \ + create_deploy_sbom" + +SPDX_DEPLOY_ARTIFACTS = "AUTO" +SPDX_DEPLOY_ARITFACTS[doc] = "A space separated list of deployed artifacts, \ + relative to SPDX_DEPLOY_ARTIFACTS_DIR that should be included in the SBoM. \ + If 'AUTO' (the default), all files in SPDX_DEPLOY_ARITFACTS_DIR will be \ + added. A :task- override *must* be used to set this value so that it is \ + scoped to a specific task" + +SPDX_DEPLOY_ARTIFACTS_DIR = "" +SPDX_DEPLOY_ARTIFACTS_DIR[doc] = "The directory recipe specific directory \ + where artifacts are deployed for staging to sstate (e.g. for do_deploy, \ + this is DEPLOY_DIR). A :task- override *must* be used to set this value so \ + that it is scoped to a specific task." + IMAGE_CLASSES:append = " create-spdx-image-3.0" SDK_CLASSES += "create-spdx-sdk-3.0" @@ -293,3 +336,141 @@ python spdx30_build_started_handler () { addhandler spdx30_build_started_handler spdx30_build_started_handler[eventmask] = "bb.event.BuildStarted" +python create_deploy_spdx() { + import oe.spdx30_tasks + from pathlib import Path + current_task = "do_" + d.getVar("BB_CURRENTTASK") + + spdxdeploydir = Path(d.getVar("SPDXDIR") + "/deploy-" + current_task) + + artifactsdir = d.getVar("SPDX_DEPLOY_ARTIFACTS_DIR") + if not artifactsdir: + bb.fatal(f"{pn}: spdx-artifactsdir must be set for task {current_task}") + return + + artifacts = d.getVar("SPDX_DEPLOY_ARTIFACTS") + + oe.spdx30_tasks.create_deploy_spdx(d, spdxdeploydir, artifactsdir, artifacts) +} +oe.spdx30_tasks.find_build_dep_objsets[vardepsexclude] += "BB_TASKDEPDATA" + +python () { + # Most recipes generate SPDX output in a distinct task from the task that + # actually is the relevant dependency. As such, we need to map the task + # that we care about to the task that generates the corresponding SPDX + # output so that we can rely on the SPDX output being present when the time + # comes to use it downstream. + # + # The down side of this is that only the first level of dependencies (e.g + # tasks listed in SPDX_DEPLOY_TASKS) will have the mapping done and thus + # find the dependencies. Transitive dependencies will not be mapped and + # thus the SPDX data will not be linked in. + # + # Ideally, this will be able to go away once more tasks directly generate + # SPDX files for their output instead of combining it into monolithic + # functions; tasks listed in this map are the best candidates to have this + # done first. + TASK_MAP = { + # If a task requires the RSS be extended, depend on the SPDX build task + # for the recipe, at least until it's possible for do_populate_sysroot + # to describe it's own output. + "do_populate_sysroot": "do_create_spdx", + # If an image is needed, also depend on the task to create the SBoM for + # the image + "do_image_complete": "do_create_image_spdx", + } + + def map_task_deps(task, flag): + task_flags= (d.getVarFlag(task, flag) or "").split() + for t in task_flags: + if t in TASK_MAP and TASK_MAP[t] not in task_flags: + d.appendVarFlag(task, flag, f" {TASK_MAP[t]}") + + def before_postfunc(f): + return f == "sstate_task_postfunc" or "buildhistory" in f + + if bb.data.inherits_class("nospdx", d): + return + + sstate_tasks = set((d.getVar("SSTATETASKS") or "").split()) + deploy_sbom_tasks = [] + for task in (d.getVar("SPDX_DEPLOY_TASKS") or "").split(): + if ":" in task: + task, func = task.split(":") + else: + func = "create_deploy_spdx" + + if not task.startswith("do_deploy") and not task == "do_image_complete": + bb.fatal(f"Task {task} is not allowed to deploy SPDX data. Must start with 'do_deploy'") + + deploy_sbom_tasks.append(task) + + if task not in sstate_tasks: + bb.fatal(f"{task} is not an sstate task") + + spdx_deploy = "${SPDXDIR}/deploy-" + task + + # Ensure function is sorted properly. It should be right before + # sstate_task_postfunc + postfuncs = (d.getVarFlag(task, "postfuncs") or "").split() + + new_postfuncs = [] + while True: + if not postfuncs or before_postfunc(postfuncs[0]): + break + new_postfuncs.append(postfuncs.pop(0)) + new_postfuncs.append(func) + new_postfuncs.extend(postfuncs) + + d.setVarFlag(task, "postfuncs", " ".join(new_postfuncs)) + d.prependVarFlag(task, "sstate-inputdirs", f"{spdx_deploy} ") + d.prependVarFlag(task, "sstate-outputdirs", "${DEPLOY_DIR_SPDX} ") + d.prependVarFlag(task, "file-checksums", "${SPDX3_DEP_FILES} ") + d.prependVarFlag(task, "dirs", f"{spdx_deploy} ") + d.prependVarFlag(task, "cleandirs", f"{spdx_deploy} ") + + deps = (d.getVarFlag(task, "depends") or "").split() + extra_deps = ["${PN}:do_create_recipe_spdx", "${PN}:do_create_spdx"] + for dep in deps: + _, fn, taskname = bb.runqueue.split_tid(dep) + if taskname in TASK_MAP: + extra_deps.append(f"{fn}:{TASK_MAP[taskname]}") + + d.prependVarFlag(task, "depends", " ".join(extra_deps) + " ") + + map_task_deps(task, "deptask") + map_task_deps(task, "rdeptask") + map_task_deps(task, "recrdeptask") + + # For now, if a recipe is directly built, deploy all of it's deploy tasks + # into a single SBoM. We may need an option in the future to have tasks + # that don't do this (e.g. because they do not deploy to a location that is + # intended to be consumed by the user) + if deploy_sbom_tasks and (d.getVar("SPDX_DEPLOY_SBOM") or "") == "1": + bb.build.addtask("do_create_deploy_sbom", "do_build", " ".join(deploy_sbom_tasks), d) +} + +python do_create_deploy_sbom() { + import oe.spdx30_tasks + from pathlib import Path + deploydir = Path(d.getVar("SPDXDEPLOYSBOMDEPLOY")) + deploy_tasks = [] + for task in (d.getVar("SPDX_DEPLOY_TASKS") or "").split(): + if ":" in task: + task, _ = task.split(":") + deploy_tasks.append(task) + + oe.spdx30_tasks.create_deploy_sbom(d, deploydir, deploy_tasks) +} +do_create_deploy_sbom[sstate-inputdirs] = "${SPDXDEPLOYSBOMDEPLOY}" +do_create_deploy_sbom[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" +do_create_deploy_sbom[recrdeptask] += "do_create_recipe_spdx do_create_spdx" +do_create_deploy_sbom[cleandirs] += "${SPDXDEPLOYSBOMDEPLOY}" +do_create_deploy_sbom[file-checksums] += "${SPDX3_DEP_FILES}" + +SSTATETASKS += "do_create_deploy_sbom" +python do_create_deploy_sbom_setscene() { + sstate_setscene(d) +} +addtask do_create_deploy_sbom_setscene +SSTATE_SKIP_CREATION:task-create-deploy-sbom = "1" diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index 40701730a6..bca169670d 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -26,6 +26,7 @@ SPDX_TOOL_VERSION ??= "1.0" SPDXRECIPEDEPLOY = "${SPDXDIR}/recipe-deploy" SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" SPDXRECIPESBOMDEPLOY = "${SPDXDIR}/recipes-bom-deploy" +SPDXDEPLOYSBOMDEPLOY = "${SPDXDIR}/deploy-bom-deploy" SPDX_INCLUDE_SOURCES ??= "0" SPDX_INCLUDE_SOURCES[doc] = "If set to '1', include source code files in the \ diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py index b33860e4aa..2d3b54069c 100644 --- a/meta/lib/oe/sbom30.py +++ b/meta/lib/oe/sbom30.py @@ -1054,6 +1054,25 @@ def write_jsonld_doc(d, objset, dest): objset.objects.remove(objset.doc) +def make_jsonld_link(d, fn, subdir, name, deploydir): + pkg_arch = d.getVar("SSTATE_PKGARCH") + + link_name = jsonld_arch_path( + d, + pkg_arch, + subdir, + name, + deploydir=deploydir, + ) + try: + link_name.parent.mkdir(exist_ok=True, parents=True) + link_name.symlink_to(os.path.relpath(fn, link_name.parent)) + except: + target = link_name.readlink() + bb.warn(f"Unable to link {fn} as {link_name}. Already points to {target}") + raise + + def write_recipe_jsonld_doc( d, objset, @@ -1061,6 +1080,7 @@ def write_recipe_jsonld_doc( deploydir, *, create_spdx_id_links=True, + create_task_link=False, ): pkg_arch = d.getVar("SSTATE_PKGARCH") @@ -1068,23 +1088,7 @@ def write_recipe_jsonld_doc( def link_id(_id): hash_path = jsonld_hash_path(hash_id(_id)) - - link_name = jsonld_arch_path( - d, - pkg_arch, - *hash_path, - deploydir=deploydir, - ) - try: - link_name.parent.mkdir(exist_ok=True, parents=True) - link_name.symlink_to(os.path.relpath(dest, link_name.parent)) - except: - target = link_name.readlink() - bb.warn( - f"Unable to link {_id} in {dest} as {link_name}. Already points to {target}" - ) - raise - + make_jsonld_link(d, dest, *hash_path, deploydir) return hash_path[-1] objset.add_aliases() @@ -1100,6 +1104,14 @@ def write_recipe_jsonld_doc( # out, so always do that even if there is an error making the links write_jsonld_doc(d, objset, dest) + if create_task_link: + pn = d.getVar("PN") + current_task = "do_" + d.getVar("BB_CURRENTTASK") + + make_jsonld_link(d, dest, "by-task", f"{pn}:{current_task}", deploydir) + + return dest + def find_root_obj_in_jsonld(d, subdir, fn_name, obj_type, **attr_filter): objset, fn = find_jsonld(d, subdir, fn_name, required=True) diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index 3dd87c2a75..c1c0733508 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -598,6 +598,135 @@ def get_is_native(d): return bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d) +def set_var_field(d, var, obj, name, package=None): + val = None + if package: + val = d.getVar("%s:%s" % (var, package)) + + if not val: + val = d.getVar(var) + + if val: + setattr(obj, name, val) + + +def find_build_dep_objsets(d, start_task): + def find_deps(d, taskdepdata, current_dep, start_dep, visited, depth=0): + key = f"{current_dep.pn}:{current_dep.taskname}" + + dep_objsets = [] + + if key not in visited: + visited.add(key) + + for n in current_dep.deps: + dep = taskdepdata[n] + dep_name = f"{dep.pn}:{dep.taskname}" + + dep_objset, dep_path = oe.sbom30.find_jsonld(d, "by-task", dep_name) + if dep_objset: + dep_objsets.append(dep_objset) + + elif dep.pn == start_dep.pn: + # If this task is still part of the same recipe, continue + # searching up the dependency tree until a valid dependency + # is found. This detects transitive dependencies that may + # have been pulled in by previous tasks in the same recipe. + dep_objsets.extend( + find_deps(d, taskdepdata, dep, start_dep, visited, depth + 1) + ) + + return dep_objsets + + pn = d.getVar("PN") + taskdepdata = d.getVar("BB_TASKDEPDATA", False) + for dep in taskdepdata.values(): + if dep.pn == pn and dep.taskname == start_task: + start_dep = dep + break + else: + bb.fatal(f"Unable to find {pn}:{start_task} in taskdepdata") + + return find_deps(d, taskdepdata, start_dep, start_dep, set()) + + +def create_deploy_package(d, objset, build, spdxid, name, start_task, files, **attrs): + recipe, _ = load_recipe_spdx(d) + + deploy_package = objset.add_root( + oe.spdx30.software_Package( + _id=spdxid, + creationInfo=objset.doc.creationInfo, + name=name, + software_packageVersion=d.getVar("PV"), + ) + ) + + objset.new_scoped_relationship( + [oe.sbom30.get_element_link_id(recipe)], + oe.spdx30.RelationshipType.generates, + oe.spdx30.LifecycleScopeType.build, + [deploy_package], + ) + + set_var_field(d, "HOMEPAGE", deploy_package, "software_homePage") + set_var_field(d, "SUMMARY", deploy_package, "summary") + set_var_field(d, "DESCRIPTION", deploy_package, "description") + + set_purls(deploy_package, (d.getVar("SPDX_PACKAGE_URLS") or "").split()) + + set_timestamp_now(d, deploy_package, "builtTime") + + supplier = objset.new_agent("SPDX_PACKAGE_SUPPLIER") + if supplier is not None: + deploy_package.suppliedBy = ( + supplier if isinstance(supplier, str) else supplier._id + ) + + if files: + objset.new_relationship( + [deploy_package], + oe.spdx30.RelationshipType.contains, + sorted(list(files)), + ) + + objset.new_scoped_relationship( + [build], + oe.spdx30.RelationshipType.hasOutput, + oe.spdx30.LifecycleScopeType.build, + sorted(list(files) + [deploy_package]), + ) + + # Collect dependencies + if start_task is not None: + dep_builds = set() + dep_packages = set() + for o in find_build_dep_objsets(d, start_task): + if obj := o.find_root(oe.spdx30.software_Package): + dep_packages.add(oe.sbom30.get_element_link_id(obj)) + + if obj := o.find_root(oe.spdx30.build_Build): + dep_builds.add(oe.sbom30.get_element_link_id(obj)) + + if dep_packages: + objset.new_scoped_relationship( + [deploy_package], + oe.spdx30.RelationshipType.dependsOn, + oe.spdx30.LifecycleScopeType.build, + sorted(list(dep_packages)), + ) + + if dep_builds: + objset.new_scoped_relationship( + [build], + oe.spdx30.RelationshipType.dependsOn, + oe.spdx30.LifecycleScopeType.build, + sorted(list(dep_builds)), + ) + + return deploy_package + + def create_recipe_spdx(d): deploydir = Path(d.getVar("SPDXRECIPEDEPLOY")) pn = d.getVar("PN") @@ -790,7 +919,9 @@ def create_recipe_spdx(d): sorted(list(all_cves)), ) - oe.sbom30.write_recipe_jsonld_doc(d, recipe_objset, "static", deploydir) + oe.sbom30.write_recipe_jsonld_doc( + d, recipe_objset, "static", deploydir, create_task_link=True + ) def load_recipe_spdx(d): @@ -804,17 +935,6 @@ def load_recipe_spdx(d): def create_spdx(d): - def set_var_field(var, obj, name, package=None): - val = None - if package: - val = d.getVar("%s:%s" % (var, package)) - - if not val: - val = d.getVar(var) - - if val: - setattr(obj, name, val) - license_data = oe.spdx_common.load_spdx_license_data(d) pn = d.getVar("PN") @@ -943,10 +1063,12 @@ def create_spdx(d): ) set_var_field( - "HOMEPAGE", spdx_package, "software_homePage", package=package + d, "HOMEPAGE", spdx_package, "software_homePage", package=package + ) + set_var_field(d, "SUMMARY", spdx_package, "summary", package=package) + set_var_field( + d, "DESCRIPTION", spdx_package, "description", package=package ) - set_var_field("SUMMARY", spdx_package, "summary", package=package) - set_var_field("DESCRIPTION", spdx_package, "description", package=package) purls = ( d.getVar("SPDX_PACKAGE_URLS:%s" % package) @@ -1133,7 +1255,9 @@ def create_spdx(d): f"Added PACKAGECONFIG entries: {len(enabled)} enabled, {len(disabled)} disabled" ) - oe.sbom30.write_recipe_jsonld_doc(d, build_objset, "builds", deploydir) + oe.sbom30.write_recipe_jsonld_doc( + d, build_objset, "builds", deploydir, create_task_link=True + ) def create_package_spdx(d): @@ -1369,26 +1493,9 @@ def create_rootfs_spdx(d): d, "%s-%s-rootfs" % (image_basename, machine) ) - rootfs = objset.add_root( - oe.spdx30.software_Package( - _id=objset.new_spdxid("rootfs", image_basename), - creationInfo=objset.doc.creationInfo, - name=image_basename, - software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.archive, - ) - ) - set_timestamp_now(d, rootfs, "builtTime") - rootfs_build = objset.add_root(objset.new_task_build("rootfs", "rootfs")) set_timestamp_now(d, rootfs_build, "build_buildEndTime") - objset.new_scoped_relationship( - [rootfs_build], - oe.spdx30.RelationshipType.hasOutput, - oe.spdx30.LifecycleScopeType.build, - [rootfs], - ) - files_by_hash = {} collect_build_package_inputs(d, objset, rootfs_build, packages, files_by_hash) @@ -1421,14 +1528,20 @@ def create_rootfs_spdx(d): ) ) - if files: - objset.new_relationship( - [rootfs], - oe.spdx30.RelationshipType.contains, - sorted(list(files)), - ) + rootfs = create_deploy_package( + d, + objset, + rootfs_build, + objset.new_spdxid("rootfs", image_basename), + image_basename, + None, + files, + ) + rootfs.software_primaryPurpose = oe.spdx30.software_SoftwarePurpose.archive - oe.sbom30.write_recipe_jsonld_doc(d, objset, "rootfs", deploydir) + oe.sbom30.write_recipe_jsonld_doc( + d, objset, "rootfs", deploydir, create_task_link=True + ) def create_image_spdx(d): @@ -1508,10 +1621,13 @@ def create_image_spdx(d): set_timestamp_now(d, a, "builtTime") if artifacts: - objset.new_scoped_relationship( - [image_build], - oe.spdx30.RelationshipType.hasOutput, - oe.spdx30.LifecycleScopeType.build, + create_deploy_package( + d, + objset, + image_build, + objset.new_spdxid(taskname, "image", imagetype), + "image", + f"do_{taskname}", artifacts, ) @@ -1532,7 +1648,9 @@ def create_image_spdx(d): objset.add_aliases() objset.link() - oe.sbom30.write_recipe_jsonld_doc(d, objset, "image", spdx_work_dir) + oe.sbom30.write_recipe_jsonld_doc( + d, objset, "image", spdx_work_dir, create_task_link=True + ) def create_image_sbom_spdx(d): @@ -1710,3 +1828,77 @@ def create_recipe_sbom(d, deploydir): objset, sbom = oe.sbom30.create_sbom(d, sbom_name, [recipe], [recipe_objset]) oe.sbom30.write_jsonld_doc(d, objset, deploydir / (sbom_name + ".spdx.json")) + + +def create_deploy_spdx(d, spdxdeploydir, artifactsdir, artifacts): + pn = d.getVar("PN") + current_task = "do_" + d.getVar("BB_CURRENTTASK") + + recipe, recipe_objset = load_recipe_spdx(d) + + if artifacts == "AUTO": + artifacts = [] + for root, dirs, files in os.walk(artifactsdir): + for p in [Path(os.path.join(root, f)) for f in files]: + if p.is_file(): + artifacts.append(p) + else: + artifacts = [artifactsdir / p for p in artifacts.split()] + + artifacts.sort(key=lambda p: (p.is_symlink(), p)) + + objset = oe.sbom30.ObjectSet.new_objset(d, f"{pn}-{current_task}-deploy") + + build = objset.add_root(objset.new_task_build(current_task, "deploy")) + set_timestamp_now(d, build, "build_buildEndTime") + objset.set_is_native(get_is_native(d)) + + files = set() + for a in artifacts: + relpath = a.relative_to(artifactsdir) + f = objset.new_file( + objset.new_spdxid("deploy", str(relpath)), + a.name, + a, + ) + files.add(f) + + if not files: + bb.fatal(f"No deployed artifacts found in {artifactsdir}") + return + + create_deploy_package( + d, + objset, + build, + objset.new_spdxid("deploy", pn, current_task), + pn, + current_task, + files, + ) + + # Create document + dest = oe.sbom30.write_recipe_jsonld_doc( + d, + objset, + "deploy", + spdxdeploydir, + create_task_link=True, + ) + + +def create_deploy_sbom(d, deploydir, deploy_tasks): + pn = d.getVar("PN") + sbom_name = d.getVar("SPDX_DEPLOY_SBOM_NAME") + + objsets = [] + for t in deploy_tasks: + o, _ = oe.sbom30.find_jsonld(d, "deploy", f"{pn}-{t}-deploy", required=True) + objsets.append(o) + + root_objs = [] + for o in objsets: + root_objs.extend(o.doc.rootElement) + + objset, sbom = oe.sbom30.create_sbom(d, sbom_name, root_objs, objsets) + oe.sbom30.write_jsonld_doc(d, objset, deploydir / (sbom_name + ".spdx.json")) diff --git a/meta/lib/oe/spdx_common.py b/meta/lib/oe/spdx_common.py index 07bf9650e2..9a862d9f5a 100644 --- a/meta/lib/oe/spdx_common.py +++ b/meta/lib/oe/spdx_common.py @@ -118,7 +118,7 @@ def collect_direct_deps(d, dep_task): ) for this_dep in taskdepdata.values(): - if this_dep[0] == pn and this_dep[1] == current_task: + if this_dep.pn == pn and this_dep.taskname == current_task: break else: bb.fatal(f"Unable to find this {pn}:{current_task} in taskdepdata") From patchwork Tue Oct 27 22:47:17 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102158 Received: from mail-oa1-f44.google.com (mail-oa1-f44.google.com [209.85.160.44]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.31417.1793141379779390106 for ; Tue, 27 Oct 2026 15:49:39 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=aG/yRyGE; spf=pass (domain: gmail.com, ip: 209.85.160.44, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f44.google.com with SMTP id 586e51a60fabf-49ddddefadbso186169fac.1 for ; Tue, 27 Oct 2026 15:49:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141379; x=1793746179; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Z1y3RBDJoDIw4KgYSPBJM4umu5zeYQMe7A/eNaaMe0w=; b=aG/yRyGEBoAN7y7OdI9F/R7Spj0sUEQ0cFwaY88YCM5AFH5qzmKRmvabYBRfwe/FtK W+8jvTLDXRM+T6LZbT9eh9JA5XNmzFThGF1ARpCKxqqmDTATE/m9Nk4eB6csyHG+69kP 1Hn7bjYX4T/I6/OvGPMkLXFW3SsVbgxuWZF7W7kXPLYTD7C4udkWcx/OHZoHWXZVdhYn QRO8Vn5QhD6mICjDVvhQRk09ymYKBAeeRQ0zO4OIpvo9clJPhywQq5ma2bggZl2rtXOL g/rL+9J1i4BoAgY7oqemvjnD1xg10OtxjmwTqdpZwoWBhL+TmK/BCesUrVnCgfSMGO3S ivOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141379; x=1793746179; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Z1y3RBDJoDIw4KgYSPBJM4umu5zeYQMe7A/eNaaMe0w=; b=lxEIlzuRgEY+lRR4UchBZNEoica5Zzp9xW3eE6BG2NeuFA7BSgqacKD/CjyTRxnJ1e v+sTQlFG+hWVDohZ24k8UAq/n9+XTqlnHM8g4cTO+h9IS4hIOP0IVjTR6gRbrknL3bS3 dLlLGwk0LRSdcqTN1Qp2GyVf9GbUWus8m68KWa6o2qig0IT1RyFT/gkMR2kFVh64Ih8p p4/HnuM09EHkvSXILhxt86P/HNDwSLmSXGQNecQ0ok16GY8SMeCAq5dRWYrWZUZ5ltVV zkWK6hT92EfntNBz2cgc1FehfSY5GZ8GPpqWBSnlbGrWvMQFlkBgzGEOTUAEhWQeKlYk smWA== X-Gm-Message-State: AFq9FYIkxZCch2qojW62TcjHOcXP+R2NBO0c2AGQqqFNGgP8VQ9gvkGI plQaoHJwezHPDkLDqhv9RQtTCDk4cDT7l+7INvD73z7IJpmeNS+3olf3cadKKQ== X-Gm-Gg: AYBFou1iSnXSYOF1F/br501F223VGffwVstggeysy27moWplbmdACgvz8ITOOJeFDgh a1WJe5qqXh0aqO7lVLDCIA5sAnGjcvKCTSwdUsI57jeoOVrwKs8xLe45jZuBvvZdkEkNGaJwmR7 PCm34if6A4vSeaW7l9U+hL+Cma2IG6bWoQp4ujXF31VTC5KV0JadLZ4HYVgE4Jy5/Oe2kF9aBNW 9GlH350HpyOYlSmqA2F0+RSKwcKIxUVm/+oR7oWNnDR0ZDO8sjixv+hP9Qgg/k40+nbt3NyFOQw VoT82JPJ6FmGwZI5Yz0goy9aQXEzo9bfIGYSj+qmLDjmavyZFW6Ib+p+m8E/KJ7PGprn6HLbi+5 1c7pcGbLH2LtOlb41Vj0f+Z3llAbXeD3M+AjjkOZzM+CdUtsTLXliWcU4ihpKy/+df16XABGT+H uJvsyJXUl7T8lPMGHRL9hdlRZ26bQDwox+3JexZSr95E9WNkRx4f2YgfQyZaAUM9IoD6WYtDjbQ cmGVkS96GfF93LnDj4BevcVQW2XdOu9eJ4oCEy0ZVpytM6QniqmlA== X-Received: by 2002:a05:6870:3345:b0:491:8db3:58bf with SMTP id 586e51a60fabf-4a8bb1963a5mr793878fac.8.1793141378986; Tue, 27 Oct 2026 15:49:38 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:38 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 3/7] oeqa: Add SPDX deploy SBoM test Date: Tue, 27 Oct 2026 16:47:17 -0600 Message-ID: <20261027224931.385138-4-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248767 Adds a test that verifies that the deploy SBoM is created correctly Signed-off-by: Joshua Watt --- meta/lib/oeqa/selftest/cases/spdx.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index c900558b44..8cc51c1369 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -485,3 +485,14 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): for candidate in objset.foreach_type(oe.spdx30.software_Package): self.assertIsNone(candidate.releaseTime) + + def test_deploy_sbom(self): + kernel_recipe = get_bb_var("PREFERRED_PROVIDER_virtual/kernel") + + objset = self.check_recipe_spdx( + "virtual/kernel", + f"{{DEPLOY_DIR_IMAGE}}/{kernel_recipe}-deploy-sbom.spdx.json", + ) + + # Document should be fully linked + self.check_objset_missing_ids(objset) From patchwork Tue Oct 27 22:47:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102159 Received: from mail-oa1-f43.google.com (mail-oa1-f43.google.com [209.85.160.43]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.31418.1793141381112697572 for ; Tue, 27 Oct 2026 15:49:41 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=ir2+Gd3j; spf=pass (domain: gmail.com, ip: 209.85.160.43, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f43.google.com with SMTP id 586e51a60fabf-48e94879f02so162170fac.0 for ; Tue, 27 Oct 2026 15:49:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141380; x=1793746180; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/2WIZpwPimqavDkzbT1ZpVYufGFe+CtcAal/HZACf5Y=; b=ir2+Gd3j7VjarNwM/F3cRdYS4237+FrolDI45vPbzamB/WFR5WMuvYZg+cIITGUSIE EKt1couVukjqlUAwd03zRI5ag+tkVnWw+vXL3et3ED8CIUChviS3+KQk9cywR8jvpJze MoE2JP7/PGjwY0AA92tzELLcW7syqwXVpuAN+k9D1Af88sgSeaxBLJlzMLlI8QYloU/9 1hk4+zMBo3ocHtI6k8SryiQc6ChHSRn9CWmzmXP4b0UOFaHK3bKV64coTi+/tQGOyRng 99e/q62TJafBtd9kbi7Abz6dRKKt5SQxFRhT/VZMrdZ2RN78XlR+MOwws4YMVPiUCqi+ xNNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141380; x=1793746180; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=/2WIZpwPimqavDkzbT1ZpVYufGFe+CtcAal/HZACf5Y=; b=i8olxYF4InCCOSxeigUehn1zSo+YAItN9pNjSHYKLdL9CLkbNMojhRLmhCrJhNiiur 3yjyop+sqFWKdGEKDmKffoq58jpBZI8lMBxB5F/A2tWhHrX6xrzbnEARFvRlP+1BdU/1 FvHK+6LM+XH8Bah60pWhZbNf+zIMatTaIa4pl4LD/GKJOZltyLdqu6oGQC0muvinByZF 1xPNeT7G/EPcBGExLrlbMXu3c1yTXHxVF4AgYSFBysPGbzP0V+dj9tVsALBUegDAVWgJ s2Sqcyb/E6ounws9ZN4VsaZONLisjrbiCgsvkdEmi+kWld2CGULiuv4jUb2IqJNJ1ICi nx4A== X-Gm-Message-State: AFq9FYJ3y9r8pofABbLY4wp3QJTTysytz3YucNT+rlB5Bdk84vHVrvHc hy2v0M9qy4adLsDcChs+mXJ2mnap4yRzwkgJv27JVXeFwHm8Zz8Cvl0lf5aqkg== X-Gm-Gg: AYBFou1JfZK8Ez/vvjjNDG9xGxysfAVc+3jrTMFYVmVT2zdfMSqtA8JvV8PiLfxPK58 9Xte8peAxNpVBNX3nxWVbw2CY8x2e/A7VoRoBfzlvC1pGcxrzn/EsJZ85PVadyc/RGM3b9WTbS8 CytxN0AKhvNofQbWD1kc0uiU+wH6CJS0cO+FzUDxGxlut8yKtpUNpz82uFvL1tdn+T7XIGBVO9e ZfZnIKKYJE+abMXFthulkd3OmlRoZ7ZDfMwI/azUFnNeFGuLjpR8Mla+Ki0WmjOV3bH950ahiml 3WNImP+5ifKvsT0215XqrKTu9iVBC3cFdJsY1wwQZpV3qTr+0n1XT3PrC6+PyWZGO3l5UGHSM3Q bOA/okHyy0v290CxM+GAXkT5nAiraFbxzupwU/sbACJf+y6zpyWgey+F9XSc/tv8dOEmBGv9fQ/ 1qbBgtD7XjYRnAB7uFkPaip8qCUNz2RyjFiidfueyZbACuke77pzTs5WJPIpWLjZE6E4MJZf25p 5ZM2klnatGRQBMKEWoxiAh01ak4QwA+Qe1R5CAek7vaudGhnmUeUw== X-Received: by 2002:a05:6870:2f14:b0:475:e0a7:9f2f with SMTP id 586e51a60fabf-4a8bb49f303mr759636fac.29.1793141380021; Tue, 27 Oct 2026 15:49:40 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:39 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 4/7] classes-global/sstate: Keep SPDX generating setscene dependencies Date: Tue, 27 Oct 2026 16:47:18 -0600 Message-ID: <20261027224931.385138-5-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248768 Tasks that create SPDX documents can reference SPDX ids from documents created by any task they depend on. When it comes time to create the final SBoM, these referenced SPDX ids must be present so that they can be merged into the SBoM. Specifically, when a task that restores from sstate (a setscene task) is one that can create an SPDX document, and that task is depended on by at least one other task that can create an SPDX document, it must always be restored. Signed-off-by: Joshua Watt --- meta/classes-global/sstate.bbclass | 38 ++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/meta/classes-global/sstate.bbclass b/meta/classes-global/sstate.bbclass index b2fa93650a..c6d9459182 100644 --- a/meta/classes-global/sstate.bbclass +++ b/meta/classes-global/sstate.bbclass @@ -1125,11 +1125,28 @@ def setscene_depvalid(task, taskdependees, notneeded, d, log=None): logit("Considering setscene task: %s" % (str(taskdependees[task])), log) - directtasks = ["do_populate_lic", "do_deploy_source_date_epoch", "do_shared_workdir", "do_stash_locale", "do_gcc_stash_builddir", "do_create_spdx", "do_create_recipe_spdx", "do_deploy_archives"] + directtasks = ["do_populate_lic", "do_deploy_source_date_epoch", "do_shared_workdir", "do_stash_locale", "do_gcc_stash_builddir", "do_deploy_archives"] + + # SPDX tasks are only needed if depended on directly, unless they are + # needed by another task that is creating SPDX documents + SPDX_TASKS = {"do_create_spdx", "do_create_recipe_spdx", "do_create_package_spdx"} def isNativeCross(x): return x.endswith("-native") or "-cross-" in x or "-crosssdk" in x or x.endswith("-cross") + def isSpdxTask(key): + taskname = taskdependees[key][1] + # Tasks that start with "do_deploy" might be included in + # SPDX_DEPLOY_TASKS and should be kept + if taskname.startswith("do_deploy"): + return True + + # Tasks that are don't start with do_deploy, but still deploy SPDX data + if taskname in {"do_image_complete", "do_populate_sdk", "do_populate_sdk_ext"}: + return True + + return taskname in SPDX_TASKS + # We only need to trigger deploy_source_date_epoch through direct dependencies if taskdependees[task][1] in directtasks: return True @@ -1142,6 +1159,8 @@ def setscene_depvalid(task, taskdependees, notneeded, d, log=None): return False return True + spdx_deps = [] + for dep in taskdependees: logit(" considering dependency: %s" % (str(taskdependees[dep])), log) if task == dep: @@ -1198,12 +1217,27 @@ def setscene_depvalid(task, taskdependees, notneeded, d, log=None): # Target populate_sysroot need their dependencies return False - if taskdependees[dep][1] in directtasks: + # Collect dependees that create SPDX documents + if isSpdxTask(dep): + spdx_deps.append(dep) + continue + + if taskdependees[dep][1] in directtasks or taskdependees[dep][1] in SPDX_TASKS: continue # Safe fallthrough default logit(" Default setscene dependency fall through due to dependency: %s" % (str(taskdependees[dep])), log) return False + + # SPDX generating tasks can refer to the SPDXID from the SPDX output of + # their dependencies. Therefore if the current task can generate SPDX and + # is depended on by another SPDX generating task, it must be kept so that + # the IDs can be correctly resolved when merging SPDX output into a + # complete SBoM + if spdx_deps and isSpdxTask(task): + logit(f"Keeping SPDX task {taskdependees[task]} needed by SPDX task(s) {', '.join(str(taskdependees[k]) for k in spdx_deps)}", log) + return False + return True addhandler sstate_eventhandler From patchwork Tue Oct 27 22:47:19 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102160 Received: from mail-oa1-f44.google.com (mail-oa1-f44.google.com [209.85.160.44]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.31668.1793141381979108280 for ; Tue, 27 Oct 2026 15:49:42 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=WlfM1FGA; spf=pass (domain: gmail.com, ip: 209.85.160.44, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f44.google.com with SMTP id 586e51a60fabf-4a76f0cce5fso200824fac.2 for ; Tue, 27 Oct 2026 15:49:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141381; x=1793746181; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=BWf9nPwSiawEirgLzEzSMAEs/S1YebD127It0ONYkPc=; b=WlfM1FGAXJAOCeapjPbJ3w8q6RQwEJSZ7Xex2aYpKOFBh1ddOYT8ZEjIxUmRUnkOsg +Dkr+Ne17CBH6PAE6Kql2NNIMovxvGojNDot8oR3ipA+gfiBuQOPd+42J49XApjGzihO MLCkrE5RwdnRx/FvfxcEiOWmmQcAx7Fl06+DGCi3czP3YasMAaw1iY6hgD9V2Y8XJea5 newFY5cxfu+60K4tSa3Cywwr4q5YE7QXfoj27bd7AnrOPcDT48+pOYrh+0gNO7O1aAZL +vLZFIq7aVbtPqxSE8hh1PPoFwHlfR9JW7Q9uXdHp6lh93fUOnXr44kR9VPSp5tPWxwc Zwug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141381; x=1793746181; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=BWf9nPwSiawEirgLzEzSMAEs/S1YebD127It0ONYkPc=; b=Q2dbZhh1tBvJHZqiEFLQWrT4RF73utpUl6lFti9jA7zR3a7yboBBLCt3t6XwIdMzIG 8KLSZFg6dai2aT5JeDs+aBf8QLOh5QH1wXbkXEPhy9KTYdX7xmZuwT5ppLzYn965/8JD 4xB22WCBnT8yR1XqOR9KHleTAFAXuKhjT32FOnuvKNo6l0pXV5ZyoeVgx0H2HgKOWt6Y TilHmI+ongdQIWD7FGqF8CFcDs7jbuBOURqpbgs6iedWx8yrucWAiV83ASlv3E3w5sPH MK8vyEcD1YZEN9wmUjQsxYJCLUIhqZ525+vcSo1qszlQLJCJZ+sEbBx5DJgi9tL/+ARN pxTw== X-Gm-Message-State: AFq9FYLzpl9psPVqoNqCRrcPNvlwvLNrCdwh8Ais9h93/7aRv9sgSNa8 qg14ivosr933klrNgYAbOhF/sYzX1fGSKPUIcVdreGGLNpX46+icU668vbGgQg== X-Gm-Gg: AYBFou0lFWg2T6Klr/SjAJH0Lp9z+rhFcgKcCqNIifxjarQLC24m4nXfZe02nwD4j1h 49LAJj47H/3SvQap92hSEuEisKwdtZ9mWoX8Vg5KULLSDAslPcX+YDWLaVpar1HT9UqDt113K74 lEZIthh5eNYkU6u0s10WRz/+Y6R2wU13z9/ZJbnSlhjLNlegvYeg+QLUlMo60kWaOjlJ3OmrX9Z wC+S8525Gbok+ve0K+I9a5R5ZlOXHbOTkaD0lD1uErab+2v6qbgtYi4yZWtVcSSKr39nR0JsQuc UUSpFy/UBaansul3BAMEHFOXIJkTrM6aWsrMMS7poXXQL2pnwm2G+SOi8tHVYhV12uzY+IvWowD f1ElO7af23yymSVYXNVnhFGAjuNO//Rttub0THZ96e3U5gyVlPXpKL6sKNMXcTP3LsuqtNFIYvG gSVvC8gja77XysMm7Yaiuz8vLh+4TicDqaNvtZyCiI5gO66fxKKt7NsOwowvkDgZz7+7XWzv+w9 mmiOZTJEaBi8rG1+HzbcjnAKURwDLtzMH8QzUgPQxgLB18rCcqm7Q== X-Received: by 2002:a05:6871:887:b0:485:d1ab:7936 with SMTP id 586e51a60fabf-4a8bb4c15d7mr812218fac.23.1793141380871; Tue, 27 Oct 2026 15:49:40 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:40 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 5/7] classes-recipe/deploy: Add do_deploy to SPDX_DEPLOY_TASKS Date: Tue, 27 Oct 2026 16:47:19 -0600 Message-ID: <20261027224931.385138-6-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248769 Any recipe that inherits this class will automatically generate deploy SPDX data for the do_deploy task Signed-off-by: Joshua Watt --- meta/classes-recipe/deploy.bbclass | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/classes-recipe/deploy.bbclass b/meta/classes-recipe/deploy.bbclass index f222a8560f..a3b48d6f7a 100644 --- a/meta/classes-recipe/deploy.bbclass +++ b/meta/classes-recipe/deploy.bbclass @@ -6,6 +6,7 @@ DEPLOYDIR = "${WORKDIR}/deploy-${PN}" SSTATETASKS += "do_deploy" +SPDX_DEPLOY_TASKS += "do_deploy" SPDX_DEPLOY_ARTIFACTS_DIR:task-deploy = "${DEPLOYDIR}" do_deploy[sstate-inputdirs] = "${DEPLOYDIR}" do_deploy[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" From patchwork Tue Oct 27 22:47:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102161 Received: from mail-oa1-f43.google.com (mail-oa1-f43.google.com [209.85.160.43]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.31669.1793141382573749942 for ; Tue, 27 Oct 2026 15:49:42 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=AsZyTsWs; spf=pass (domain: gmail.com, ip: 209.85.160.43, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f43.google.com with SMTP id 586e51a60fabf-48e9476e26aso151322fac.3 for ; Tue, 27 Oct 2026 15:49:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141382; x=1793746182; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/ixwZywXXbhp5HqkpDBB0XHk0fgGBqlbqBA8TTGVPvA=; b=AsZyTsWs8F6r6ZEgreH5agLBMZd0Ip4c8Xoomj7QhRER4e4fz2SLKmmu1O3LefLpqE bTGYLR7GBovqKSZh3m6KhA8mGCKmm1l1F6QDL43BieqtdXAITLPW4YNahjmHdlX47o/j 6rZW1ULri4bE5Mh3311mCaKhEdEeGohy85qgM0d/vurQVv5Xs+mlMS+pmCtuwh8ht606 uEkKvYAMDJHYVJbA8aEKmpspC9An51BQkB/ufStFCjWrIQkH7x34/eY4j/+jORitnmti Jn7z26TsiOYfFPKr7Z/dwes8cb8AE0rOBN0WIIDfjBMAdO11S1p8pfSwfG5XsjFQuiGL CSCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141382; x=1793746182; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=/ixwZywXXbhp5HqkpDBB0XHk0fgGBqlbqBA8TTGVPvA=; b=E+zzNmKBhNv65vOO2zMd4SIvKBsxu21ZBh0z6IILL3hsoL2SWUg4EiDgcqmmPFPwN8 YhTFeCaaxDSidwEx08lTLpmnPqgUifnu5WNXwjvvNZT6clYLkaHx++Z5I0v4kd+91yhM ibU56u/HEzZzsCO5Z6OhswwUEu4DQZoNEIqJkedayK8dqpZYF01TZ0v9VR/nmlT1niaI r+KtNqXC/5+XMHC1KtGTlmqy0lREH5m6QjmQtGCq6h0pJJMCsyqu41LLVS+BkuUyGfBU 1Jef1szq4aQGZR8CtPTAUV00szRmtO8zyIWq9FV7W/cUoy+pwSrRg2YedRqes8Golx8U ytUA== X-Gm-Message-State: AFq9FYIiO31LZco92XQE4DbCsbb/Z/YA1Rw/qHMFfagoQ+d7OYVUOFEj oYQswI//O5P+FHEcRcsoeLGOGQGuUmLLl6PyiOHx7omYCumQWx84dHIOZaUDWQ== X-Gm-Gg: AYBFou09mk9ONPNlPSGb7f6HY9JwmrJOrYDU/2m71f+CvR/9vTe7nZuW3oXlZJ2sB18 NJQ1cXcBwEVcfALXH7l2Alt+5SiSyImjgiuSpfbVXKU/wOsnFh8GeTZnyVA+ksZFFqy7Bgbo1/g ZMfv9ixhiQX0e9rjw9chOVG9TjHNo6+T0grnNeH/McuSEyrMfKD2YmITB8x6I8+C1zzdFLJUnbJ Pu1PLNRcjzfNQZWd8VPscqyNK9cqvQW0IJQT51NBjJxc3AUz+mpHD0HMRDIfKdx83917FMTys/0 YBoFYXOmzIwDuItTNm9MTmY9pqa8esHIne86XRDFOsrizbVM4X5/ca6qlDr/RZwxn6GxhW+9Ren FztmquLZcWKGPBsC06PfJECNyrOu6B4OVfC5HPuyW0zmpdKJtnBMseCsLRVYOrU1dbfeW0u2dTZ PNLoW8ZRc5xhpyTGNrjVjdTaUBYSl1v+kCGhHIYMXwZzAfBfPtgZqixbo7O0AMjvvRmzlo4JFa/ y9zXWBFQiwlqKU8ROZ3wfRQPzoRefcs+m8eZ/m6S6VwmF25Z4Qi/w== X-Received: by 2002:a05:6870:d114:b0:491:993d:d9b0 with SMTP id 586e51a60fabf-4a8bb5ce9d2mr752393fac.13.1793141381746; Tue, 27 Oct 2026 15:49:41 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:41 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 6/7] spdx: Replace do_create_image_spdx with deploy task Date: Tue, 27 Oct 2026 16:47:20 -0600 Message-ID: <20261027224931.385138-7-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248770 Replaces the dedicated do_create_image_spdx task with a deploy task tied to do_image_complete (which is task that deploys images). This has the advantage that images recipe SPDX dependencies are now completely automatically detected in the task graph, and the SPDX documents are merged in automatically when dependencies on do_image_complete are detected Signed-off-by: Joshua Watt --- .../create-spdx-image-3.0.bbclass | 32 +++++++------------ meta/classes-recipe/nospdx.bbclass | 1 - meta/classes/create-spdx-3.0.bbclass | 3 -- meta/classes/spdx-common.bbclass | 1 - meta/lib/oe/spdx30_tasks.py | 23 ++++++++----- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/meta/classes-recipe/create-spdx-image-3.0.bbclass b/meta/classes-recipe/create-spdx-image-3.0.bbclass index b60cdd826f..64cb065632 100644 --- a/meta/classes-recipe/create-spdx-image-3.0.bbclass +++ b/meta/classes-recipe/create-spdx-image-3.0.bbclass @@ -30,7 +30,7 @@ python do_create_rootfs_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_rootfs_spdx(d) } -addtask do_create_rootfs_spdx after do_rootfs do_create_recipe_spdx before do_image +addtask do_create_rootfs_spdx after do_rootfs do_create_recipe_spdx before do_image do_image_complete SSTATETASKS += "do_create_rootfs_spdx" do_create_rootfs_spdx[sstate-inputdirs] = "${SPDXROOTFSDEPLOY}" do_create_rootfs_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" @@ -43,33 +43,25 @@ python do_create_rootfs_spdx_setscene() { } addtask do_create_rootfs_spdx_setscene -python do_create_image_spdx() { +python create_image_spdx() { import oe.spdx30_tasks - oe.spdx30_tasks.create_image_spdx(d) -} -addtask do_create_image_spdx after do_image_complete do_create_rootfs_spdx do_create_recipe_spdx before do_build -SSTATETASKS += "do_create_image_spdx" -SSTATE_SKIP_CREATION:task-create-image-spdx = "1" -do_create_image_spdx[sstate-inputdirs] = "${SPDXIMAGEWORK}" -do_create_image_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" -do_create_image_spdx[cleandirs] = "${SPDXIMAGEWORK}" -do_create_image_spdx[dirs] = "${SPDXIMAGEWORK}" -do_create_image_spdx[file-checksums] += "${SPDX3_DEP_FILES}" -do_create_image_spdx[vardeps] += "\ - SPDX_IMAGE_PURPOSE \ - " + from pathlib import Path + current_task = "do_" + d.getVar("BB_CURRENTTASK") -python do_create_image_spdx_setscene() { - sstate_setscene(d) -} -addtask do_create_image_spdx_setscene + spdxdeploydir = Path(d.getVar("SPDXDIR") + "/deploy-" + current_task) + oe.spdx30_tasks.create_image_spdx(d, spdxdeploydir) +} +oe.spdx30_tasks.create_image_spdx[vardeps] += "SPDX_IMAGE_PURPOSE" +SPDX_DEPLOY_TASKS += "do_image_complete:create_image_spdx" +# No deploy sbom is needed since do_create_image_sbom_spdx() is used instead +SPDX_DEPLOY_SBOM = "0" python do_create_image_sbom_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_image_sbom_spdx(d) } -addtask do_create_image_sbom_spdx after do_create_rootfs_spdx do_create_image_spdx before do_build +addtask do_create_image_sbom_spdx after do_create_rootfs_spdx do_image_complete before do_build SSTATETASKS += "do_create_image_sbom_spdx" SSTATE_SKIP_CREATION:task-create-image-sbom-spdx = "1" do_create_image_sbom_spdx[sstate-inputdirs] = "${SPDXIMAGEDEPLOYDIR}" diff --git a/meta/classes-recipe/nospdx.bbclass b/meta/classes-recipe/nospdx.bbclass index 723194da2d..fafcdd0a13 100644 --- a/meta/classes-recipe/nospdx.bbclass +++ b/meta/classes-recipe/nospdx.bbclass @@ -10,6 +10,5 @@ deltask do_create_spdx deltask do_create_spdx_runtime deltask do_create_package_spdx deltask do_create_rootfs_spdx -deltask do_create_image_spdx deltask do_create_image_sbom_spdx deltask do_create_deploy_sbom diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 6077105094..f79ecac153 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -375,9 +375,6 @@ python () { # for the recipe, at least until it's possible for do_populate_sysroot # to describe it's own output. "do_populate_sysroot": "do_create_spdx", - # If an image is needed, also depend on the task to create the SBoM for - # the image - "do_image_complete": "do_create_image_spdx", } def map_task_deps(task, flag): diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index bca169670d..13839aac3a 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -15,7 +15,6 @@ CVE_VERSION ??= "${PV}" SPDXDIR ??= "${WORKDIR}/spdx/${SPDX_VERSION}" SPDXDEPLOY = "${SPDXDIR}/deploy" SPDXWORK = "${SPDXDIR}/work" -SPDXIMAGEWORK = "${SPDXDIR}/image-work" SPDXSDKWORK = "${SPDXDIR}/sdk-work" SPDXSDKEXTWORK = "${SPDXDIR}/sdk-ext-work" SPDXDEPS = "${SPDXDIR}/deps.json" diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index c1c0733508..567613cebc 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -1544,19 +1544,19 @@ def create_rootfs_spdx(d): ) -def create_image_spdx(d): +def create_image_spdx(d, spdx_deploy_dir): import oe.sbom30 - image_deploy_dir = Path(d.getVar("DEPLOY_DIR_IMAGE")) + pn = d.getVar("PN") + current_task = "do_" + d.getVar("BB_CURRENTTASK") + + image_deploy_dir = Path(d.getVar("IMGDEPLOYDIR")) manifest_path = Path(d.getVar("IMAGE_OUTPUT_MANIFEST")) - spdx_work_dir = Path(d.getVar("SPDXIMAGEWORK")) image_basename = d.getVar("IMAGE_BASENAME") machine = d.getVar("MACHINE") - objset = oe.sbom30.ObjectSet.new_objset( - d, "%s-%s-image" % (image_basename, machine) - ) + objset = oe.sbom30.ObjectSet.new_objset(d, f"{pn}-{current_task}-deploy") with manifest_path.open("r") as f: manifest = json.load(f) @@ -1649,13 +1649,18 @@ def create_image_spdx(d): objset.add_aliases() objset.link() oe.sbom30.write_recipe_jsonld_doc( - d, objset, "image", spdx_work_dir, create_task_link=True + d, + objset, + "deploy", + spdx_deploy_dir, + create_task_link=True, ) def create_image_sbom_spdx(d): import oe.sbom30 + pn = d.getVar("PN") image_name = d.getVar("IMAGE_NAME") image_basename = d.getVar("IMAGE_BASENAME") image_link_name = d.getVar("IMAGE_LINK_NAME") @@ -1677,7 +1682,9 @@ def create_image_sbom_spdx(d): root_elements.append(oe.sbom30.get_element_link_id(rootfs_image)) image_objset, _ = oe.sbom30.find_jsonld( - d, "image", "%s-%s-image" % (image_basename, machine), required=True + d, + "deploy", + f"{pn}-do_image_complete-deploy", ) for o in image_objset.foreach_root(oe.spdx30.software_File): root_elements.append(oe.sbom30.get_element_link_id(o)) From patchwork Tue Oct 27 22:47:21 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102162 Received: from mail-oa1-f54.google.com (mail-oa1-f54.google.com [209.85.160.54]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.31670.1793141383404227495 for ; Tue, 27 Oct 2026 15:49:43 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=h8X11U7A; spf=pass (domain: gmail.com, ip: 209.85.160.54, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f54.google.com with SMTP id 586e51a60fabf-49ddddefadbso186185fac.1 for ; Tue, 27 Oct 2026 15:49:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793141382; x=1793746182; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=zCDQnNDI3a2nbYfBkQMM38pAkt4zcIW62FFBDBOz91U=; b=h8X11U7A+2sz8es4z/pI4GCMp3dXAboJak/4RprTJ5VQd8fw/pNasl3AOByprgjkrA 1aX8veCUq4xOKoBlLlW4EQ4+EqDFf1060CKsZvjNSZkfGERKP6GcKnSOgxG0QpQ40iQE NvBj0p2wW15hqOz01URzGvCg4geiuJuYfGrqyVpUC+lckM2Pcbz21Rgdei9mMIzTphq5 jl67GCrWuX43lCVZ54MlCq71qwOZVl8MFKbkRyyiquWKNgosLoCy/EJh9C2uWa26mwDs cLBFXBWnrFWhqOIoC05pjazuWs31cPUQXkCyKOJVRakar9G9BSMMTcs0Igx8DxOKEl7y 8aHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793141382; x=1793746182; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=zCDQnNDI3a2nbYfBkQMM38pAkt4zcIW62FFBDBOz91U=; b=gxIURbs0Vq9LB4ogRzLA+S8SAIP6E1fRZYPLH3TveqWwhLQXVGQSX8OmWhGr4hTCFN rolbvhfDRTnmqhhLpPIPJPVUK9kxsVIVmLbf/CR5/Q17xZyLSPuf4xn0MczfKRoq1kKk Oyj4HxyjEH2DNIXJAXGKHHa/izkmwdOa1Eve7fC98iNwfboxRkKgvmIxtaUFT8Tvvg8s HjfiCupRmIhOInPoFCabdQ7V2Sopkki23cTFV/z2I4VHnHIFqw71uD6sScWmRcP5gDHb nN35R8t4ztbZ6+2bxnGf24++S5mGdShSeYP/n5Lx0wZn0UEGSVtj/nGWyfKKfW9/r/6C /r6A== X-Gm-Message-State: AFq9FYI237lIep03MhLjMP7jhWbYI3CrjsNeQwPwwhlV/BOwDY8b5HMH P0zeYXifFPhoUuXlB7ucs89UKFICz40xzbJeyOBMst2tunYc/Q2qTV6ZPv44jg== X-Gm-Gg: AYBFou1cHvapIZfYKv4IWg+8beivBWwHbRw8QY8RzOORMZkA4n0SmYxZzSWHiFoxbHK MmgNr1rIMqWGpENwGQaJYdvU+vcdv+93eGLRcbxjVjC78AD5PSStWzta6z41HrBRb3DQd9n+QeI 0fvoYCU3l5vctoygnHmGhDD+5FzO4LXQxw/6+inZ9+tXy8oGEvFGINMl9tgMYtdp5QDqw3AdFg4 XRXqSFBKa7KSrdPrvdunqJ7UhqjSTJoYVrI4YQ/qoDC8HJIkWT1JgRLGUj5yXURcKioNQ/QJHnK AQk6UXVGSVvXF73fUjjVoF51Xks744OgS8OQBCGvbbOv1kZYUDdEPX9wJruOHHUspRuUrkIqIZG wQoXN15kJAiX7uk+5YNUvpkwmcd5bDHyfy2RuGVYUPpzPrTOAwg02/ptA1QcLRzLYoT/Kw+z50c 3aou9EUwpR7ePixdw/L7AtX6ny+yL11fRK7Z6jl8q1VHSnjqRkohDD2VMNXPM/KZ7LWd4cj95O+ ptQopDTgFUCK4/ofrPmxVDMZwt1kddvX1aMzLP7escOJQiSIBmouQ== X-Received: by 2002:a05:6870:1698:b0:48f:e107:3188 with SMTP id 586e51a60fabf-4a8bb581206mr762763fac.40.1793141382527; Tue, 27 Oct 2026 15:49:42 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::1109]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b7979514sm1111037fac.17.2026.10.27.15.49.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2026 15:49:42 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v6 7/7] layer.conf: Fix initramfs-framework not knowing which udev it has Date: Tue, 27 Oct 2026 16:47:21 -0600 Message-ID: <20261027224931.385138-8-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261027224931.385138-1-JPEWhacker@gmail.com> References: <20261026214627.2388650-1-JPEWhacker@gmail.com> <20261027224931.385138-1-JPEWhacker@gmail.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Tue, 27 Oct 2026 22:49:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248771 The SIGGEN_EXCLUDE_SAFE_RECIPE_DEPS from initramfs-framework to eudev and systemd meant that it would not correctly update when switching udev providers (for example, when switching from the "poky" distro to "poky-altcfg" distro). Fix this by removing both entries. Signed-off-by: Joshua Watt --- meta/conf/layer.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/meta/conf/layer.conf b/meta/conf/layer.conf index 13c920be6c..b55d50c60c 100644 --- a/meta/conf/layer.conf +++ b/meta/conf/layer.conf @@ -59,8 +59,6 @@ SIGGEN_EXCLUDE_SAFE_RECIPE_DEPS += " \ docbook-xsl-stylesheets->perl \ ca-certificates->openssl \ initramfs-framework->${VIRTUAL-RUNTIME_base-utils} \ - initramfs-framework->eudev \ - initramfs-framework->systemd \ initramfs-module-install-efi->dosfstools \ initramfs-module-install-efi->e2fsprogs \ initramfs-module-install-efi->parted \