From patchwork Wed Oct 28 22:04:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102286 Received: from mail-oa1-f46.google.com (mail-oa1-f46.google.com [209.85.160.46]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.8308.1793225174265101163 for ; Wed, 28 Oct 2026 15:06:14 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=TeIubgy4; spf=pass (domain: gmail.com, ip: 209.85.160.46, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f46.google.com with SMTP id 586e51a60fabf-451a49abd8aso1433401fac.3 for ; Wed, 28 Oct 2026 15:06:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225173; x=1793829973; 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=TeIubgy4U/fsXmZyAiC9rvSewvU7lSzm90noPDPMIFReTzRv7UmkIBsxbPJsRT4Y9d EMI8S4ZKh2yxVLeUoUMjHF+z0sfYfP5kik2X1iSh1pWK7RlYc3qoYKRAKUhUFk384jDY w1Eq/QKTLJIE+MPw8bp0FXXhkjyry/pxrK9b0GAsmgJl0gDAOP0PlSNyqcBDCNbE9HxE CueDIWdouSe/UABnBpscld1agG2nyjn2VpG5qtj+xjO2c78iKTp0+aJDbhqDh4N+1xT9 nvx4dsLEXbp7YLRyHvs1hMJAZdE69Kny1fcwIBwkIN5GiNYUAW9PmKZd8dHgziLrIAcN Kdyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225173; x=1793829973; 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=i3xpO4TcEb5zNWU51KiaEZMbp36XF/46jlBzyhbR1wjKywuD0CSrcxZIy4LINLhf78 8tMzMawsii7HOPukVCcw/wVb5iXKhC+pjULY5/3Fc9wcgRKCcOqCCQNjehp4Bjo7nZeh JxY9BGIRDMwyuuQWLS4V36tnjKjuj6DKBTKRY5EYBthqFoj1Un7wUjduYdMjE2pQIwxF JN3h9Qf81nTbgFGD98Z1gHJM70KkFTXHGJLFJdPhubOx0bk5+4FFd8eYWN4/8DpYT1QW gNdrxKEQpqcG4o5yNQT6e0P6IOicGGNB0GPgVUETsBI3LQrk1RRwug6xPUbvIfEfUj3A ECkg== X-Gm-Message-State: AFq9FYJdYwO+zpJsfM6rvwEBXtLaZQwkmO00B9AIVgH9ZTtwzCYVNha2 qiafuJpb+nFZwHEjiIYuH5SXeIDPnUMOUNHhzP2UHZ+Sz8oXsMdxm9zY9hc8pA== X-Gm-Gg: AYBFou1qiK1AxEjrmIsrIHYEd3SFdXyOwYc5cqk0IrEB9OJKuzPdyIrivNtny3pLxSq 3CQAwGPC1+yEsnU67xZDbbYztpDtNN6xYvo712LprBciTs/7erD+cgHqNOUS+M+RV90DTA8/pPu KrBvfwHoASSHYEzRTihMgANIne/H6/AO3vmlR9VX9tnI8ge0TMs86QBxudw4LiDrD4Un+AUytS1 28k7+csDIJdEDdqYms4IX4o14mOYKPe2ssA4OHf3T7wheZRLiy+rt4GUKxuAQbHhVdiOnpmYDQr v6yeKSJclY9WI3veFtti3grJVbIMnzv98ttML4HDFHapzYIJBxtoHSKSWz9di3LRgG4f5eVj2Sk c5CPrJegiNZ7my5hWx98/f33VPb25f+ssR7QSQmPYVZI4Rb03oFG2MBX726OctBQx2O9haAuGGK o3ZNA/KgFV3EAHMBBC+cdyFZCHx24MAl6JOK2iGZEmUkopS2/O58XzbT0iPauji0lpYj/FeefIx DKA9rN6+EnFgcc5o9mzqmbE70vZAuYEAs1Le5p/ezb+94eppX30L/+Xd+v+oYiBIo9Ws9lZLcpl ozveLdsEFdMvzvCqwK3LgI4WfU6DSncoti1E+YzBUnFZiLgf X-Received: by 2002:a05:6871:ce:b0:499:6b20:13df with SMTP id 586e51a60fabf-4a8bb850c15mr2415122fac.30.1793225173321; Wed, 28 Oct 2026 15:06:13 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:12 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 1/8] spdx: Skip dependencies that are not in the taskhash Date: Wed, 28 Oct 2026 16:04:32 -0600 Message-ID: <20261028220609.1348489-2-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248838 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 Wed Oct 28 22:04:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102287 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.8440.1793225175663357304 for ; Wed, 28 Oct 2026 15:06:15 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=thG4DO9j; 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-4911df1e196so857777fac.1 for ; Wed, 28 Oct 2026 15:06:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225175; x=1793829975; 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=uIBnEwzzJKBXDm8pNbxVgPtbm+nTeh8yKSfu9OkcV90=; b=thG4DO9jDR46TdNm/GgvP4Vy2lYrEUEFv/XsFBnGL6ostdjiL284cB/vBxCsY3jZ7Q bdGhTilJTS+4W9IshNZNu8REI3qFmKzDicrwXx3GqiGgfmknk3pajliqVvbB2wwtlwva 6uAjRUuLFafeCW2Wq/iL8Mgc/BQOPQlf44PBUD78/WEBeqPiFulzN+AUTDyRin7sAzpX mGmlPZgYog++qgHqotaOdtvUB7rdLdz+D5+SoTqXgFzCWov0DzPvz2Pzin8s9JPtJa5a HLMkhttyoyNug1hmiNnTiuA1/y972keuUFL4fi0g9UBqQdlIkPJ7IDl+WVf8aPkFR/OD Irpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225175; x=1793829975; 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=uIBnEwzzJKBXDm8pNbxVgPtbm+nTeh8yKSfu9OkcV90=; b=rpjPOkj5ieHxWrka0TmbhqRvmhka8tWgi5YV8xg0DrG5K7qsxtJXuqpymKSVK46xAi 70U8Er/Nf3WSspFrmUON9R6nHAttgyRjVElO6utOMtQl2voXn/p/cWkPbZm4kn6+5sWj Y6GrV1dZh5tqwTU0re98wd9Ieuw2M3sRM6ZpU8ecn8MsB9Qn+7BviR6Xrgvm6XQppyaJ 4sbyg2w17BxbFnUYSz/07rd9ICqLoW1+bj5rNh9h0ySAB14VPCgfDiYJGYD9iLRBe6NM dy4dbiD3UK+ll4a/xbNcnOjOrdVcTf6SRJZWKqoD9THFM91Pbo5LNg3Ag158XSQFiMaC 0Jtw== X-Gm-Message-State: AFq9FYKTK3H7dGPv7r4PSe+xbzX+rSxdqC5/mdTFy9AapoNmtk3fdRtY 102KmA31gOZN8i2yWuoeBLNwSNExe3iYBkspnV7LslEPIVWvbcZaJQGidJDtfA== X-Gm-Gg: AYBFou2HfGGuuN4pyXwXpJrcS57+qbXg1LiOBEvy6o0OzV9VTX/0EyFQSjbgMASDWxv vR1u7pmKDDsWAVSA4Hth/BE4U7xakLdb3fL7SNN0bOf16LegFMRmIDvUDFBxKKU/x8/HKgI6W7l /ZWvN+gumwcj+3WyAv4p5YK1H60l5K38I1EU6i4mdbcYqvDc1Kb9hyJeo8tzlwlB09byaA8LYHJ 0C0tKbovmP5eUFQ0n0zT0CJAe3egpdyrgbva/v5CeAVsOY51CsJCZroEKktV0jRzfHROcJ0Tkly 68CwabKAi8gU0gXJjeZZb0NbRmwGklWqEHLVxkapJvMElUV6o2xj57aKsBw898bfhhAZPxGsyJ9 5oaZ4wfvYBxwqTs9NCe1B35Fqy6wdsyiaAJFz97d3B439NPYh8FQyVsK9o2q5bCYKaP/oLq+srf mr3D8KY0DrTKAKExUfxZntdALqMxUUyLZOmw84u2a9/XoZGpiKBvWfV114GSVPjic6z+CV3DOCI EMBX4uBG2Tjv479gaw02eMiuG7CJoplkHulH+n5EuDUvL5mb3sVZUuXu5IV6r69helCHQECQNYg fJBS+eXKoAGZISthv1SejFOJrGc= X-Received: by 2002:a05:6870:a104:b0:49d:c9b9:7509 with SMTP id 586e51a60fabf-4a8bb96355cmr2949708fac.13.1793225174498; Wed, 28 Oct 2026 15:06:14 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:13 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 2/8] spdx: Add ability for deploy tasks to create SPDX Date: Wed, 28 Oct 2026 16:04:33 -0600 Message-ID: <20261028220609.1348489-3-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248839 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 | 188 ++++++++++++ meta/classes/spdx-common.bbclass | 1 + meta/lib/oe/sbom30.py | 46 +-- meta/lib/oe/spdx30_tasks.py | 289 +++++++++++++++--- meta/lib/oe/spdx_common.py | 2 +- 8 files changed, 466 insertions(+), 66 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..fb6a4f249e 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -163,6 +163,55 @@ 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." + +SPDX_DEPLOY_ALLOW_EMPTY = "0" +SPDX_DEPLOY_ALLOW_EMPTY[doc] = "If set to '1', SPDX deploy task is allowed to \ + have no output artifacts. A SPDX document will still be produced, but it \ + will have no output files. This must always be set with a task override, \ + e.g.: SPDX_DEPLOY_ALLOW_EMPTY:task-deploy = '1'" + IMAGE_CLASSES:append = " create-spdx-image-3.0" SDK_CLASSES += "create-spdx-sdk-3.0" @@ -293,3 +342,142 @@ 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} ") + d.prependVarFlag(task, "vardeps", "SPDX_DEPLOY_ALLOW_EMPTY") + + 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..ce28ab4500 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -80,7 +80,9 @@ def add_license_expression( if lic is None: p, _ = oe.license.get_license_path(d, node) if p is None: - bb.fatal(f"{pn}: No generic license file exists for: {node.ident} in any provider") + bb.fatal( + f"{pn}: No generic license file exists for: {node.ident} in any provider" + ) return with open(p, errors="replace") as f: @@ -598,6 +600,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 +921,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 +937,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 +1065,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 +1257,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 +1495,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 +1530,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 +1623,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 +1650,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 +1830,80 @@ 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: + if ( + d.getVar("SPDX_DEPLOY_ALLOW_EMPTY:task-" + d.getVar("BB_CURRENTTASK")) or "" + ) != "1": + 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 Wed Oct 28 22:04:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102288 Received: from mail-ot1-f52.google.com (mail-ot1-f52.google.com [209.85.210.52]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.8311.1793225176388702884 for ; Wed, 28 Oct 2026 15:06:16 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=eck/ux55; spf=pass (domain: gmail.com, ip: 209.85.210.52, mailfrom: jpewhacker@gmail.com) Received: by mail-ot1-f52.google.com with SMTP id 46e09a7af769-854e904005cso102193a34.1 for ; Wed, 28 Oct 2026 15:06:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225175; x=1793829975; 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=eck/ux55L4JAx8unbyW02M+c/TGhZFypydLto+YvGraZ0yapgRAMvyduW5o6/oKFVT x3mE3oLPyMasi8Vr/b8+i57gk7dEPhwQvbzpj0Lms8NNgCbLqX3rhhhUrymvVuKNx59/ 8HPRS/MPhne6lo86a57yILmaKDfb81qq/0+3Mq0FX8v8x5pzTQpt5HcW67ideAv5TiHK uZ2TpIaZavf7/7G9/K/fuoDLZo49bLofb/DEeRgrlzEoBtG9LgCa0ekSYkNNaPGR2U+B H9l4G89V04+m1jI8mvm8BcI9Ea0bTSzc9VnngXeU6bsj2BNKA8eXeUC6LDcp8fVNK76P mmxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225175; x=1793829975; 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=KCzCGsr4FLf9NcQkkEeiS/ZNbXtk/YswKIDzuRhyRW+/gvAPn3y678yknDCC99RnMA I2fMdf8k6aCwY5YAEs1YArFcc3onDviwOyDRQ1HI9rBzyWh49kRuOH+VYgGrtoo+PNPU k1EGeNeViz6Y2bY0rq5r+T9d8mMGXqlp4y+8bcaRPgdpG7eBK8CNKmzfyHsZzcgJ92ZD IGckP8RGRt9vCiBoFL0ItoYTGXP5WuRMkmm79f2ZzlA3bnoikfDdIFWUpLk84j9sK847 hkB6RhIJ7UU/ym6Rrhl9ueW1K9JihN1YnPjtfFrVY7sRJT0JCw5qSRktrauRJ8nj7OEe AXpA== X-Gm-Message-State: AFq9FYKYyF2+OVbNYUSlnLWuhaEIukd+CSc1YebZbkR0oes+ZvzxORX/ 4Ko5YvOscqZsgNMDIwPppCBU87ptqsLhF/cz1sNly43u8tUeg+6sPR2GWzPhZw== X-Gm-Gg: AYBFou26zpE9TQdUQRMSkWuLCGfZ+cxkapqXK0J68ULf0x7e4BbYK1c6YZAAn3EzW1M DMuFskXceRid/vBWsNPfWQAd2lQvzZuwSH0Cp0LyYVkvEzIFjWeiABAAbEjpaIcEcjEdCpC1bgR 0IuiZ0wL7H7wXQ1azdwTAveIsFf66qRSf9QggAxs4L49ukz8GNmUKj9lqSCq004W6sEkFSnrr96 ewHFXI6DLzc5DJYbO+aTdbo/oWhp10VHM9rJ3feQEAxOWB1v0MLAeOA8kW6vZTkGFVDP7DLgovX PxzxugIuazBNtBAzhh8IrE5XDgvDewQSlcsNY0GqExCan7oXv9ttWuJcxd6e8eq+GzTkqzR+Juc v8wMM9zaurjlIzr13v36DOQs2/lc1VRcQdg4P4mzgGzGk3b/oCWpBcMS5SjGegrkm34regxz+8g 8EGZg9PWfI+niZlQXxerKYDNz/oadOn0XM7dYzHFbqNeQxd3s0UNNIgh4yiYBVcjfE0nPwL0+VM xZWqQZXTF6ynDmXjBl+s7+sC5nSKl8tmGkwAylmyF7xI+kErmJxxBAbXc2ONsL6lswx6EZjz+kN T+kQJ6wKtlaQc6qj0z/BDmttX4k= X-Received: by 2002:a05:6820:1c8c:b0:70b:1217:4ab0 with SMTP id 006d021491bc7-714ddce6251mr564658eaf.5.1793225175480; Wed, 28 Oct 2026 15:06:15 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:14 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 3/8] oeqa: Add SPDX deploy SBoM test Date: Wed, 28 Oct 2026 16:04:34 -0600 Message-ID: <20261028220609.1348489-4-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248840 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 Wed Oct 28 22:04:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102289 Received: from mail-oa1-f53.google.com (mail-oa1-f53.google.com [209.85.160.53]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.8441.1793225177305952493 for ; Wed, 28 Oct 2026 15:06:17 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=Kmz/8c0j; spf=pass (domain: gmail.com, ip: 209.85.160.53, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f53.google.com with SMTP id 586e51a60fabf-48ed188ee81so743201fac.1 for ; Wed, 28 Oct 2026 15:06:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225176; x=1793829976; 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=Kmz/8c0jPAsESpv9FQRsY3rTErtx4AseGSUf8zMgBTlyIV6LRQDs58fTG9+Gwa3acL L+6VzkaEs4wFWszEnGEhwrGjK1cEe1w1otBbM/xM1u24NQJDxH+sMC2z1ZPzbcqWVf2v Pq2THBdnmB9wZD+6oftsox8MQlKsjMiAGmX/b614d/AxA6tREmpMoKez8iSOY25ZqoRH uj4gkN37H06uMWyl6evBM2mT+r1Uu8sDlDqZGl+pfIMXOugFLRNjtvGhajaDR2ql+WN7 CXb6kV7CC1iak6EquWoUOKKObYqZWkgLfommfl/xJKhD7fdsQWSM07oDzyW3a29KVMxN W8qQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225176; x=1793829976; 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=1XH2UF5ZjjDSCaOUb7OLPXGaj2ucV81MsybUY786gyeAVGLikU6DWMDn+e+IDTcAff 3i5bKIG1ECqroHyjH3Co3nZlXSPe+s91hlRjzun2wy6QfU/tNhqufXtraw6vMTRTqyWA GXbm+VhxxJJS2ZdjXYzBrbQpOOodY1xqDTKn2r88oVghbS5r/zdV98U4MLtbDpKC2WC3 V9Q91vqYWItsMAX55I4mezg3hww9sxC9rofX1xWEHMXQF3z0AQTJmmn8tGyo20MRPgCc ojbMPbjtzD0u6i35OGBx9LDXi+vclbR2vUrS6NQw62xQoSdsRxp65HbDFgiN91X5ZRrJ wrfA== X-Gm-Message-State: AFq9FYI1vX0RILOBW/HDmbZ55ryNopETB9vGdGrqF04TksxDJ1HgIZ7R +ZMdI5Az6tJVWaa18o345k2Q3SpW7NuzIvjGOinD+6b+nwUhl9OxMlVufpXaXA== X-Gm-Gg: AYBFou2H5Ipw1FG49hs4hoXVmTYXObqhv2EhDmAxAiYcWSHXmFdWXogd/n/OGDPZusb Jul/EuIQn1XrX+efJuxD/Bpa/ZyT0u/TrlHxddnumfDhXPDJo+0sSetdnPy/YOCS1koKg1crVHz 9JwLODjCH3pM/hbnKOj5YOlAvQVg+CaEA/p31GABpFTb6M0C1kTzjZCbxNgfMO60Ll2ysIOI15E FH7yahHYyBlwa/TpP4dtbKVQ8txDc+ycNlQYbRM0iBU5Mxs1Di9+4leZBoJJWa9VbPEPtciLJCK iQKFbqVsfkRHO2C8YViXg8PQoKkkyCLj6XOypA3u65YLATjga4dsRT/TKqw0BpcNs7h3sYOhLD8 cnD0fmEC3TTviMI3tEg7iDK1S72ypgEhV33pseQM3owvPnzqbDg8FsRNETS2hx3vSrIVyyzd/Ws TIpL7CDbkTBnAFNJq85EleiER8a4mZ+KZQa27JQS/DI1dvzKabiYpRGlJg2Xb3VkCg4w8khuE6T ePka+dXd1F/18RH/32sA3TpaAU8dSe9igCV1DrNVOKm8WrbbG2+HGvwmBtMHHPjWIFfstKXpYKr FzJ7JTwwG0ilx8CLycbNHdYsSGs= X-Received: by 2002:a05:6871:3a12:b0:48f:e0f6:bd5f with SMTP id 586e51a60fabf-4a8bb70088dmr2596523fac.48.1793225176410; Wed, 28 Oct 2026 15:06:16 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:15 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 4/8] classes-global/sstate: Keep SPDX generating setscene dependencies Date: Wed, 28 Oct 2026 16:04:35 -0600 Message-ID: <20261028220609.1348489-5-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248841 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 Wed Oct 28 22:04:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102290 Received: from mail-oa1-f42.google.com (mail-oa1-f42.google.com [209.85.160.42]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.8443.1793225178229107333 for ; Wed, 28 Oct 2026 15:06:18 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=Z795uou6; spf=pass (domain: gmail.com, ip: 209.85.160.42, mailfrom: jpewhacker@gmail.com) Received: by mail-oa1-f42.google.com with SMTP id 586e51a60fabf-483a66818edso750798fac.0 for ; Wed, 28 Oct 2026 15:06:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225177; x=1793829977; 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=Z795uou630ZVhpm6tG2HdtBnKuBDlnOcXzKniStk3Au69YtzeBXipMxQzAQin8IfIY g1RBmZocUfeXltMvS3+brpGS44I/sA2GweoxkNPPK1/EBXW/j7WYgnNUjSEJRhbMQ2Zt KNKMZXkEXgclPcrAME3Sn+NgzIM8VFppBHDs2InmSdBn/md/qSAVQOoz+zcjo9tPJopf D0QMxTHErdAMXEb+/biGsQdHmt7sanp6dIAaGy8o2TjQPkC22ydtlKNHfH+l6ZB/iEsB 0A1DJlBsOa3sCErMeIA4lN09jZOhKfLekzaMsnoZNXgWq8tbF++/D0kbV43WdhFbgaJX s+4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225177; x=1793829977; 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=m9vHjD2LtFaJL9MTiwVzpXwqvIOGHKXmFXoCzreEcdsL33Tnurntov/uXsSwxKzIWZ PR4D/j2Hcg9JwL7zlYHDT/HLIHgviWNrPGNYRSxXWh6GQQ2QfD7V8x5cca/7ClG96mDF C7B8Ap5M7BXsdRS71aBFKzougDCTP2bgz2R0vVmnggQFc/7vsfG5WcDL7LM56xKX9c9A 7BLq83vTgeb8VkeMUm8Kt/ES5i5n6rjsvJXe2QUGbcgLGm0SoCyZS6TZncQTrNd9R8hC FDEA8yRIwoWy4AWJR9vHFAedXujgq3jHxxyJvyNIERugv2KZPC2x7O5fJ14TZpXU0kh/ 0/vw== X-Gm-Message-State: AFq9FYJWMFCp28fEkKoGV204uggRIMsLcWAIs/xElbtxfBTRUdx4UzVF w53UtB5/xJBecYdzO28h9NBxXbK9MKf5ny/mi4GBN0DLwOZZ/+pBYWhZY/cJtw== X-Gm-Gg: AYBFou0yFfTm7mGVtCmxFEz/ZZIZF7md4qM1C9nRVOM7pd001DNdxyIX563TpTgDbmU 9ze2iXGFhQFJvOEz47cJjZfz0XI6lPwsg6EzDObr6gL9SBwyEixWcr8feHdRcpWjLDa0pKKuiiK b2y3DVJu8KzLC4tG5+SBjMwVFyI4FRuAYX5Q35BqdIOLSbFcymic3OFcmf1MNCwlEEr/kCuH/4u uLTHzF59ce1VfkpEgre/PFxwra1hoRiBSZGGElbKEh7BnzcS3b2EayaA2IUhpLtlk0kkLdsoARt +iCwDY6yQlu8AxZSGykPeeAyInvvOqauAfegwoUsGRrHVuEPTtGR0WdVkkj7UOc/xA+zsxTzk5b 9KQ3CEwf8A4sdr5NJPTfRHlsjL37IfCdWeydhrYE7RlrLZWy/1+s96pU/FNayRMU17ugR8KiuRl 8uThhNtFgzm9XjLBrHR1wszd+xCg1sJTMZRr8KM1HcYYIkz8RnpBlcgzD3JN2m1w5/v2dIjr98A mZl//mCnJ9N/xwcrqjYOBh0+1FKIhHpu3qbJ3a4xK16ubN3AKhUgQWk3xkjY0xHEHgTWSLx6RR/ ecUorQaYjsJL3clKpr1pGUmJOtZBWPS1n+N+yYBl7J/v4Rox X-Received: by 2002:a05:6871:3869:b0:494:76db:2aa8 with SMTP id 586e51a60fabf-4a8bb59ac9fmr2986976fac.5.1793225177416; Wed, 28 Oct 2026 15:06:17 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:16 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 5/8] classes-recipe/deploy: Add do_deploy to SPDX_DEPLOY_TASKS Date: Wed, 28 Oct 2026 16:04:36 -0600 Message-ID: <20261028220609.1348489-6-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248842 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 Wed Oct 28 22:04:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102291 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.8313.1793225179324877135 for ; Wed, 28 Oct 2026 15:06:19 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=OvHWlMFW; 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-4932b13c4ccso912641fac.3 for ; Wed, 28 Oct 2026 15:06:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225178; x=1793829978; 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=hZSmURBO/asW2c3yPgYbfLgj6euKLa4vKOrL0iSBjEs=; b=OvHWlMFWFA7EcjfHbXJbkM7nu7NhUVpPZwHnNr6MUMMvymo1RE+GYRPhxQFLwsN30j C01q75gTVHGn33tOe5gBifbw6qXi8hJOuwutz20rgTaI0bMnAjxh2m4ius2HfFnxcUi4 Br8kokHJe41UNHtmh7I3Z1qd6ZMhI6H3WJCJajccMKspD+d6vc8LD3a7rrIfbAsPd7Ce njYxFTKafnabwKofEjAdHxu/3hKS+bkA92iPhgffEuOOJkZ4S226DxXZGHMYVWmguOSf zJOM8Wf/YtRVDZvQCwrbjs9VaCKuF9rAa/j9/e6TPCYLIo8XVKez1i23FCNgy82kCv3d 2elA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225178; x=1793829978; 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=hZSmURBO/asW2c3yPgYbfLgj6euKLa4vKOrL0iSBjEs=; b=rBdy3iAmyTF+SxfkRwqiJUwQXnnA7lbiUrwk32xGUt7vyN9iQUgfWp0nCuIuWUYVMx 10a2BzAjkch683v8KoGT8qMBD4B5SRlu89TxDf8MbjrC+Wdou9hJFvPX2Ng55koBcPGV Hx3nh+U86NUw7QCBOecFkwD38sE19EK5vUo27RRHxFWb97veYajk33PcZByo+Niob9B7 Sc8sdBUJG2LEk1ZWAqKIEI4Drk6offwOlHrTVaK7v2S/UiCUyIN0wMsMEHE4ylWQ6G3s CGglKW+GFaDHMLiwfCVqQ3DalcvJRrvY3JK6UW3CQMneJv+FDo6JqrIZO9EsgdDfl5TW k0cw== X-Gm-Message-State: AFq9FYIVYqk8AlVPaVIA39U6vwsL7ZtReSFRleGl0cSA/4EEVI8cpeP0 nv96KB59mOfPOBr8Ee9AXON0yR/7H3WvLl5DCKCb4AfFAbhuYCu8nIpnCGh2Bg== X-Gm-Gg: AYBFou2+ZB2yxpK7QTG9I3dCjwMU8JL/D9zpTyLoZNY45tZygiS1y3J0sBbPe/nNgxQ RjiVehAqIqeY5GSeFfbXEJJDgF1sMYcXL6ZhUKEMHqWddORt3NA7aghJ9y30IG+qAjBzsAtRh20 4qUzXDEk9JqVhE1l5aX+QKzkU/J4A+xtcPD7pGffgplVrOf4u0mrHQZaCIE/FZDTHbT/WNKFMHr b1By6AcdGD4nlUaFhYFDfxTwBTs6cNATlWAFFal/RzndQWB2/lYwRlxVi/as+nxFLohTniNhmu4 Ni58zy8xoVzWC5u9Pmp0Faysam//932PdQi4gB90ZQU9ipNp1dJAdOG2YisvCgTmltaiiXH/+NW D118lG88xz+46QqM1d8Zfm9r8tksZV0Sy9iOgB4qNJHsfB/A0STHj3cODCcF2Si9xuxGbKheEF1 1qJO/8r/dImL3raTMjCohmB7YeF+9KgoFo33cRT1NE35KbdGvhDc5iW+eqhyZfkKNmExyjToU4W mQG5uB7Pf0km7q5jadawwmF2P57LIBOyBQw8+b/QuDql8wTmkcCDFDbCPxky5QJ+frLEYb/YmfV 9pKTyHVXJpWTBzhD2DOm+UVKJZo= X-Received: by 2002:a05:6870:9f08:b0:475:e235:905 with SMTP id 586e51a60fabf-4a8bba79bfcmr2541449fac.35.1793225178493; Wed, 28 Oct 2026 15:06:18 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:17 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 6/8] spdx: Replace do_create_image_spdx with deploy task Date: Wed, 28 Oct 2026 16:04:37 -0600 Message-ID: <20261028220609.1348489-7-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:19 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248843 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 fb6a4f249e..0d0bddcc67 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -381,9 +381,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 ce28ab4500..6010fe7230 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -1546,19 +1546,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) @@ -1651,13 +1651,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") @@ -1679,7 +1684,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 Wed Oct 28 22:04:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102292 Received: from mail-oo1-f42.google.com (mail-oo1-f42.google.com [209.85.161.42]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.8315.1793225180361915245 for ; Wed, 28 Oct 2026 15:06:20 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=i8sq7/xK; spf=pass (domain: gmail.com, ip: 209.85.161.42, mailfrom: jpewhacker@gmail.com) Received: by mail-oo1-f42.google.com with SMTP id 006d021491bc7-6de1fd5f572so749496eaf.3 for ; Wed, 28 Oct 2026 15:06:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225179; x=1793829979; 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=i8sq7/xK2AUdShbXwVz0h0wgIQofXA2kYrJJPhLmrE8H5Ub33YSMbalozNkCF8KDBJ /sLi+2zmzQ0k200izm5ugKRE2mWv/4eqFaKWbe1Iwbytkix0k/fngdWwabTN18tcG5iP 91SgCSh48jySwgsP9lnNiXdUgKyA5p5zZ++Spk9WBp9MX5F3amR9MWupHKsPeedlnuAO NC4eKTx93iMQvTbzfwVDds9y9njMBOQrSUsU/lLIeFQpiZFYvQq0jKxhTgxVNIIRorXL 5S/WE7zIqqRAdYiskxCn/SzSsGGjzQkZ+vMHW0HSJ7he8KSkArT9bHrU++XCPOeY7/Ob vMiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225179; x=1793829979; 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=kXXhsFfpotjlyE67x7LaYsZi45E1+4wuhIQrF02xtRmTHAJ/D1Yv9DvG7iSXYkmEiX Jp8LjYUdZVXWvt1BsHOwnKwKUuX5DydUOqQZCxWXQu8taYBKaKeARzRzvMSzrA5/oHbK 76qg6bSx0AdAuOp2bLE5tMcTQqVo2ol55c0banEtFkkaur7FHq2xD65+UnfNhaYInPPW 2vIjiH0CuUamPG1i8lMoXQ/AYKcWmTu7rxOo7Xc8d6vhR6pJTbHKWpwwMqk7AOZFXpam OSbAZ/l99Ve/amo3BL3fFgctDtUQMhDrC1cWipPB8IRpgefqtH1avKbLlgDCOlo7ote0 JQ+Q== X-Gm-Message-State: AFq9FYIIm45468bJccENsII99v7iaoV/PBDSbIVu1geKopWB/EQ/S3a6 J3qqmdGpD7LEEdjEjLh+e9UySX6viRl1l+cfA9ig9tvfTFXIfGbueRIJMyR+bQ== X-Gm-Gg: AYBFou0Y9s67SZUDLBkLGVLHrqnRbVi8SqZPLWRBGFXWpYGAq2JSjWZsnXSR13GphWh +luWyaqQPBPEAMRhSVUnlWuq6NwzMUYtpYeuUaGfyFavaMKe0OHgVKngfRUXiE2shgw3Cg/2boB NH95GDhTZTtyeOVucLB5UjGw6KwfGBCAKjMFoS90nNPVhaDACUfyj0hZZeYJjXdr5MXk8KaVOBy FNcSB5Vkrbr3scVG7efOaI5zZyOYmcQZuY0Yj6qcp51wsgkXimaBoq7b/SIqQhd3xAj0C3UnICJ 9txI4o4MpW+qoVRZXBjGNuTzANry7xQ0+yJkHkE8kJhKUZacjhruMetaNAp2aOikAX/i2wAeWvU XIWn/dyGXe1WP5XpJ95ot6kuti6Ur1s7f4PUJNW+w2N5ZrpFSh/p6eqhNrCL2u0CGzyxiBIm1AX jw37eY8YbOqjfgjbpiW40fMWLxg8gqmW3iKUsmGuwOQ+e0VaXsl6GfR6x6qmJkNJvt+GfzgAO3C anQ14Ism3jK5IgENnTeif+SEgiBdG1mUytm+cWe6DsX7Wz+WLUK1mccD/l+DeRFgzdaju6ALkAV CAEAuG0V0UXBhv1J4tTl8dqRt/c= X-Received: by 2002:a05:6820:3413:10b0:713:e433:aa9d with SMTP id 006d021491bc7-713ec60ad2bmr1457269eaf.8.1793225179475; Wed, 28 Oct 2026 15:06:19 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:18 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 7/8] layer.conf: Fix initramfs-framework not knowing which udev it has Date: Wed, 28 Oct 2026 16:04:38 -0600 Message-ID: <20261028220609.1348489-8-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:29 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248844 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 \ From patchwork Wed Oct 28 22:04:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 102293 Received: from mail-oo1-f45.google.com (mail-oo1-f45.google.com [209.85.161.45]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.8316.1793225181235536593 for ; Wed, 28 Oct 2026 15:06:21 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20260707 header.b=izrl/SEq; spf=pass (domain: gmail.com, ip: 209.85.161.45, mailfrom: jpewhacker@gmail.com) Received: by mail-oo1-f45.google.com with SMTP id 006d021491bc7-6b1afdf5196so630840eaf.2 for ; Wed, 28 Oct 2026 15:06:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793225180; x=1793829980; 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=BTYMigd0+ZyC4B85UyNY8s3jidM5wVxaP5djY52xhfM=; b=izrl/SEqBEnV8tDyr6qtf6MIe4oBTUp6j1A2JluJrmEdSWq1FURIj8Y+Jm6eO5IJ9A GRQot5fOd0Dbtxaz7IQlSOcbEDI+sh/b7LSWn9YaIkgCP1MTBFE+tAqyWMD4BgeI0TVk a1THrBmQO2dSv0dxq9YC7WwLD5QlSBN8Gp7IP3h1Xx0Lm2Q5JmVQ2pluPErSEleObWPQ 2XApKm7RvYsfRC5CYz8HDeIrWwApsu3WXZ3EYFgeUMteMlHSbuyq/SO1AterLpphsfrd 9Fk/+bechgxkh6tgQ9aCgtuXvDsy/sRmT7gwNRaJDCHmx+YIM3N2C3o/0anKimfQhcrY NViw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793225180; x=1793829980; 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=BTYMigd0+ZyC4B85UyNY8s3jidM5wVxaP5djY52xhfM=; b=TLDHpUcmjU/6DUKVssSoFTo/FuiCSmBkNOALmnwAeMKC64Bjf6nTLVdiod+TazNU9R FmXYAc9b17ap0y/cSg70NP3VRx/tirYQftg9Nc1oBwSaQXlwtnk4i/8O1D+4cO2NJyzI LLgHKmtozzdbrFjYIVwM4AB8PBqlgne9af7C7btKGm3b3No5pIIkpru//HSyxRWTJ7Bm JfC2IRcHqSCiGBdy8uc+wiu0xLjC5OOMNKVeYNCq1vBBo4bKUYlfX58agwOCJ00EG0yX HtcAObLVu9KYBHCF17RGO4ipBUCR35Du1A3OqpxKAeja10Fc43Mnn4wR9xULmpmh19cs A4aw== X-Gm-Message-State: AFq9FYJkx/Xx1rWX3vISeciwbh1i0CTH4kfN9vB/JnMWBfYK27bop1SI VD35fNnzCFZervarr0q7avGIFcqLiQnE20et6U/AHRZ2zF5mq62eUD43jCsY8Q== X-Gm-Gg: AYBFou1U6yScBm1nVVdUheVsrXcHQh5FAbtyHeStDacBuFa2pnFQbsLUKaDodkjhDn6 VMhPAmpHT0GEgCs5zZXCe9RZ37sofoDE6JD11XhMSVJbmWAWr8vCs02s7YfxWTs29EvpNOZIqjt cPWdcHg6/2nPziMZLur9/lqMKYpcE/X0CaXesr5ynXrdI0UhPh9JH2km2N6Kt8UElBQVTPrMckW Gukn98f+TSiEVLo8A9C9QMPCESQoGUQ8CQqou4oRCek+tlHRHke/L0eBtUPlj3pLaoz5B8GxNUg v3mLqUf+qawJynM50hTkq7T643G/Nrduw9aV0LAa2KRDZdsg32IfKtp03z1tuLEP+xqHn+6cALX 3pSmRbtKRSWlL6VgcxF9AWscy6f0g8YdPQehV5eiby2jQNlpkExrN+jo3P/+OJtFtJip4350dfl OvRlrh2tQKHD4PuZ522pFgTbGdnqzD1u8YOVyUrRj8ERBOHQ9q37dDIUD7gSS7ROQjqK96YxYFG tQDJOHkSIi3bKGXYBqHyLFeK40NerBiRYcP0Uw0tYJjU547t1QlqaL3WbZE8TCjD9l9QYq6fx0A 1qgWFjfnP6utv6pl7yhbrvhtK2I= X-Received: by 2002:a05:6820:571c:20b0:6f5:a96d:cbb with SMTP id 006d021491bc7-713ef141eb9mr1328469eaf.45.1793225180366; Wed, 28 Oct 2026 15:06:20 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([2601:283:4b01:ba50::8aac]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-4a8b77abffcsm3527597fac.4.2026.10.28.15.06.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 15:06:19 -0700 (PDT) From: Joshua Watt X-Google-Original-From: Joshua Watt To: openembedded-core@lists.openembedded.org Cc: Joshua Watt Subject: [OE-core][PATCH v7 8/8] ovmf: Allow empty SPDX deploy artifacts Date: Wed, 28 Oct 2026 16:04:39 -0600 Message-ID: <20261028220609.1348489-9-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261028220609.1348489-1-JPEWhacker@gmail.com> References: <20261027224931.385138-1-JPEWhacker@gmail.com> <20261028220609.1348489-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 ; Wed, 28 Oct 2026 22:06:29 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248845 In native builds, ovfm do_deploy doesn't produce any artifacts. Set the SPDX_DEPLOY_ALLOW_EMPTY flag to prevent SPDX from erroring when this occurs. Signed-off-by: Joshua Watt --- meta/recipes-core/ovmf/ovmf_git.bb | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index bf69108f0a..7cc844dfa6 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -249,5 +249,6 @@ do_deploy:class-target() { fi } addtask do_deploy after do_compile before do_build +SPDX_DEPLOY_ALLOW_EMPTY:task-deploy = "1" BBCLASSEXTEND = "native"