From patchwork Tue Mar 10 18:38: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: 83005 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2903FFD4F23 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f176.google.com (mail-oi1-f176.google.com [209.85.167.176]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2660.1773168065517441019 for ; Tue, 10 Mar 2026 11:41:05 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=SjGqI6T7; spf=pass (domain: gmail.com, ip: 209.85.167.176, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f176.google.com with SMTP id 5614622812f47-46708149af2so1568079b6e.0 for ; Tue, 10 Mar 2026 11:41:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168064; x=1773772864; 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; bh=kZsTCBgME1PNRjxHczDMbLqJbIl+DF2WK2U4einEvRE=; b=SjGqI6T7ly4hHDAV16C5S0lK9xuFfxvfeSlYzXLIfi8rSFAmpU3lhfxWj4/r8XhLYT ZgPPMEvZG/UIOr4fumzZzmoOG5wfvEipTXn2ELbG+u7P4PVIl7/an7n0kXYzqMfXiNHF 0iwe54AAgCOcweXEU7rTty7ra80TYMpnvqK7wm6asVnTug7b+RRx0pqxFnxFxSZriz3v 9m8fLzx9/Kbw15nvAm9OG31dpWzJJ3VU1d1vT1PS6LE7EdHcpkQOp19RqR1zi5z+hSe5 5NuOfRNSmzjrJ/SXFTSwdPazgjjJ9Ny76DW5577QrmJ0Ml25PRJZJuxGs6pNITWmihOU ynYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168064; x=1773772864; 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; bh=kZsTCBgME1PNRjxHczDMbLqJbIl+DF2WK2U4einEvRE=; b=LZHg/m7SU8Ebdn/5yRXg155h1AazTK+RXTdOxSQ+VfdP/KlJpwuNt9wlWHs2J49MFG 2aEQP4ieVWpJqhZpLEgBxtSwOn9TqWHog3W3WgTN5aVMrQdcIYBLlBlZjKAYEA8CoM/y CKPznvq4RSTng6XYPhCTOOHe2rBXk8tmLQNu8T1hKmLdUhANaCLG0TuYmcWu2BIKDObq Z4ErFn0Pdoj2V9z7Gthv9imrhWoo36Ex4BoHgwsBYQ5kamQ1WyPgnXzFMSVnj4MI6uTW ZEwTbOJJSUdlcY9I8HzUkDmYvv3qiQ4JnE+nfx5LgM2p1L8rFbzUJr42xTi3tJKBFTPh LJOQ== X-Gm-Message-State: AOJu0YzaSp2wcKwBGA4Vu+OaTFViLk2WExzZ8bqm7Gg/J4KvOMI/BFGn d6UWx/vB3amhN38ggWdx2F1OLVlHhb4EEYGUCqaVmPyKD30K9moxi2rJKtrcCg== X-Gm-Gg: ATEYQzzce8C+k2mN2w5rwrzigcYNkSGwWkdZG2Km8TvVEgrH4L9t64ecnlmev+cCSde LgPM4HaNitmqQdcDiBWWEPWihsfqEWxzcMBsFX9885+qR0hkeMx4vZq83rvvGjJzmrQF3O9b8uK hTW02Nvh589v/V2928DDkaMwfQwbL2Pljeo0YBAl2RetlyH5Pfs9vKg3uqUI+8qT62sn1yMCAhn FchGRtJZOCsSMUu2m8s5Pd2Zi4J93QhLK9WIWenY2G9owXFJ1+qQXyAigni70h+CaxuvpAQ0Ntk xX/NKzQTOI+Vj/M/u1Ly4W6YHuVIH5Q7QXGImkBUpIS5HvUfnB+6j58wdOjLVYC9d4v4YUB5t0m OjUZwJKGSCh76KrBgwLSz3KCeJ9o5vhZX4a6yD/a1eGldODTzXsz51vODbz8qxXXEyE7ip8zZev 9S2cGUpovLcj2yHPKvIOrm X-Received: by 2002:a05:6808:c162:b0:455:d5d1:8ac0 with SMTP id 5614622812f47-466dcb76992mr8745223b6e.53.1773168064561; Tue, 10 Mar 2026 11:41:04 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:04 -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 01/15] llvm-project-source: Use allarch.bbclass Date: Tue, 10 Mar 2026 12:38:21 -0600 Message-ID: <20260310184058.533343-2-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232812 Converts the recipe to use allarch.bbclass. This is necessary because SSTATE_PKGARCH is set to "allarch" based on if allarch is inherited or not. If it is not, SSTATE_PKGARCH has the value "all", which means any data written out based on it cannot be found (because "all" is not in SSTATE_ARCHS) Signed-off-by: Joshua Watt --- meta/recipes-devtools/clang/llvm-project-source.inc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/meta/recipes-devtools/clang/llvm-project-source.inc b/meta/recipes-devtools/clang/llvm-project-source.inc index 13e54efbc2..6bb595b7bc 100644 --- a/meta/recipes-devtools/clang/llvm-project-source.inc +++ b/meta/recipes-devtools/clang/llvm-project-source.inc @@ -5,7 +5,7 @@ deltask do_populate_sysroot deltask do_populate_lic RM_WORK_EXCLUDE += "${PN}" -inherit nopackages +inherit nopackages allarch PN = "llvm-project-source-${PV}" WORKDIR = "${TMPDIR}/work-shared/llvm-project-source-${PV}-${PR}" @@ -14,14 +14,8 @@ SSTATE_SWSPEC = "sstate:llvm-project-source::${PV}:${PR}::${SSTATE_VERSION}:" STAMP = "${STAMPS_DIR}/work-shared/llvm-project-source-${PV}-${PR}" STAMPCLEAN = "${STAMPS_DIR}/work-shared/llvm-project-source-${PV}-*" -INHIBIT_DEFAULT_DEPS = "1" DEPENDS = "" PACKAGES = "" -TARGET_ARCH = "allarch" -TARGET_AS_ARCH = "none" -TARGET_CC_ARCH = "none" -TARGET_LD_ARCH = "none" -TARGET_OS = "linux" baselib = "lib" PACKAGE_ARCH = "all" From patchwork Tue Mar 10 18:38:22 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83006 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F3E8FD4F26 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f169.google.com (mail-oi1-f169.google.com [209.85.167.169]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2661.1773168066491886374 for ; Tue, 10 Mar 2026 11:41:06 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=WlIpjzjt; spf=pass (domain: gmail.com, ip: 209.85.167.169, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f169.google.com with SMTP id 5614622812f47-46702742c7dso667549b6e.1 for ; Tue, 10 Mar 2026 11:41:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168065; x=1773772865; 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; bh=7bs/2ESNOjlKv5F2a1L5fY1cfh3Mb2GOypfpxUG+ELw=; b=WlIpjzjtnuGlPpwbu5W8VZ+0EMZ9r9veKKQi+dIP4lsXG1J0rCeKlEyKDesmVOSeYk b8iPEU/DDKJ2We/SngWijgp1zyJq2Ar9fw3dfp6pJfvGiJvJ0dtE3eRf2dlSrZMnKbGM IjYJssvkX00BH/WGgzvjZJGr4CfogVUD4ujy3wl3UeSIkhz+yAsVbJWqvPnQybQdUhDe yEJTajRHHDUEw5m3gDck7mDX7p9damf/dJERoN75vUP2jZsWRdf4bYUAH9M1GOFgZ+ur 0E9X347gF6/wmMBjvvhuAZ+dZzeBUZmycHhKPFeKTltp1U2j6+mORco1HykThZX2qrTy 97oA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168065; x=1773772865; 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; bh=7bs/2ESNOjlKv5F2a1L5fY1cfh3Mb2GOypfpxUG+ELw=; b=eHDgG8rCmcDEbwAo7EFyauC/TSJj6H26zJbwWgE2C2eWLzBa1R+/GQEbH0vh3U7pxe 40pSSXS+9clHbXgxeRHXUSWjmWzjYXfGoDVAPnBqEoTQ1PxtwvDoSnm/kuSj4p2zoyw4 z8riyo5YZbAPkw2OQLZWH7RqQmbtaNxEK/km9g8PVA7EQGKkwkoBauFNLhfxkBo8Om7g lsiMP87TYMLB9Al/Nb1DedVUEsldaa/kmt1LKu30ITd4kPkfX4+CP3MOTe/l/2dqYdJz aU53dEhiywt0CTYepV6aOuK3sbtb0fz6opHlOeA1fcrujcBeWwchfArpXWdcGCccYCXe eVGA== X-Gm-Message-State: AOJu0YzHzqbVw9M9D9Tt0z2SlYBX2nepoUrCJIf/VT4nKLlKUAcxEcl9 Yh0LOKFjidSiM+SOWk66wXjQUOYlZ9Jx4ESG1FNCDBt3IiO7aaJDRCatyugnDw== X-Gm-Gg: ATEYQzztwJJL0esCWvbB2qMRFDHY31jCsbFe1FDc4Oi4m36OOWy3j4gPjTjCDUVl04h MYRJ8o73nkO5Z72PpAotnTlARwW1puTFR592k2qUKmUDNMDXPUGnFHpnDtkuKSJD8T1rj6tynAT ExJPiMARKlpeZc2B/GtZu6ctqjZM5NMba9V0KW1p+uFKOlUHveV//ak+IBXkAX6vNmqI+r3rZz7 LwQpZkawWayppbFKf83+kEoyqbvRPX2Aeie12VxgNJj838wid+6xQ0HD15JYfpjeYqXMKIJSEtr vLAQB9stIwSa9TL+9HHDnR56Mx1ONy3qMLC0CNOrt/Jc4Lq5yOxwYzP60Yj1qtSnHtzV5PO4bTH uQzwpU95QOlnxPbTkmwugLdeyW6L1jbfCrYqjI90yOHfvqg5+2KDuyZDcH8Dv7MQR+Sb0dHsSba j2qSzoCpnEaowepAo167xJoK61+d2/AqE= X-Received: by 2002:a05:6808:2e44:b0:467:2509:c20a with SMTP id 5614622812f47-4672509c5d6mr1365442b6e.47.1773168065445; Tue, 10 Mar 2026 11:41:05 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:05 -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 02/15] gcc-source: Use allarch.bbclass Date: Tue, 10 Mar 2026 12:38:22 -0600 Message-ID: <20260310184058.533343-3-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232813 Converts the recipe to use allarch.bbclass. This is necessary because SSTATE_PKGARCH is set to "allarch" based on if allarch is inherited or not. If it is not, SSTATE_PKGARCH has the value "all", which means any data written out based on it cannot be found (because "all" is not in SSTATE_ARCHS) Signed-off-by: Joshua Watt --- meta/recipes-devtools/gcc/gcc-source.inc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/meta/recipes-devtools/gcc/gcc-source.inc b/meta/recipes-devtools/gcc/gcc-source.inc index 265bcf4bef..3ac679b1a6 100644 --- a/meta/recipes-devtools/gcc/gcc-source.inc +++ b/meta/recipes-devtools/gcc/gcc-source.inc @@ -1,11 +1,11 @@ -deltask do_configure -deltask do_compile -deltask do_install +deltask do_configure +deltask do_compile +deltask do_install deltask do_populate_sysroot -deltask do_populate_lic +deltask do_populate_lic RM_WORK_EXCLUDE += "${PN}" -inherit nopackages +inherit nopackages allarch PN = "gcc-source-${PV}" WORKDIR = "${TMPDIR}/work-shared/gcc-${PV}-${PR}" @@ -14,14 +14,8 @@ SSTATE_SWSPEC = "sstate:gcc::${PV}:${PR}::${SSTATE_VERSION}:" STAMP = "${STAMPS_DIR}/work-shared/gcc-${PV}-${PR}" STAMPCLEAN = "${STAMPS_DIR}/work-shared/gcc-${PV}-*" -INHIBIT_DEFAULT_DEPS = "1" DEPENDS = "" PACKAGES = "" -TARGET_ARCH = "allarch" -TARGET_AS_ARCH = "none" -TARGET_CC_ARCH = "none" -TARGET_LD_ARCH = "none" -TARGET_OS = "linux" baselib = "lib" PACKAGE_ARCH = "all" From patchwork Tue Mar 10 18:38:23 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83011 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 71E8FFD4F28 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f174.google.com (mail-oi1-f174.google.com [209.85.167.174]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2662.1773168067562520636 for ; Tue, 10 Mar 2026 11:41:07 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=N8QZwJfA; spf=pass (domain: gmail.com, ip: 209.85.167.174, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f174.google.com with SMTP id 5614622812f47-467161c4b89so1195588b6e.3 for ; Tue, 10 Mar 2026 11:41:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168066; x=1773772866; 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; bh=ejPOECwOwHRSqAC4uEbDkFRtMsD+n1UdWSUGrtjhMl8=; b=N8QZwJfA1gx5jolvQ5gAd4RTB7PzZSwzqcIP/HuLM36siXfUyS7eNsPqAFrNzVuoGz T7iA6cQ849TX7VSbgcE9Ludl3+hd2ETrK2oBs5yDADsr/ZPM9HOrCeYP9STe7Ty1MLGQ erH9hN0i626eKIZRDxsJ5j69Bdgt4Cv6EkBI7ZzMEx7SGyt9YRUI0FXu05Cxrq+rHWLz TBhfiq7D7UublNt/pdm6w6Qfribr6G3zmY03Dvl5d9PMcTVmCS7ELFnPR4ugaBVeCHGw GnPz7aYwKk9bCW9jpx91XpaTeP765O6OHMsUEFqm7RK126zfhLY+Yj+w0wM9ZEajsg1/ cfKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168066; x=1773772866; 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; bh=ejPOECwOwHRSqAC4uEbDkFRtMsD+n1UdWSUGrtjhMl8=; b=EZKFAMMwo7iP20F86ca1cD94stADUpvduPcVePEYk+u1KFfHXLEShFKbkpbT8R25NS SK6hE/BAhyKuFdReBmSk5opFAdeOwB82iwu8Mkk8m/a1YbihyCoxLLBUgsuPYMiovtX4 jw4QWZVkK7v70mFrK59Jgr+LOyPCm+FqmMPz188gfCNBX4em3Oe290mF7jN3DgjC7Yii I37coP+J3SKHUlzK8oOlDfOTVZbWOO0LzK+QLJX1xNvIo9x0svS1c8YWJvpzDL9Uw7Yf mj/jBqWeXTBbyaNKutQWuHDsmRUo8xzZnc/yKgPURKDeUVvcP0g8968Ls10AbHKLgpWp eR/g== X-Gm-Message-State: AOJu0YwdjfbCKhA0kUZHKOvdodXttBuO/qAnGcZRlJ7yE+TXnZye2l1t E92wsZ8b89p49LHifmE0MGdKGXcj6wlj2WVZ8NpDk/NEvE8vsTG8880EdGfCBQ== X-Gm-Gg: ATEYQzxF28Xey3LC+OfMd38SeFQQPipAUqR2FaAYrqAyVf6myH9vtTr44a5ktON8Lza PtvxGqrSUWk7q6r+R5EcJRA45kSjPgHFEzJYCvn5DK3YJGxJmMoKZiLs4eVDW2b8n8pEi3V0zAc P8cry7FLnPb8qA2ZpJTlO8pQ12MbMiCVuvLNUz9JlWXwvxqiISFshJUgatrLD4G0vzm64ihH7Ps IsKKsAzAk02fb5SmXabx1P9X0npvcHw0ut+qU/W3OypdJTuJhXI8ZP2ZdRwws7M6NWYxaZGi6/T qybdjtglbEeeIwfKJqgziB+qAC1LzeVV837gLxIrKFJnw2DoIf49mtud6MdZQW9umMxO1QnQYpu JH4AVuRBVMGEHr7iF8nHpMO4qtwNCOSwMJypvuuOu1eSUFiDGfxGUX7ts46d68t7jz4csS8Qhss dhymImV9ONsu6ZiYlr7uB0 X-Received: by 2002:a05:6808:2228:b0:450:3ff9:f4ef with SMTP id 5614622812f47-466dcb89bb8mr9048559b6e.56.1773168066303; Tue, 10 Mar 2026 11:41:06 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:05 -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 03/15] spdx3: Add recipe SPDX data Date: Tue, 10 Mar 2026 12:38:23 -0600 Message-ID: <20260310184058.533343-4-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232814 Adds a new package to the SPDX output that represents the recipe data for a given recipe. Importantly, this data contains only things that can be determined statically from only the recipe, so it doesn't require fetching or building anything. This means that build time dependencies and CVE information for recipes can be analyzed without needing to actually do any builds. Sadly, license data cannot be included because NO_GENERIC_LICENSE means that actual license text might only be available after do_fetch Signed-off-by: Joshua Watt --- meta/classes-global/sstate.bbclass | 4 +- .../create-spdx-image-3.0.bbclass | 4 +- .../create-spdx-sdk-3.0.bbclass | 4 +- meta/classes-recipe/kernel.bbclass | 2 +- meta/classes-recipe/nospdx.bbclass | 1 + meta/classes/create-spdx-2.2.bbclass | 12 +- meta/classes/create-spdx-3.0.bbclass | 51 ++- meta/classes/spdx-common.bbclass | 21 +- meta/lib/oe/spdx30_tasks.py | 402 ++++++++++++------ meta/lib/oeqa/selftest/cases/spdx.py | 19 +- 10 files changed, 354 insertions(+), 166 deletions(-) diff --git a/meta/classes-global/sstate.bbclass b/meta/classes-global/sstate.bbclass index 2fd29d7323..95c44f404e 100644 --- a/meta/classes-global/sstate.bbclass +++ b/meta/classes-global/sstate.bbclass @@ -954,7 +954,7 @@ def sstate_checkhashes(sq_data, d, siginfo=False, currentcount=0, summary=True, extrapath = d.getVar("NATIVELSBSTRING") + "/" else: extrapath = "" - + tname = bb.runqueue.taskname_from_tid(task)[3:] if tname in ["fetch", "unpack", "patch", "populate_lic", "preconfigure"] and splithashfn[2]: @@ -1116,7 +1116,7 @@ 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_deploy_archives"] + 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"] def isNativeCross(x): return x.endswith("-native") or "-cross-" in x or "-crosssdk" in x or x.endswith("-cross") diff --git a/meta/classes-recipe/create-spdx-image-3.0.bbclass b/meta/classes-recipe/create-spdx-image-3.0.bbclass index 636ab14eb0..15a91e90e2 100644 --- a/meta/classes-recipe/create-spdx-image-3.0.bbclass +++ b/meta/classes-recipe/create-spdx-image-3.0.bbclass @@ -34,7 +34,7 @@ addtask do_create_rootfs_spdx after do_rootfs before do_image SSTATETASKS += "do_create_rootfs_spdx" do_create_rootfs_spdx[sstate-inputdirs] = "${SPDXROOTFSDEPLOY}" do_create_rootfs_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" -do_create_rootfs_spdx[recrdeptask] += "do_create_spdx do_create_package_spdx" +do_create_rootfs_spdx[recrdeptask] += "do_create_recipe_spdx do_create_spdx do_create_package_spdx" do_create_rootfs_spdx[cleandirs] += "${SPDXROOTFSDEPLOY}" do_create_rootfs_spdx[file-checksums] += "${SPDX3_DEP_FILES}" @@ -76,7 +76,7 @@ do_create_image_sbom_spdx[sstate-inputdirs] = "${SPDXIMAGEDEPLOYDIR}" do_create_image_sbom_spdx[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" do_create_image_sbom_spdx[stamp-extra-info] = "${MACHINE_ARCH}" do_create_image_sbom_spdx[cleandirs] = "${SPDXIMAGEDEPLOYDIR}" -do_create_image_sbom_spdx[recrdeptask] += "do_create_spdx do_create_package_spdx" +do_create_image_sbom_spdx[recrdeptask] += "do_create_recipe_spdx do_create_spdx do_create_package_spdx" do_create_image_sbom_spdx[file-checksums] += "${SPDX3_DEP_FILES}" python do_create_image_sbom_spdx_setscene() { diff --git a/meta/classes-recipe/create-spdx-sdk-3.0.bbclass b/meta/classes-recipe/create-spdx-sdk-3.0.bbclass index e5f220cdfa..a4b8ed3bf9 100644 --- a/meta/classes-recipe/create-spdx-sdk-3.0.bbclass +++ b/meta/classes-recipe/create-spdx-sdk-3.0.bbclass @@ -5,14 +5,14 @@ # # SPDX SDK tasks -do_populate_sdk[recrdeptask] += "do_create_spdx do_create_package_spdx" +do_populate_sdk[recrdeptask] += "do_create_recipe_spdx do_create_spdx do_create_package_spdx" do_populate_sdk[cleandirs] += "${SPDXSDKWORK}" do_populate_sdk[postfuncs] += "sdk_create_sbom" do_populate_sdk[file-checksums] += "${SPDX3_DEP_FILES}" POPULATE_SDK_POST_HOST_COMMAND:append:task-populate-sdk = " sdk_host_create_spdx" POPULATE_SDK_POST_TARGET_COMMAND:append:task-populate-sdk = " sdk_target_create_spdx" -do_populate_sdk_ext[recrdeptask] += "do_create_spdx do_create_package_spdx" +do_populate_sdk_ext[recrdeptask] += "do_create_recipe_spdx do_create_spdx do_create_package_spdx" do_populate_sdk_ext[cleandirs] += "${SPDXSDKEXTWORK}" do_populate_sdk_ext[postfuncs] += "sdk_ext_create_sbom" do_populate_sdk_ext[file-checksums] += "${SPDX3_DEP_FILES}" diff --git a/meta/classes-recipe/kernel.bbclass b/meta/classes-recipe/kernel.bbclass index d61cc82a4e..8fd4e1141a 100644 --- a/meta/classes-recipe/kernel.bbclass +++ b/meta/classes-recipe/kernel.bbclass @@ -882,7 +882,7 @@ do_create_spdx:append() { except Exception as e: bb.error(f"Failed to parse kernel config file: {e}") - path = oe.sbom30.jsonld_arch_path(d, pkg_arch, "recipes", f"recipe-{pn}", deploydir=deploydir) + path = oe.sbom30.jsonld_arch_path(d, pkg_arch, "builds", f"build-{pn}", deploydir=deploydir) build_objset = oe.sbom30.load_jsonld(d, path, required=True) build = build_objset.find_root(oe.spdx30.build_Build) if not build: diff --git a/meta/classes-recipe/nospdx.bbclass b/meta/classes-recipe/nospdx.bbclass index b20e28218b..90e14442ba 100644 --- a/meta/classes-recipe/nospdx.bbclass +++ b/meta/classes-recipe/nospdx.bbclass @@ -5,6 +5,7 @@ # deltask do_collect_spdx_deps +deltask do_create_recipe_spdx deltask do_create_spdx deltask do_create_spdx_runtime deltask do_create_package_spdx diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass index 65d10d86db..3288cdf75a 100644 --- a/meta/classes/create-spdx-2.2.bbclass +++ b/meta/classes/create-spdx-2.2.bbclass @@ -399,6 +399,15 @@ def get_license_list_version(license_data, d): return ".".join(license_data["licenseListVersion"].split(".")[:2]) +# This task is added for compatibility with tasks shared with SPDX 3, but +# doesn't do anything +do_create_recipe_spdx() { + : +} +do_create_recipe_spdx[noexec] = "1" +addtask do_create_recipe_spdx after do_collect_spdx_deps + + python do_create_spdx() { from datetime import datetime, timezone import oe.sbom @@ -594,7 +603,7 @@ python do_create_spdx() { } do_create_spdx[vardepsexclude] += "BB_NUMBER_THREADS" # NOTE: depending on do_unpack is a hack that is necessary to get it's dependencies for archive the source -addtask do_create_spdx after do_package do_packagedata do_unpack do_collect_spdx_deps before do_populate_sdk do_build do_rm_work +addtask do_create_spdx after do_create_recipe_spdx do_package do_packagedata do_unpack do_patch do_collect_spdx_deps before do_populate_sdk do_build do_rm_work SSTATETASKS += "do_create_spdx" do_create_spdx[sstate-inputdirs] = "${SPDXDEPLOY}" @@ -605,6 +614,7 @@ python do_create_spdx_setscene () { } addtask do_create_spdx_setscene +do_create_spdx[deptask] += "do_create_spdx" do_create_spdx[dirs] = "${SPDXWORK}" do_create_spdx[cleandirs] = "${SPDXDEPLOY} ${SPDXWORK}" do_create_spdx[depends] += " \ diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index d4575d61c4..672ca27cd0 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -159,11 +159,18 @@ SPDX3_DEP_FILES = "\ ${SPDX_LICENSES}:True \ " -python do_create_spdx() { +python do_create_recipe_spdx() { import oe.spdx30_tasks - oe.spdx30_tasks.create_spdx(d) + oe.spdx30_tasks.create_recipe_spdx(d) } -do_create_spdx[vardeps] += "\ +addtask do_create_recipe_spdx after do_collect_spdx_deps + +SSTATETASKS += "do_create_recipe_spdx" +do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}" +do_create_recipe_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" +do_create_recipe_spdx[file-checksums] += "${SPDX3_DEP_FILES}" +do_create_recipe_spdx[cleandirs] = "${SPDXRECIPEDEPLOY}" +do_create_recipe_spdx[vardeps] += "\ SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ SPDX_PACKAGE_ADDITIONAL_PURPOSE \ SPDX_PROFILES \ @@ -171,7 +178,19 @@ do_create_spdx[vardeps] += "\ SPDX_UUID_NAMESPACE \ " +python do_create_recipe_spdx_setscene () { + sstate_setscene(d) +} +addtask do_create_recipe_spdx_setscene + +python do_create_spdx() { + import oe.spdx30_tasks + oe.spdx30_tasks.create_spdx(d) +} addtask do_create_spdx after \ + do_unpack \ + do_patch \ + do_create_recipe_spdx \ do_collect_spdx_deps \ do_deploy_source_date_epoch \ do_populate_sysroot do_package do_packagedata \ @@ -181,18 +200,25 @@ SSTATETASKS += "do_create_spdx" do_create_spdx[sstate-inputdirs] = "${SPDXDEPLOY}" do_create_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" do_create_spdx[file-checksums] += "${SPDX3_DEP_FILES}" - -python do_create_spdx_setscene () { - sstate_setscene(d) -} -addtask do_create_spdx_setscene - +do_create_spdx[deptask] += "do_create_spdx" do_create_spdx[dirs] = "${SPDXWORK}" do_create_spdx[cleandirs] = "${SPDXDEPLOY} ${SPDXWORK}" do_create_spdx[depends] += " \ ${PATCHDEPENDENCY} \ ${@create_spdx_source_deps(d)} \ " +do_create_spdx[vardeps] += "\ + SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ + SPDX_PACKAGE_ADDITIONAL_PURPOSE \ + SPDX_PROFILES \ + SPDX_NAMESPACE_PREFIX \ + SPDX_UUID_NAMESPACE \ + " + +python do_create_spdx_setscene () { + sstate_setscene(d) +} +addtask do_create_spdx_setscene python do_create_package_spdx() { import oe.spdx30_tasks @@ -205,16 +231,15 @@ SSTATETASKS += "do_create_package_spdx" do_create_package_spdx[sstate-inputdirs] = "${SPDXRUNTIMEDEPLOY}" do_create_package_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" do_create_package_spdx[file-checksums] += "${SPDX3_DEP_FILES}" +do_create_package_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" +do_create_package_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" +do_create_package_spdx[rdeptask] = "do_create_spdx" python do_create_package_spdx_setscene () { sstate_setscene(d) } addtask do_create_package_spdx_setscene -do_create_package_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" -do_create_package_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" -do_create_package_spdx[rdeptask] = "do_create_spdx" - python spdx30_build_started_handler () { import oe.spdx30_tasks d = e.data.createCopy() diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index 3110230c9e..3c239a718b 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -23,6 +23,7 @@ SPDXDEPS = "${SPDXDIR}/deps.json" SPDX_TOOL_NAME ??= "oe-spdx-creator" SPDX_TOOL_VERSION ??= "1.0" +SPDXRECIPEDEPLOY = "${SPDXDIR}/recipe-deploy" SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" SPDX_INCLUDE_SOURCES ??= "0" @@ -67,12 +68,6 @@ def create_spdx_source_deps(d): deps = [] if d.getVar("SPDX_INCLUDE_SOURCES") == "1": pn = d.getVar('PN') - # do_unpack is a hack for now; we only need it to get the - # dependencies do_unpack already has so we can extract the source - # ourselves - if oe.spdx_common.has_task(d, "do_unpack"): - deps.append("%s:do_unpack" % pn) - if oe.spdx_common.is_work_shared_spdx(d) and \ oe.spdx_common.process_sources(d): # For kernel source code @@ -84,8 +79,6 @@ def create_spdx_source_deps(d): # For gcc-source-${PV} source code if oe.spdx_common.has_task(d, "do_preconfigure"): deps.append("%s:do_preconfigure" % pn) - elif oe.spdx_common.has_task(d, "do_patch"): - deps.append("%s:do_patch" % pn) # For gcc-cross-x86_64 source code elif oe.spdx_common.has_task(d, "do_configure"): deps.append("%s:do_configure" % pn) @@ -97,8 +90,8 @@ python do_collect_spdx_deps() { # This task calculates the build time dependencies of the recipe, and is # required because while a task can deptask on itself, those dependencies # do not show up in BB_TASKDEPDATA. To work around that, this task does the - # deptask on do_create_spdx and writes out the dependencies it finds, then - # do_create_spdx reads in the found dependencies when writing the actual + # deptask on do_create_recipe_spdx and writes out the dependencies it finds, then + # downstream tasks read in the found dependencies when writing the actual # SPDX document import json import oe.spdx_common @@ -106,15 +99,13 @@ python do_collect_spdx_deps() { spdx_deps_file = Path(d.getVar("SPDXDEPS")) - deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + deps = oe.spdx_common.collect_direct_deps(d, "do_create_recipe_spdx") with spdx_deps_file.open("w") as f: json.dump(deps, f) } -# NOTE: depending on do_unpack is a hack that is necessary to get it's dependencies for archive the source -addtask do_collect_spdx_deps after do_unpack -do_collect_spdx_deps[depends] += "${PATCHDEPENDENCY}" -do_collect_spdx_deps[deptask] = "do_create_spdx" +addtask do_collect_spdx_deps +do_collect_spdx_deps[deptask] = "do_create_recipe_spdx" do_collect_spdx_deps[dirs] = "${SPDXDIR}" oe.spdx_common.collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index 99f2892dfb..a8b4525e3d 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -32,7 +32,9 @@ def set_timestamp_now(d, o, prop): delattr(o, prop) -def add_license_expression(d, objset, license_expression, license_data): +def add_license_expression( + d, objset, license_expression, license_data, search_objsets=[] +): simple_license_text = {} license_text_map = {} license_ref_idx = 0 @@ -44,14 +46,15 @@ def add_license_expression(d, objset, license_expression, license_data): if name in simple_license_text: return simple_license_text[name] - lic = objset.find_filter( - oe.spdx30.simplelicensing_SimpleLicensingText, - name=name, - ) + for o in [objset] + search_objsets: + lic = o.find_filter( + oe.spdx30.simplelicensing_SimpleLicensingText, + name=name, + ) - if lic is not None: - simple_license_text[name] = lic - return lic + if lic is not None: + simple_license_text[name] = lic + return lic lic = objset.add( oe.spdx30.simplelicensing_SimpleLicensingText( @@ -178,7 +181,9 @@ def add_package_files( # Check if file is compiled if check_compiled_sources: - if not oe.spdx_common.is_compiled_source(filename, compiled_sources, types): + if not oe.spdx_common.is_compiled_source( + filename, compiled_sources, types + ): continue spdx_file = objset.new_file( @@ -293,17 +298,16 @@ def get_package_sources_from_debug( return dep_source_files -def collect_dep_objsets(d, build): +def collect_dep_objsets(d, subdir, fn_prefix, obj_type, **attr_filter): deps = oe.spdx_common.get_spdx_deps(d) dep_objsets = [] - dep_builds = set() + dep_objs = set() - dep_build_spdxids = set() for dep in deps: bb.debug(1, "Fetching SPDX for dependency %s" % (dep.pn)) - dep_build, dep_objset = oe.sbom30.find_root_obj_in_jsonld( - d, "recipes", "recipe-" + dep.pn, oe.spdx30.build_Build + 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 @@ -311,10 +315,10 @@ def collect_dep_objsets(d, build): if dep.in_taskhash: dep_objsets.append(dep_objset) - # The build _can_ be linked against (by alias) - dep_builds.add(dep_build) + # The object _can_ be linked against (by alias) + dep_objs.add(dep_obj) - return dep_objsets, dep_builds + return dep_objsets, dep_objs def index_sources_by_hash(sources, dest): @@ -423,9 +427,7 @@ def add_download_files(d, objset): if fd.method.supports_checksum(fd): # TODO Need something better than hard coding this for checksum_id in ["sha256", "sha1"]: - expected_checksum = getattr( - fd, "%s_expected" % checksum_id, None - ) + expected_checksum = getattr(fd, "%s_expected" % checksum_id, None) if expected_checksum is None: continue @@ -462,50 +464,96 @@ def set_purposes(d, element, *var_names, force_purposes=[]): ] -def create_spdx(d): - def set_var_field(var, obj, name, package=None): - val = None - if package: - val = d.getVar("%s:%s" % (var, package)) +def set_purls(spdx_package, purls): + if purls: + spdx_package.software_packageUrl = purls[0] - if not val: - val = d.getVar(var) + for p in sorted(set(purls)): + spdx_package.externalIdentifier.append( + oe.spdx30.ExternalIdentifier( + externalIdentifierType=oe.spdx30.ExternalIdentifierType.packageUrl, + identifier=p, + ) + ) - if val: - setattr(obj, name, val) + +def create_recipe_spdx(d): + deploydir = Path(d.getVar("SPDXRECIPEDEPLOY")) + deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) + pn = d.getVar("PN") license_data = oe.spdx_common.load_spdx_license_data(d) - deploydir = Path(d.getVar("SPDXDEPLOY")) - deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) - spdx_workdir = Path(d.getVar("SPDXWORK")) - include_sources = d.getVar("SPDX_INCLUDE_SOURCES") == "1" - pkg_arch = d.getVar("SSTATE_PKGARCH") - is_native = bb.data.inherits_class("native", d) or bb.data.inherits_class( - "cross", d - ) include_vex = d.getVar("SPDX_INCLUDE_VEX") if not include_vex in ("none", "current", "all"): bb.fatal("SPDX_INCLUDE_VEX must be one of 'none', 'current', 'all'") - build_objset = oe.sbom30.ObjectSet.new_objset(d, "recipe-" + d.getVar("PN")) + recipe_objset = oe.sbom30.ObjectSet.new_objset(d, "static-" + pn) - build = build_objset.new_task_build("recipe", "recipe") - build_objset.set_element_alias(build) + recipe = recipe_objset.add_root( + oe.spdx30.software_Package( + _id=recipe_objset.new_spdxid("recipe", pn), + creationInfo=recipe_objset.doc.creationInfo, + name=d.getVar("PN"), + software_packageVersion=d.getVar("PV"), + software_primaryPurpose=oe.spdx30.software_SoftwarePurpose.specification, + software_sourceInfo=json.dumps( + { + "FILENAME": os.path.basename(d.getVar("FILE")), + "FILE_LAYERNAME": d.getVar("FILE_LAYERNAME"), + }, + separators=(",", ":"), + ), + ) + ) - build_objset.doc.rootElement.append(build) + set_purls(recipe, (d.getVar("SPDX_PACKAGE_URLS") or "").split()) + + # TODO: This doesn't work before do_unpack because the license text has to + # be available for recipes with NO_GENERIC_LICENSE + # recipe_spdx_license = add_license_expression( + # d, + # recipe_objset, + # d.getVar("LICENSE"), + # license_data, + # ) + # recipe_objset.new_relationship( + # [recipe], + # oe.spdx30.RelationshipType.hasDeclaredLicense, + # [oe.sbom30.get_element_link_id(recipe_spdx_license)], + # ) + + if val := d.getVar("HOMEPAGE"): + recipe.software_homePage = val + + if val := d.getVar("SUMMARY"): + recipe.summary = val + + if val := d.getVar("DESCRIPTION"): + recipe.description = val + + for cpe_id in oe.cve_check.get_cpe_ids( + d.getVar("CVE_PRODUCT"), d.getVar("CVE_VERSION") + ): + recipe.externalIdentifier.append( + oe.spdx30.ExternalIdentifier( + externalIdentifierType=oe.spdx30.ExternalIdentifierType.cpe23, + identifier=cpe_id, + ) + ) - build_objset.set_is_native(is_native) + dep_objsets, dep_recipes = collect_dep_objsets( + d, "static", "static-", oe.spdx30.software_Package + ) - for var in (d.getVar("SPDX_CUSTOM_ANNOTATION_VARS") or "").split(): - build_objset.new_annotation( - build, - "%s=%s" % (var, d.getVar(var)), - oe.spdx30.AnnotationType.other, + if dep_recipes: + recipe_objset.new_scoped_relationship( + [recipe], + oe.spdx30.RelationshipType.dependsOn, + oe.spdx30.LifecycleScopeType.build, + sorted(oe.sbom30.get_element_link_id(dep) for dep in dep_recipes), ) - build_inputs = set() - # Add CVEs cve_by_status = {} if include_vex != "none": @@ -514,7 +562,7 @@ def create_spdx(d): decoded_status = { "mapping": patched_cve["abbrev-status"], "detail": patched_cve["status"], - "description": patched_cve.get("justification", None) + "description": patched_cve.get("justification", None), } # If this CVE is fixed upstream, skip it unless all CVEs are @@ -531,8 +579,7 @@ def create_spdx(d): bb.debug(1, "Skipping %s since it is already fixed upstream" % cve) continue - spdx_cve = build_objset.new_cve_vuln(cve) - build_objset.set_element_alias(spdx_cve) + spdx_cve = recipe_objset.new_cve_vuln(cve) cve_by_status.setdefault(decoded_status["mapping"], {})[cve] = ( spdx_cve, @@ -540,13 +587,118 @@ def create_spdx(d): decoded_status["description"], ) + all_cves = set() + for status, cves in cve_by_status.items(): + for cve, items in cves.items(): + spdx_cve, detail, description = items + spdx_cve_id = oe.sbom30.get_element_link_id(spdx_cve) + + all_cves.add(spdx_cve) + + if status == "Patched": + recipe_objset.new_vex_patched_relationship([spdx_cve_id], [recipe]) + elif status == "Unpatched": + recipe_objset.new_vex_unpatched_relationship([spdx_cve_id], [recipe]) + elif status == "Ignored": + spdx_vex = recipe_objset.new_vex_ignored_relationship( + [spdx_cve_id], + [recipe], + impact_statement=description, + ) + + vex_just_type = d.getVarFlag("CVE_CHECK_VEX_JUSTIFICATION", detail) + if vex_just_type: + if ( + vex_just_type + not in oe.spdx30.security_VexJustificationType.NAMED_INDIVIDUALS + ): + bb.fatal( + f"Unknown vex justification '{vex_just_type}', detail '{detail}', for ignored {cve}" + ) + + for v in spdx_vex: + v.security_justificationType = ( + oe.spdx30.security_VexJustificationType.NAMED_INDIVIDUALS[ + vex_just_type + ] + ) + + elif status == "Unknown": + bb.note(f"Skipping {cve} with status 'Unknown'") + else: + bb.fatal(f"Unknown {cve} status '{status}'") + + if all_cves: + recipe_objset.new_relationship( + [recipe], + oe.spdx30.RelationshipType.hasAssociatedVulnerability, + sorted(list(all_cves)), + ) + + oe.sbom30.write_recipe_jsonld_doc(d, recipe_objset, "static", deploydir) + + +def load_recipe_spdx(d): + + return oe.sbom30.find_root_obj_in_jsonld( + d, + "static", + "static-" + d.getVar("PN"), + oe.spdx30.software_Package, + ) + + +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") + deploydir = Path(d.getVar("SPDXDEPLOY")) + deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) + spdx_workdir = Path(d.getVar("SPDXWORK")) + include_sources = d.getVar("SPDX_INCLUDE_SOURCES") == "1" + pkg_arch = d.getVar("SSTATE_PKGARCH") + is_native = bb.data.inherits_class("native", d) or bb.data.inherits_class( + "cross", d + ) + + recipe, recipe_objset = load_recipe_spdx(d) + + build_objset = oe.sbom30.ObjectSet.new_objset(d, "build-" + pn) + + build = build_objset.new_task_build("recipe", "recipe") + build_objset.set_element_alias(build) + + build_objset.doc.rootElement.append(build) + + build_objset.set_is_native(is_native) + + for var in (d.getVar("SPDX_CUSTOM_ANNOTATION_VARS") or "").split(): + build_objset.new_annotation( + build, + "%s=%s" % (var, d.getVar(var)), + oe.spdx30.AnnotationType.other, + ) + + build_inputs = set() + cpe_ids = oe.cve_check.get_cpe_ids(d.getVar("CVE_PRODUCT"), d.getVar("CVE_VERSION")) source_files = add_download_files(d, build_objset) build_inputs |= source_files recipe_spdx_license = add_license_expression( - d, build_objset, d.getVar("LICENSE"), license_data + d, build_objset, d.getVar("LICENSE"), license_data, [recipe_objset] ) build_objset.new_relationship( source_files, @@ -575,7 +727,10 @@ def create_spdx(d): build_inputs |= files index_sources_by_hash(files, dep_sources) - dep_objsets, dep_builds = collect_dep_objsets(d, build) + dep_objsets, dep_builds = collect_dep_objsets( + d, "builds", "build-", oe.spdx30.build_Build + ) + if dep_builds: build_objset.new_scoped_relationship( [build], @@ -587,6 +742,22 @@ def create_spdx(d): debug_source_ids = set() source_hash_cache = {} + # Collect all VEX statements from the recipe + vex_statements = {} + for rel in recipe_objset.foreach_filter( + oe.spdx30.Relationship, + relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability, + ): + for cve in rel.to: + vex_statements[cve] = [] + + for cve in vex_statements.keys(): + for rel in recipe_objset.foreach_filter( + oe.spdx30.security_VexVulnAssessmentRelationship, + from_=cve, + ): + vex_statements[cve].append(rel) + # Write out the package SPDX data now. It is not complete as we cannot # write the runtime data, so write it to a staging area and a later task # will write out the final collection @@ -645,16 +816,7 @@ def create_spdx(d): or "" ).split() - if purls: - spdx_package.software_packageUrl = purls[0] - - for p in sorted(set(purls)): - spdx_package.externalIdentifier.append( - oe.spdx30.ExternalIdentifier( - externalIdentifierType=oe.spdx30.ExternalIdentifierType.packageUrl, - identifier=p, - ) - ) + set_purls(spdx_package, purls) pkg_objset.new_scoped_relationship( [oe.sbom30.get_element_link_id(build)], @@ -663,6 +825,13 @@ def create_spdx(d): [spdx_package], ) + pkg_objset.new_scoped_relationship( + [oe.sbom30.get_element_link_id(recipe)], + oe.spdx30.RelationshipType.generates, + oe.spdx30.LifecycleScopeType.build, + [spdx_package], + ) + for cpe_id in cpe_ids: spdx_package.externalIdentifier.append( oe.spdx30.ExternalIdentifier( @@ -696,7 +865,11 @@ def create_spdx(d): package_license = d.getVar("LICENSE:%s" % package) if package_license and package_license != d.getVar("LICENSE"): package_spdx_license = add_license_expression( - d, build_objset, package_license, license_data + d, + build_objset, + package_license, + license_data, + [recipe_objset], ) else: package_spdx_license = recipe_spdx_license @@ -721,58 +894,41 @@ def create_spdx(d): [oe.sbom30.get_element_link_id(concluded_spdx_license)], ) - # NOTE: CVE Elements live in the recipe collection - all_cves = set() - for status, cves in cve_by_status.items(): - for cve, items in cves.items(): - spdx_cve, detail, description = items - spdx_cve_id = oe.sbom30.get_element_link_id(spdx_cve) - - all_cves.add(spdx_cve_id) + # Copy CVEs from recipe + if vex_statements: + pkg_objset.new_relationship( + [spdx_package], + oe.spdx30.RelationshipType.hasAssociatedVulnerability, + sorted( + oe.sbom30.get_element_link_id(cve) + for cve in vex_statements.keys() + ), + ) - if status == "Patched": + for cve, vexes in vex_statements.items(): + for vex in vexes: + if vex.relationshipType == oe.spdx30.RelationshipType.fixedIn: pkg_objset.new_vex_patched_relationship( - [spdx_cve_id], [spdx_package] + [oe.sbom30.get_element_link_id(cve)], [spdx_package] ) - elif status == "Unpatched": + elif vex.relationshipType == oe.spdx30.RelationshipType.affects: pkg_objset.new_vex_unpatched_relationship( - [spdx_cve_id], [spdx_package] + [oe.sbom30.get_element_link_id(cve)], [spdx_package] ) - elif status == "Ignored": + elif ( + vex.relationshipType == oe.spdx30.RelationshipType.doesNotAffect + ): spdx_vex = pkg_objset.new_vex_ignored_relationship( - [spdx_cve_id], + [oe.sbom30.get_element_link_id(cve)], [spdx_package], - impact_statement=description, + impact_statement=vex.security_impactStatement, ) - vex_just_type = d.getVarFlag( - "CVE_CHECK_VEX_JUSTIFICATION", detail - ) - if vex_just_type: - if ( - vex_just_type - not in oe.spdx30.security_VexJustificationType.NAMED_INDIVIDUALS - ): - bb.fatal( - f"Unknown vex justification '{vex_just_type}', detail '{detail}', for ignored {cve}" - ) - + if vex.security_justificationType: for v in spdx_vex: - v.security_justificationType = oe.spdx30.security_VexJustificationType.NAMED_INDIVIDUALS[ - vex_just_type - ] - - elif status == "Unknown": - bb.note(f"Skipping {cve} with status 'Unknown'") - else: - bb.fatal(f"Unknown {cve} status '{status}'") - - if all_cves: - pkg_objset.new_relationship( - [spdx_package], - oe.spdx30.RelationshipType.hasAssociatedVulnerability, - sorted(list(all_cves)), - ) + v.security_justificationType = ( + vex.security_justificationType + ) bb.debug(1, "Adding package files to SPDX for package %s" % pkg_name) package_files = add_package_files( @@ -851,14 +1007,15 @@ def create_spdx(d): status = "enabled" if feature in enabled else "disabled" build.build_parameter.append( oe.spdx30.DictionaryEntry( - key=f"PACKAGECONFIG:{feature}", - value=status + key=f"PACKAGECONFIG:{feature}", value=status ) ) - bb.note(f"Added PACKAGECONFIG entries: {len(enabled)} enabled, {len(disabled)} disabled") + bb.note( + f"Added PACKAGECONFIG entries: {len(enabled)} enabled, {len(disabled)} disabled" + ) - oe.sbom30.write_recipe_jsonld_doc(d, build_objset, "recipes", deploydir) + oe.sbom30.write_recipe_jsonld_doc(d, build_objset, "builds", deploydir) def create_package_spdx(d): @@ -1197,17 +1354,17 @@ def create_image_spdx(d): image_path = image_deploy_dir / image_filename if os.path.isdir(image_path): a = add_package_files( - d, - objset, - image_path, - lambda file_counter: objset.new_spdxid( - "imagefile", str(file_counter) - ), - lambda filepath: [], - license_data=None, - ignore_dirs=[], - ignore_top_level_dirs=[], - archive=None, + d, + objset, + image_path, + lambda file_counter: objset.new_spdxid( + "imagefile", str(file_counter) + ), + lambda filepath: [], + license_data=None, + ignore_dirs=[], + ignore_top_level_dirs=[], + archive=None, ) artifacts.extend(a) else: @@ -1234,7 +1391,6 @@ def create_image_spdx(d): set_timestamp_now(d, a, "builtTime") - if artifacts: objset.new_scoped_relationship( [image_build], diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index 5830d7c087..759ca86b73 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -141,6 +141,11 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): SPDX_CLASS = "create-spdx-3.0" def test_base_files(self): + self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/static/static-base-files.spdx.json", + task="create_recipe_spdx", + ) self.check_recipe_spdx( "base-files", "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", @@ -149,7 +154,7 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): def test_gcc_include_source(self): objset = self.check_recipe_spdx( "gcc", - "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/recipes/recipe-gcc.spdx.json", + "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/builds/build-gcc.spdx.json", extraconf="""\ SPDX_INCLUDE_SOURCES = "1" """, @@ -162,12 +167,12 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): if software_file.name == filename: found = True self.logger.info( - f"The spdxId of {filename} in recipe-gcc.spdx.json is {software_file.spdxId}" + f"The spdxId of {filename} in build-gcc.spdx.json is {software_file.spdxId}" ) break self.assertTrue( - found, f"Not found source file {filename} in recipe-gcc.spdx.json\n" + found, f"Not found source file {filename} in build-gcc.spdx.json\n" ) def test_core_image_minimal(self): @@ -305,7 +310,7 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): # This will fail with NameError if new_annotation() is called incorrectly objset = self.check_recipe_spdx( "base-files", - "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/recipes/recipe-base-files.spdx.json", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/builds/build-base-files.spdx.json", extraconf=textwrap.dedent( f"""\ ANNOTATION1 = "{ANNOTATION_VAR1}" @@ -360,8 +365,8 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): def test_kernel_config_spdx(self): kernel_recipe = get_bb_var("PREFERRED_PROVIDER_virtual/kernel") - spdx_file = f"recipe-{kernel_recipe}.spdx.json" - spdx_path = f"{{DEPLOY_DIR_SPDX}}/{{SSTATE_PKGARCH}}/recipes/{spdx_file}" + spdx_file = f"build-{kernel_recipe}.spdx.json" + spdx_path = f"{{DEPLOY_DIR_SPDX}}/{{SSTATE_PKGARCH}}/builds/{spdx_file}" # Make sure kernel is configured first bitbake(f"-c configure {kernel_recipe}") @@ -392,7 +397,7 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): def test_packageconfig_spdx(self): objset = self.check_recipe_spdx( "tar", - "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/recipes/recipe-tar.spdx.json", + "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/builds/build-tar.spdx.json", extraconf="""\ SPDX_INCLUDE_PACKAGECONFIG = "1" """, From patchwork Tue Mar 10 18:38:24 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83009 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8CF2CFD4F2A for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f177.google.com (mail-oi1-f177.google.com [209.85.167.177]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2595.1773168067871544730 for ; Tue, 10 Mar 2026 11:41:07 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=V9IqUOg4; spf=pass (domain: gmail.com, ip: 209.85.167.177, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f177.google.com with SMTP id 5614622812f47-46703fb602fso953794b6e.0 for ; Tue, 10 Mar 2026 11:41:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168067; x=1773772867; 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; bh=vTEs0ehcHll89HzxGCoaETOYfkK7ZCZMY3NvuGYxHJM=; b=V9IqUOg49UespN8oudqYbz/cusVZilnj0Ci5G6j01mpcUAIIdcXf88g9IqCdhflUCA p5pXHB3T57QZvUSxrSsV8Sx7QA3Zi+1ybaPhg7z6u93bu9bvJhnHYkB8pCnHaTvPh96W YRlP6ZAxpImwdA6jIovSUY34p2MiTJdxItKMsU8FVfIC2vULmp+vTeRrtCJCkkjHwlLE QE+EGbtwH5nP4x9AObiRo+QX4Kqv8qqSTwM8dADlxL8hKB18PqJbenWo8yF1SRAuygSe ggZBQWoDXrMoJGp63j8fIvHtpGW8mh2802dhcVH3n3xTuOGFxCN3mVA7tsI8OI/ni2ly eIUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168067; x=1773772867; 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; bh=vTEs0ehcHll89HzxGCoaETOYfkK7ZCZMY3NvuGYxHJM=; b=V9/oCqaILdyiJhj3msYKwx1b9lgqmTDGJMCziMCidh1IZDiN9EJDDM6tC0b7Svk0Yl 19I7zJa1COCE+cpWnL/SkBXQpCvFqmnnom0KR1oNzF5Tvd5ah7K4x6Bqjnn8mHygk5af FEblTQZeoLMtHr0DjqRuOqCiCSrxCoJ0HpKZfsezAgsR22zCSTre1xysXfRVkmeXkSg1 ralK9cRIGxWMNp71L6wZJbnftMixG4xvm923WVcshN+HSG7O5x0nGBefzELJ0JUSy6HW 3niBuKe0BeiF7WdRVLg4Uan86X2OZMt7e3Eq7pcJkMUKaKOy6VAM/qR/7GdK9yXLssyU BqIg== X-Gm-Message-State: AOJu0YxteGJdpFR+eN1dMRttKFRDCU7rADGWkIzSlq+OXN3QYqBW0SDI 30xCmL7B2AvkAZHNk7/D3MWhBzQYRXD36KajvSCP0q5Z4K7+rbwf0XdAHNwHeQ== X-Gm-Gg: ATEYQzwArCSHUMLJFkI8n35+2dELqPmez+cML9C4Umltg50ErJcgU5oVmvhjEKKoR0C ld0zbod3xBeHg2aoeLxwnw1jqXQVNMZx6uTxDP/6a0OrtWx8aa+6igvrXyyzGiXlVeNdT0rWeJL aWou3boZ6MWO4dBd9Cz6wjqO97tvNNZHIK+Ic2/uj+v/IfdbQwSsez47172j9Es4u9DV7GV8gkz kStosYq5RVEp4a894+No1QFvRCygCa+wMXsad1iuR4HzHh+IJYG/IlcIAhEAsCBM4KhuQB9ETE6 50pRv9i+C9Z28PBtY8R6krwqb8tGkN9nJ0JoeosTH9pW99f7M6kfpwrEM74wnZn0LLyHKkCq7jP to42M6ulJnZRVkNzAZrHVMJCh7gZIjfsPkc/W5aKiFx9lcN6GvAH3UBP6Sz4MEEhg1oTIi3F75f axTb5/CvF0WywfeLIuVV68 X-Received: by 2002:a05:6808:179e:b0:467:1cf5:768b with SMTP id 5614622812f47-4671cf84823mr2298820b6e.10.1773168066933; Tue, 10 Mar 2026 11:41:06 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:06 -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 04/15] spdx3: Add recipe SBoM task Date: Tue, 10 Mar 2026 12:38:24 -0600 Message-ID: <20260310184058.533343-5-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232815 Adds a task that will create the complete recipe-level SBoM for a given target recipe, following all dependencies. For example: ``` bitbake -c create_recipe_sbom zstd ``` Would produce the complete recipe SBoM for the zstd recipe, include all build time dependencies (recursively). The complete SBoM for all (target) recipes can be built with: ``` bitbake -c create_recipe_sbom meta-world-recipe-sbom ``` Signed-off-by: Joshua Watt --- meta/classes/create-spdx-3.0.bbclass | 32 +++++++++++++++++++ meta/classes/spdx-common.bbclass | 1 + meta/conf/distro/include/maintainers.inc | 1 + meta/lib/oe/spdx30_tasks.py | 10 ++++++ meta/lib/oeqa/selftest/cases/spdx.py | 10 ++++++ .../meta/meta-world-recipe-sbom.bb | 29 +++++++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 meta/recipes-core/meta/meta-world-recipe-sbom.bb diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 672ca27cd0..c3ea95b8bc 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -142,6 +142,10 @@ SPDX_PACKAGE_URLS[doc] = "A space separated list of Package URLs (purls) for \ Override this variable to replace the default, otherwise append or prepend \ to add additional purls." +SPDX_RECIPE_SBOM_NAME ?= "${PN}-recipe-sbom" +SPDX_RECIPE_SBOM_NAME[doc] = "The name of output recipe SBoM when using \ + create_recipe_sbom" + IMAGE_CLASSES:append = " create-spdx-image-3.0" SDK_CLASSES += "create-spdx-sdk-3.0" @@ -240,6 +244,34 @@ python do_create_package_spdx_setscene () { } addtask do_create_package_spdx_setscene +addtask do_create_recipe_sbom after create_recipe_spdx +python do_create_recipe_sbom() { + import oe.spdx30_tasks + from pathlib import Path + deploydir = Path(d.getVar("SPDXRECIPESBOMDEPLOY")) + oe.spdx30_tasks.create_recipe_sbom(d, deploydir) +} + +SSTATETASKS += "do_create_recipe_sbom" +do_create_recipe_sbom[recrdeptask] = "do_create_recipe_spdx" +do_create_recipe_sbom[nostamp] = "1" +do_create_recipe_sbom[sstate-inputdirs] = "${SPDXRECIPESBOMDEPLOY}" +do_create_recipe_sbom[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" +do_create_recipe_sbom[file-checksums] += "${SPDX3_DEP_FILES}" +do_create_recipe_sbom[cleandirs] = "${SPDXRECIPESBOMDEPLOY}" +do_create_recipe_sbom[vardeps] += "\ + SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ + SPDX_PACKAGE_ADDITIONAL_PURPOSE \ + SPDX_PROFILES \ + SPDX_NAMESPACE_PREFIX \ + SPDX_UUID_NAMESPACE \ + " + +python do_create_recipe_sbom_setscene () { + sstate_setscene(d) +} +addtask do_create_recipe_sbom_setscene + python spdx30_build_started_handler () { import oe.spdx30_tasks d = e.data.createCopy() diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index 3c239a718b..abf2332bee 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -25,6 +25,7 @@ SPDX_TOOL_VERSION ??= "1.0" SPDXRECIPEDEPLOY = "${SPDXDIR}/recipe-deploy" SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" +SPDXRECIPESBOMDEPLOY = "${SPDXDIR}/recipes-bom-deploy" SPDX_INCLUDE_SOURCES ??= "0" SPDX_INCLUDE_COMPILED_SOURCES ??= "0" diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc index 3c7fc4974d..40e090d452 100644 --- a/meta/conf/distro/include/maintainers.inc +++ b/meta/conf/distro/include/maintainers.inc @@ -535,6 +535,7 @@ RECIPE_MAINTAINER:pn-meta-go-toolchain = "Richard Purdie X-Patchwork-Id: 83012 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9BF98FD4F29 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f169.google.com (mail-oi1-f169.google.com [209.85.167.169]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2596.1773168068450317275 for ; Tue, 10 Mar 2026 11:41:08 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BeNX+j4z; spf=pass (domain: gmail.com, ip: 209.85.167.169, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f169.google.com with SMTP id 5614622812f47-467161c4b89so1195595b6e.3 for ; Tue, 10 Mar 2026 11:41:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168067; x=1773772867; 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; bh=+wYSZS61IRGHmLD9OmiNc9hgO2b0xZj5mQwHOFCwfH8=; b=BeNX+j4zF5itTfIu7GGO2a+HcMoibJb2bCi1cd86WPG4FcYcYLpIPUwPO9LxI6tsyu XJHSgBrjA8laD/zvEh5psRLVSdOnme4fcYoZoOH20QawCeCNqveZ7JJrTZNLRiiJ9ZKJ S/1aWHNjGGRVlsPIWNFq4sdSYQiq/9dnWuN7rpavpfkohePiv+qlDZaqAvy3sXE5mp/z iwLbxJgWUAOpcxNAcRyi97NysHE791c5anxFlOIZFd409l4SQAUA2g8OsrkGY7XT4uGs xYxq+Cf9iEV8hLvJHFCpvp5uriDbNr7bHBwRTv9O0LwmQW+ml/5l3TxiGTat+4fCnola sKtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168067; x=1773772867; 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; bh=+wYSZS61IRGHmLD9OmiNc9hgO2b0xZj5mQwHOFCwfH8=; b=a0LiS0xVClME+hdx1FfAjD1h3QeAPdBMX6ah6xWma3iqzsjEWkS8wD5k447OcW1g3h A85ZR/GZkmiRB2ZMxuOW+8PGkqWk/VioGB0nc4R8FTR1dDjD+/jxnxOivGH0rv0r7Dem AG+Z0cO7ZQjiFdvdwcuDsNQ5Am/i5NZbGS5fJp2HF66UtLEe769KcXtYB/o5lMRRE7kb AVrtyFbHXWd0F+kMINYex7HkXeaBeVWgCOA+UUXFcfDBBMoi9M98jMJGkopcvl1ENo2E 0oiQActaEzcwVxnlHzK6I46E0fEDt9mSVE8n2jcWRty8Zbrj3bLuIrc5uriFqWaxcUxq MuAA== X-Gm-Message-State: AOJu0Yy4r+WvtPB9hE1NFG49ZiO0zMfxeq88yi7Jj0TvPfPw63PAWvUR I6UqgYoatRVGcHebkkeGZxPeVjtuZt6kYzhoPpgIIFFCWlLMdHea9yA9dpFJtg== X-Gm-Gg: ATEYQzypZ0hM4dF7mRdMpVjGSPB0jfy2coA7dAjOQE6a1S0ko9RfJYxN5SNSVr+VQ4J oWcXnxqwDk3GC82Uoc+/HSx2TpocZKzSKzu67ep94Y+qX635Pb8ZKvuMu1y+5kyV85r9imFn1cK 1XvgXf6DEgC0hjzAQYHbRWzh9tjjnLM4SZi8NYBnWv3iH3m8N73laiEllFP6Zv9zDG70/HR3rA8 CMopOV3KQhptGN/ggjqbA85AvBWxNfVfzSB4dwa/GKxwq2mVd9+gFsJufMiHd1q3537VidzUtVI W4GPgQRL9GVUIucsBbymXVuQaChtOBNay9F5PRm5VTCwaYHygVkjgzCtMwZfvc39cCYbRViGMY1 CG3LGpHIBCYWPUOLAB1yfSaNe8iZFjhuxOX09pBIOwaDjMaygHCbA4NOjJ/tJLCBfr2hJgrqjeQ +agZIeyuFxSlHSq8/al6oL X-Received: by 2002:a05:6808:5093:b0:467:db8:e46d with SMTP id 5614622812f47-4670db8f589mr4454510b6e.34.1773168067617; Tue, 10 Mar 2026 11:41:07 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:07 -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 05/15] spdx3: Add is-native property Date: Tue, 10 Mar 2026 12:38:25 -0600 Message-ID: <20260310184058.533343-6-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232816 Adds a custom is-native property to the recipe package to indicate if it is a native recipe Signed-off-by: Joshua Watt --- meta/lib/oe/sbom30.py | 20 ++++++++++++++++++++ meta/lib/oe/spdx30_tasks.py | 18 +++++++++++------- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py index 227ac51877..50a72fce39 100644 --- a/meta/lib/oe/sbom30.py +++ b/meta/lib/oe/sbom30.py @@ -118,6 +118,26 @@ class OEDocumentExtension(oe.spdx30.extension_Extension): ) +@oe.spdx30.register(OE_SPDX_BASE + "recipe-extension") +class OERecipeExtension(oe.spdx30.extension_Extension): + """ + This extension is added to recipe software_Packages to indicate various + useful bits of information about the recipe + """ + + CLOSED = True + + @classmethod + def _register_props(cls): + super()._register_props() + cls._add_property( + "is_native", + oe.spdx30.BooleanProp(), + OE_SPDX_BASE + "is-native", + max_count=1, + ) + + def spdxid_hash(*items): h = hashlib.md5() for i in items: diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index b6c917045e..a8fffbb085 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -477,6 +477,10 @@ def set_purls(spdx_package, purls): ) +def get_is_native(d): + return bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d) + + def create_recipe_spdx(d): deploydir = Path(d.getVar("SPDXRECIPEDEPLOY")) deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) @@ -507,6 +511,11 @@ def create_recipe_spdx(d): ) ) + if get_is_native(d): + ext = oe.sbom30.OERecipeExtension() + ext.is_native = True + recipe.extension.append(ext) + set_purls(recipe, (d.getVar("SPDX_PACKAGE_URLS") or "").split()) # TODO: This doesn't work before do_unpack because the license text has to @@ -668,9 +677,7 @@ def create_spdx(d): spdx_workdir = Path(d.getVar("SPDXWORK")) include_sources = d.getVar("SPDX_INCLUDE_SOURCES") == "1" pkg_arch = d.getVar("SSTATE_PKGARCH") - is_native = bb.data.inherits_class("native", d) or bb.data.inherits_class( - "cross", d - ) + is_native = get_is_native(d) recipe, recipe_objset = load_recipe_spdx(d) @@ -1021,14 +1028,11 @@ def create_spdx(d): def create_package_spdx(d): deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) deploydir = Path(d.getVar("SPDXRUNTIMEDEPLOY")) - is_native = bb.data.inherits_class("native", d) or bb.data.inherits_class( - "cross", d - ) providers = oe.spdx_common.collect_package_providers(d) pkg_arch = d.getVar("SSTATE_PKGARCH") - if is_native: + if get_is_native(d): return bb.build.exec_func("read_subpackage_metadata", d) From patchwork Tue Mar 10 18:38:26 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83015 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 292D9FD4F24 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f179.google.com (mail-oi1-f179.google.com [209.85.167.179]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2663.1773168069370836584 for ; Tue, 10 Mar 2026 11:41:09 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=T4g2eDfP; spf=pass (domain: gmail.com, ip: 209.85.167.179, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f179.google.com with SMTP id 5614622812f47-464ba2bb3aeso143168b6e.1 for ; Tue, 10 Mar 2026 11:41:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168068; x=1773772868; 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; bh=GygUv99XXYXKewxHRq+dVr3zF/qZkskkMg0YO5XWbQU=; b=T4g2eDfPW8cYNKW1/g/HfHq2WIP29DthiWFAp7Asev7h8F2JjvxiZC/ULUgekXACjS /DAm0+LVxdBnOr+C+zuM6ua2E2Z5mWq69V1T9Gw7+lr21oy8By5DqEdeb03ht11/Yfvq t8FVoBJSwSavJKK1qpMPmXJBvDlzF2bAGsz2FeiCr/iQf7KGtfnyl4d1w3Y/3dUJLD5t +C0zcFqzrc2pXHaMPv2GeqLGxUAFzLq1wVGOelJFrXHhYBZ1YurE53YcGaPuIiyHxeka mIeY42rJPZmjgg46UPxFkR0zzUTF8zDiADg59ykWNjcgGPT3X2d6+k6goiQxVD/2e3IT n/ng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168068; x=1773772868; 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; bh=GygUv99XXYXKewxHRq+dVr3zF/qZkskkMg0YO5XWbQU=; b=oDClFR5fVnmSBJRugL1NsktZQI1zcpGa7vnIObHun87dt1G/hbsGzuc+oDPUcn+wvW 8EilUJZrP+lQu6U2ep9Z5tyP/UQtydqGH7//M5hY3DsMUaca08Cv/dGXDjQal9/zgD8v Dm14kBxzrAlNpqXvevnSH6b7Zs9/tZbX2xqb6lYWykkIIe8iZV+N9XPvNJpE+kSSNm3D FrkJEHimjR5r39o4Vz0EI7rSphcrrn5FmASp1F1ujNYmFbMxuMveIT6J4N01ufwRjeow PFIFGszidOEZQis7bZqFwrfLvoRIdtvK/OOLt5JoFvpgiC8m0GVXbCenDNVpK2jsv8H2 4ycQ== X-Gm-Message-State: AOJu0Yzh10bhymDaBAA14JDCyOJ+O/iXqqocc7eAhfBeOa/0Tsta8BjD mGn3oA2piEVC9YWdz6nKWBQlk9fQBNvZvW0GGrgdVsZ+Qra3X5GJaBrYajwGPQ== X-Gm-Gg: ATEYQzz+rGta4QG16qyVFTVda4k+q7TFBGDzTDSTDHz2Ya4HpaMsfOzw2mzyxc3Bh44 8I98SBI1R0kZSPDRtl/heB4GTbwd5xLnbeN24Dxe2K0g5Dt3GQUoBi3AOpCg/BiW0NOn+VYxaN9 DxwtO6w5LWtiYfBrVU0v9IQzIjGwrdOhp04jtTfeaBqEp2EfiITJmNZuyTjtVphkoA/EP7Yh52H T52NjcRG3Or4K0mJzdvOCRy9EJSLrJb2KfBBtCfEjIDdfjNWeWwCvjzrrhWIIQOJoK++5VFWrDC hgdCaFnP7yJTFv+qb8gKTUZYNDb2WGpwGccKuR6MnPoTLEwIngm172djpi8gRoivjM4GXcE1/qi d5UHrMPq0HJ+jzk8uyvOwgx6EF3sM6MRXnmMNDXics50wcmC3uEq2/KHy6z1T19G97fH5+NJgBf yS6gKO7xjDUnPAqlzLogOd X-Received: by 2002:a05:6808:1990:b0:45c:85fa:5a3e with SMTP id 5614622812f47-4671bfb6b05mr2545745b6e.25.1773168068417; Tue, 10 Mar 2026 11:41:08 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:07 -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 06/15] spdx30: Include patch file information in VEX Date: Tue, 10 Mar 2026 12:38:26 -0600 Message-ID: <20260310184058.533343-7-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232817 Modifies the SPDX VEX output to include the patches that fix a particular vulnerability. This is done by adding a `patchedBy` relationship from the `VexFixedVulnAssessmentRelationship` to the `File` that provides the fix. If the file can be located without fetching (e.g. is a file:// in SRC_URI), the checksum will be included. Signed-off-by: Joshua Watt --- meta/lib/oe/sbom30.py | 60 ++++++++++++++------------- meta/lib/oe/spdx30_tasks.py | 81 ++++++++++++++++++++++++++++--------- 2 files changed, 92 insertions(+), 49 deletions(-) diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py index 50a72fce39..21f084dc16 100644 --- a/meta/lib/oe/sbom30.py +++ b/meta/lib/oe/sbom30.py @@ -620,37 +620,38 @@ class ObjectSet(oe.spdx30.SHACLObjectSet): ) spdx_file.extension.append(OELicenseScannedExtension()) - def new_file(self, _id, name, path, *, purposes=[]): - sha256_hash = bb.utils.sha256_file(path) + def new_file(self, _id, name, path, *, purposes=[], hashfile=True): + if hashfile: + sha256_hash = bb.utils.sha256_file(path) - for f in self.by_sha256_hash.get(sha256_hash, []): - if not isinstance(f, oe.spdx30.software_File): - continue + for f in self.by_sha256_hash.get(sha256_hash, []): + if not isinstance(f, oe.spdx30.software_File): + continue - if purposes: - new_primary = purposes[0] - new_additional = [] + if purposes: + new_primary = purposes[0] + new_additional = [] - if f.software_primaryPurpose: - new_additional.append(f.software_primaryPurpose) - new_additional.extend(f.software_additionalPurpose) + if f.software_primaryPurpose: + new_additional.append(f.software_primaryPurpose) + new_additional.extend(f.software_additionalPurpose) - new_additional = sorted( - list(set(p for p in new_additional if p != new_primary)) - ) + new_additional = sorted( + list(set(p for p in new_additional if p != new_primary)) + ) - f.software_primaryPurpose = new_primary - f.software_additionalPurpose = new_additional + f.software_primaryPurpose = new_primary + f.software_additionalPurpose = new_additional - if f.name != name: - for e in f.extension: - if isinstance(e, OEFileNameAliasExtension): - e.aliases.append(name) - break - else: - f.extension.append(OEFileNameAliasExtension(aliases=[name])) + if f.name != name: + for e in f.extension: + if isinstance(e, OEFileNameAliasExtension): + e.aliases.append(name) + break + else: + f.extension.append(OEFileNameAliasExtension(aliases=[name])) - return f + return f spdx_file = oe.spdx30.software_File( _id=_id, @@ -661,12 +662,13 @@ class ObjectSet(oe.spdx30.SHACLObjectSet): spdx_file.software_primaryPurpose = purposes[0] spdx_file.software_additionalPurpose = purposes[1:] - spdx_file.verifiedUsing.append( - oe.spdx30.Hash( - algorithm=oe.spdx30.HashAlgorithm.sha256, - hashValue=sha256_hash, + if hashfile: + spdx_file.verifiedUsing.append( + oe.spdx30.Hash( + algorithm=oe.spdx30.HashAlgorithm.sha256, + hashValue=sha256_hash, + ) ) - ) return self.add(spdx_file) diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index a8fffbb085..aec47d4f81 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -568,44 +568,63 @@ def create_recipe_spdx(d): if include_vex != "none": patched_cves = oe.cve_check.get_patched_cves(d) for cve, patched_cve in patched_cves.items(): - decoded_status = { - "mapping": patched_cve["abbrev-status"], - "detail": patched_cve["status"], - "description": patched_cve.get("justification", None), - } + mapping = patched_cve["abbrev-status"] + detail = patched_cve["status"] + description = patched_cve.get("justification", None) + resources = patched_cve.get("resource", []) # If this CVE is fixed upstream, skip it unless all CVEs are # specified. - if ( - include_vex != "all" - and "detail" in decoded_status - and decoded_status["detail"] - in ( - "fixed-version", - "cpe-stable-backport", - ) + if include_vex != "all" and detail in ( + "fixed-version", + "cpe-stable-backport", ): bb.debug(1, "Skipping %s since it is already fixed upstream" % cve) continue spdx_cve = recipe_objset.new_cve_vuln(cve) - cve_by_status.setdefault(decoded_status["mapping"], {})[cve] = ( + cve_by_status.setdefault(mapping, {})[cve] = ( spdx_cve, - decoded_status["detail"], - decoded_status["description"], + detail, + description, + resources, ) all_cves = set() for status, cves in cve_by_status.items(): for cve, items in cves.items(): - spdx_cve, detail, description = items + spdx_cve, detail, description, resources = items spdx_cve_id = oe.sbom30.get_element_link_id(spdx_cve) all_cves.add(spdx_cve) if status == "Patched": - recipe_objset.new_vex_patched_relationship([spdx_cve_id], [recipe]) + spdx_vex = recipe_objset.new_vex_patched_relationship( + [spdx_cve_id], [recipe] + ) + patches = [] + for idx, filepath in enumerate(resources): + patches.append( + recipe_objset.new_file( + recipe_objset.new_spdxid( + "patch", str(idx), os.path.basename(filepath) + ), + os.path.basename(filepath), + filepath, + purposes=[oe.spdx30.software_SoftwarePurpose.patch], + hashfile=os.path.isfile(filepath), + ) + ) + + if patches: + recipe_objset.new_scoped_relationship( + spdx_vex, + oe.spdx30.RelationshipType.patchedBy, + oe.spdx30.LifecycleScopeType.build, + patches, + ) + elif status == "Unpatched": recipe_objset.new_vex_unpatched_relationship([spdx_cve_id], [recipe]) elif status == "Ignored": @@ -751,12 +770,14 @@ def create_spdx(d): # Collect all VEX statements from the recipe vex_statements = {} + vex_patches = {} for rel in recipe_objset.foreach_filter( oe.spdx30.Relationship, relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability, ): for cve in rel.to: vex_statements[cve] = [] + vex_patches[cve] = [] for cve in vex_statements.keys(): for rel in recipe_objset.foreach_filter( @@ -764,6 +785,13 @@ def create_spdx(d): from_=cve, ): vex_statements[cve].append(rel) + if rel.relationshipType == oe.spdx30.RelationshipType.fixedIn: + for patch_rel in recipe_objset.foreach_filter( + oe.spdx30.Relationship, + relationshipType=oe.spdx30.RelationshipType.patchedBy, + from_=rel, + ): + vex_patches[cve].extend(patch_rel.to) # Write out the package SPDX data now. It is not complete as we cannot # write the runtime data, so write it to a staging area and a later task @@ -889,7 +917,9 @@ def create_spdx(d): # Add concluded license relationship if manually set # Only add when license analysis has been explicitly performed - concluded_license_str = d.getVar("SPDX_CONCLUDED_LICENSE:%s" % package) or d.getVar("SPDX_CONCLUDED_LICENSE") + concluded_license_str = d.getVar( + "SPDX_CONCLUDED_LICENSE:%s" % package + ) or d.getVar("SPDX_CONCLUDED_LICENSE") if concluded_license_str: concluded_spdx_license = add_license_expression( d, build_objset, concluded_license_str, license_data @@ -915,9 +945,20 @@ def create_spdx(d): for cve, vexes in vex_statements.items(): for vex in vexes: if vex.relationshipType == oe.spdx30.RelationshipType.fixedIn: - pkg_objset.new_vex_patched_relationship( + spdx_vex = pkg_objset.new_vex_patched_relationship( [oe.sbom30.get_element_link_id(cve)], [spdx_package] ) + if vex_patches[cve]: + pkg_objset.new_scoped_relationship( + spdx_vex, + oe.spdx30.RelationshipType.patchedBy, + oe.spdx30.LifecycleScopeType.build, + [ + oe.sbom30.get_element_link_id(p) + for p in vex_patches[cve] + ], + ) + elif vex.relationshipType == oe.spdx30.RelationshipType.affects: pkg_objset.new_vex_unpatched_relationship( [oe.sbom30.get_element_link_id(cve)], [spdx_package] From patchwork Tue Mar 10 18:38:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83010 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C555FFD4F2E for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f173.google.com (mail-oi1-f173.google.com [209.85.167.173]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2598.1773168070193413725 for ; Tue, 10 Mar 2026 11:41:10 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=MbWwcSK5; spf=pass (domain: gmail.com, ip: 209.85.167.173, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f173.google.com with SMTP id 5614622812f47-4648447e29bso4944823b6e.0 for ; Tue, 10 Mar 2026 11:41:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168069; x=1773772869; 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; bh=RgZWWYUETcp+KAK54Y1gHYnk1xGLeXOCGllecsNhDhw=; b=MbWwcSK5rLmuau7f6BXPolyL0RsSqJbSf6rczXrI+Zz0vTHsI8rVlYjWD2v/hulh+3 1f36YRhAE+yrM3vh8xqlGUbx9vqhi3dOfucBFf5wbaeIoBNWB71kyU1HjrxmDB6aINRk 8q4dXJr8GtBlxdZZ1qsbiPtRqJ+llTVKdyJDCMiAC+Tvpuc1+7AN1rEhIkfBXjZv64Cg cBLcapRrMSyCsKsT0aZ0oLMnH04pA7Q2J+v2KniamEte0migq1c60geFJWvu6Ja3QtXI fdo/ts7TOinODxMwBrVSV/sBscuzIZUxtELcwyszm7uY2ImdwUTDFmnahDPFJskKIyeU LmDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168069; x=1773772869; 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; bh=RgZWWYUETcp+KAK54Y1gHYnk1xGLeXOCGllecsNhDhw=; b=QPuRz4BGvsflc1qsHd2GmDawBmTOVPkNmXFbv/yx9nnOI2AADaAJVABdKJAvO9Jt5r 3btIFXq2JVv9WXn11uYuyS9JSoHbnGRhoXVXen88jGre+1kekY9xpR4iI4NqYUVSm7NO xGCXVvY2Di/kvl9MQwlePvm99LrK3GwpTYmwGUAvMN2UmgW2fWAebogcWYtP/HOj0DuN TXpxLiLogIrTJozziKEEywoHOPYo0jTugeeYf3U/oveORflLo6+TqJH845Hj9CetQ/md xLdtZGLVVtk65FFtCrQBnGFhwRaG9ZPgVmL/feg3TMUfrNvOQsMF9yEPUyyU1zX4RoQk qBmA== X-Gm-Message-State: AOJu0YzsQ6z1JyhAdknvv809utuLETsxU2GmaLJZ+WYQu8sxsS+TH9A4 epBsGd22dv2a4sBHlEfZKZdn3nfGkTQiEfxZuwE1dh09+WLciAvipMmsNeD/+A== X-Gm-Gg: ATEYQzw0Mj4cDbkg9bWwI7WGkDKO6CJKSVO2RKq33m/h2qHG3uLVyovI6rC7LB9o+Wa BsX3a5AtnDufSUVBqh+D/VcZc5TBaPtZltcB1APotKkvjiEtbFPFxzVUJPLmCa+bFs1N7fQTJjQ luQxoDopQSXsYX/5iwfWDuXfyrKUFhgO8UsWTfBFiGEonQV3WhdAo5aM1jTKpJw89WZ9j3ckQbj t+bqkfMzH4k8SCmFB3WPguQ9Gg35dXMyrPW2fLzZyNXQbQbiBhVTI7cHXlyO8zsdwYhH2lO1S0O Qny5wikrUZvny219IEmAMu9wtAHUZUcrCJzpQWdzf/BoU0kePgU7tlMPc7ugkTkQNhfdWl9nMfr E96z2Te3o4cC4Mt9dTY6RdsQZyyDrXH5nctIXHny7o8NKE9l5rOD/c8AUSUiBtiZxLcoZ8GSaI1 5IhcdPtE0zD06N8aUDCNtd X-Received: by 2002:a05:6808:c3c4:b0:450:471:b9ba with SMTP id 5614622812f47-466dcaa9ffdmr8591224b6e.14.1773168069157; Tue, 10 Mar 2026 11:41:09 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:08 -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 07/15] spdx: De-duplicate CreationInfo Date: Tue, 10 Mar 2026 12:38:27 -0600 Message-ID: <20260310184058.533343-8-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232818 De-duplicates CreationInfo objects that are identical (except for ID) when writing out an SBoM. This significantly reduces the number of CreationInfo objects that end up in the final document. Signed-off-by: Joshua Watt --- meta/lib/oe/sbom30.py | 112 ++++++++++++++++++++++++++++++------------ meta/lib/oe/spdx30.py | 2 +- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py index 21f084dc16..55a2863d2d 100644 --- a/meta/lib/oe/sbom30.py +++ b/meta/lib/oe/sbom30.py @@ -14,6 +14,7 @@ import uuid import os import oe.spdx_common from datetime import datetime, timezone +from contextlib import contextmanager OE_SPDX_BASE = "https://rdf.openembedded.org/spdx/3.0/" @@ -191,6 +192,25 @@ def to_list(l): return l +class Dedup(object): + def __init__(self, objset): + self.unique = set() + self.dedup = {} + self.objset = objset + + def find_duplicates(self, cmp, typ, **kwargs): + for o in self.objset.foreach_filter(typ, **kwargs): + for u in self.unique: + if cmp(u, o): + self.dedup[o] = u + break + else: + self.unique.add(o) + + def get(self, o): + return self.dedup.get(o, o) + + class ObjectSet(oe.spdx30.SHACLObjectSet): def __init__(self, d): super().__init__() @@ -895,6 +915,45 @@ class ObjectSet(oe.spdx30.SHACLObjectSet): self.missing_ids -= set(imports.keys()) return self.missing_ids + @contextmanager + def deduplicate(self): + d = Dedup(self) + + yield d + + visited = set() + + def visit(o, path): + if isinstance(o, oe.spdx30.SHACLObject): + if o in visited: + return False + visited.add(o) + + for k in o: + v = o[k] + if isinstance(v, oe.spdx30.SHACLObject): + o[k] = d.get(v) + + elif isinstance(o, oe.spdx30.ListProxy): + for idx, v in enumerate(o): + if isinstance(v, oe.spdx30.SHACLObject): + o[idx] = d.get(v) + + return True + + if d.dedup: + for o in self.objects: + o.walk(visit) + + for k, v in d.dedup.items(): + bb.debug( + 1, + f"Removing duplicate {k.__class__.__name__} {k._id or id(k)} -> {v._id or id(v)}", + ) + self.objects.discard(k) + + self.create_index() + def load_jsonld(d, path, required=False): deserializer = oe.spdx30.JSONLDDeserializer() @@ -1080,39 +1139,28 @@ def create_sbom(d, name, root_elements, add_objectsets=[]): # SBoM should be the only root element of the document objset.doc.rootElement = [sbom] - # De-duplicate licenses - unique = set() - dedup = {} - for lic in objset.foreach_type(oe.spdx30.simplelicensing_LicenseExpression): - for u in unique: - if ( - u.simplelicensing_licenseExpression - == lic.simplelicensing_licenseExpression - and u.simplelicensing_licenseListVersion - == lic.simplelicensing_licenseListVersion - ): - dedup[lic] = u - break - else: - unique.add(lic) - - if dedup: - for rel in objset.foreach_filter( - oe.spdx30.Relationship, - relationshipType=oe.spdx30.RelationshipType.hasDeclaredLicense, - ): - rel.to = [dedup.get(to, to) for to in rel.to] - - for rel in objset.foreach_filter( - oe.spdx30.Relationship, - relationshipType=oe.spdx30.RelationshipType.hasConcludedLicense, - ): - rel.to = [dedup.get(to, to) for to in rel.to] + def cmp_license_expression(a, b): + return ( + a.simplelicensing_licenseExpression == b.simplelicensing_licenseExpression + and a.simplelicensing_licenseListVersion + == b.simplelicensing_licenseListVersion + ) - for k, v in dedup.items(): - bb.debug(1, f"Removing duplicate License {k._id} -> {v._id}") - objset.objects.remove(k) + def cmp_creation_info(a, b): + data_a = {k: a[k] for k in a} + data_b = {k: b[k] for k in b} + data_a["@id"] = "" + data_b["@id"] = "" + return data_a == data_b + + with objset.deduplicate() as dedup: + # De-duplicate licenses + dedup.find_duplicates( + cmp_license_expression, + oe.spdx30.simplelicensing_LicenseExpression, + ) - objset.create_index() + # Deduplicate creation info + dedup.find_duplicates(cmp_creation_info, oe.spdx30.CreationInfo) return objset, sbom diff --git a/meta/lib/oe/spdx30.py b/meta/lib/oe/spdx30.py index cd97eebd18..1f58402ffc 100644 --- a/meta/lib/oe/spdx30.py +++ b/meta/lib/oe/spdx30.py @@ -701,7 +701,7 @@ class SHACLObject(object): self.__dict__["_obj_data"][iri] = prop.init() def __iter__(self): - return self._OBJ_PROPERTIES.keys() + return iter(self._OBJ_PROPERTIES.keys()) def walk(self, callback, path=None): """ From patchwork Tue Mar 10 18:38:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83008 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D0D2AFD4F1E for ; Tue, 10 Mar 2026 18:41:12 +0000 (UTC) Received: from mail-oi1-f170.google.com (mail-oi1-f170.google.com [209.85.167.170]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2600.1773168071284282971 for ; Tue, 10 Mar 2026 11:41:11 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=PksrJPvq; spf=pass (domain: gmail.com, ip: 209.85.167.170, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f170.google.com with SMTP id 5614622812f47-464bba3a9easo8798331b6e.0 for ; Tue, 10 Mar 2026 11:41:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168070; x=1773772870; 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; bh=6Tj4cGGvEEbE1QT7Q+4TdJLcoNUT6Vuz9fhKtg+CMko=; b=PksrJPvq7Kw4ntdPWSal9fE+quReE5rKMHkKSotylTQG/6Xl+c/JI1NUlu2F4ljZ4O zi4xhNvmi/5M9qsHpcTnDhsyxdZqqh0y5SjGz/hR/xW3puLgBmiC0ioMQmUd9hYN+RR2 JeUJ4L/jRS1DZY1tRZEodlxw8cDA1pjwT/+OVLE2ckiNiwreHnOdFjt9y0ODuHY2ygzI L3sUoK+OCEk4dQndsDYJAYlpQPCQbK6GYFP66dK3EeHBwqzJC+b8C6cjFcB9vKvKQmYq DYRpeGj5zqCI1uEgrc24E8B0j2J/C+S7bFS4Jw3f7TV+izsop8tOYrYqkIYAW+2kvxfH 9Dnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168070; x=1773772870; 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; bh=6Tj4cGGvEEbE1QT7Q+4TdJLcoNUT6Vuz9fhKtg+CMko=; b=LzgbBj2dpVF57EhSNv4XahH/pSNctkL4QdrN1Z60SzuVWKDwhrJpk9nWgzgGSbgpHm ApWnVnmSUmlyLuLAhduqheuoWYxVmekfDZkdRG3hZcZhHyVwYAhSExOKgh80jmE7b1/L n2ICdQvvWRiiaMubCqsfYozbv46sOO4nHDLXFtd3Ow7SqO/yl+wwy8oMtGd/Mj5VCFfl pbhSKpBnH1xhrTIWl8WSFO3FtTB1fAkUr5M2wPZDsTYB1d2bMjcVoYbLYdEtCqOi6yd9 TvsKD8aYu53HEUrO97xOH2ct3CPwEYba7vh/ilswWCb9ljpDywR3Csoaj43UUkYoTJ9K 70LA== X-Gm-Message-State: AOJu0YwOK70clTjzeced+7/V0mrkKxAA4y6McLBuE8Aa49WLfH6niLKy 3vnvOGcnYeU14wZiLpoYsHC0giU0fX9lFhvZD09weKO5g7KJHXo2hnoKLyGYww== X-Gm-Gg: ATEYQzznalpWqqppTUsRGxLseNDmC/ftyUHHHsvtHTMh5413ID1COZ7zlgKM9lHR0z8 t/Z7NsyE83oZku4HPVWq14MniQPWqrWNJUxpJ90+755fVVCZFgpRSPakNUfJqBaj8BH5RV8tY4v cfKVCRtlwNacKyMMXYqb4Kwu5s/7EDhAdKcFpnBfrk6ME565GPrA3vp8GOot3WsYIVDinvRmGDt usqEsHaqTu1li1xw7ukLxgrhAPh0GL5ScUVlQHbfy7d1w5MVA370X7BMD1AXsG3n0EiIWaUA/6s EWdkpFBTrlrxN9G+dbb06YBZVmaYthS+AK4vsGH7bC4aEeXgNJ8YVMg6rHHr/TxA3k3WtP+b4HO Q66DmZMc430csB+JI2YDgq9wBRlP589UcWqBUHRbVh4Cj/loqc4x8NJljaom9g80ZbA9Tt42ESX ryBLj3tNAy1dkSqZpG9yeMQQfILk4JIUU= X-Received: by 2002:a05:6808:e88:b0:45e:e088:5f3e with SMTP id 5614622812f47-466dcb7230bmr8985372b6e.49.1773168070428; Tue, 10 Mar 2026 11:41:10 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:09 -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 08/15] spdx_common: Check for dependent task in task flags Date: Tue, 10 Mar 2026 12:38:28 -0600 Message-ID: <20260310184058.533343-9-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:12 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232819 Checks that the task being used to detect dependencies is present in at least one dependency task flag of the current task. This helps prevent errors where the wrong task is specified and never found. Signed-off-by: Joshua Watt --- meta/lib/oe/spdx_common.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/meta/lib/oe/spdx_common.py b/meta/lib/oe/spdx_common.py index 72c24180d5..3aaf2a9c8b 100644 --- a/meta/lib/oe/spdx_common.py +++ b/meta/lib/oe/spdx_common.py @@ -96,6 +96,17 @@ def collect_direct_deps(d, dep_task): taskdepdata = d.getVar("BB_TASKDEPDATA", False) + # Check that the task is listed one of the task dependency flags of the + # current task + depflags = ( + set((d.getVarFlag(current_task, "deptask") or "").split()) + | set((d.getVarFlag(current_task, "rdeptask") or "").split()) + | set((d.getVarFlag(current_task, "recrdeptask") or "").split()) + ) + + if not dep_task in depflags: + bb.fatal(f"Task {dep_task} was not found in any dependency flag of {pn}:{current_task}") + for this_dep in taskdepdata.values(): if this_dep[0] == pn and this_dep[1] == current_task: break From patchwork Tue Mar 10 18:38:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83007 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E7961FD4F21 for ; Tue, 10 Mar 2026 18:41:12 +0000 (UTC) Received: from mail-oi1-f175.google.com (mail-oi1-f175.google.com [209.85.167.175]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2665.1773168072114593313 for ; Tue, 10 Mar 2026 11:41:12 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=e3GDNKxQ; spf=pass (domain: gmail.com, ip: 209.85.167.175, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f175.google.com with SMTP id 5614622812f47-463a0e14abfso9432859b6e.2 for ; Tue, 10 Mar 2026 11:41:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168071; x=1773772871; 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; bh=9Wsvm7UZ+qXi5zyTV0UmCwyCSQ0eIKoDgVpDnS6yewE=; b=e3GDNKxQJQXGsopYiaoXA+CS+8N1pN02wKQEneUqvFncF9rnwbHdR2kpaHjzmMVk4A C1n0fLkLpcSl4jotLwiZkNM+4sCoeiBDIWacfw3iWyd7TQxzQqnTNo/l5t7mZ1pCw89n zW124/+K7wsqqcdUGMXk2fJT0X0DL6BpZtDCsC40b852JQd7ptdUO1NVWIUQ3G6Ock+p XOHVCnSrsvdDryZxb0GNvp5JvoUTVXoTKJnhpaIMYJzT6HRe7BUeLo3EusxhbX5/oQTl qteSBZUm2SDiet3RMZQnx/YGZ+ThSwSejocvpR86a9vjBTKWmelSLFKTFtkhyT+woVvT 1fSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168071; x=1773772871; 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; bh=9Wsvm7UZ+qXi5zyTV0UmCwyCSQ0eIKoDgVpDnS6yewE=; b=DEjaweVKYwPST2y0RZZMDb782jKNWnpRMKBQhokNDsSyyoE286q+Gp5oIxjoxTwiHN t6c0Q2VqGcRc4Juk7sKV+Srcwm8pW5K6FgPwWK4/Q+vT9/HKiE4u03vGQZEs7/N8i1HO SBg9D90FDlonzGQznQ9RcFOvrYQJ77r7NtYS+/BYZ0jYSyAdN4v9nnHw1KfKEMpVNwMp ML1ynGBsY4LU4ykL6/iYYlLFA01wxYxPWz4R1Z8QlJWNH1jjK6BPhHi79+q+0DA1ExE/ jYxv2jV83w9wXtEZEuy//LaxC/s1EakXFfz/HCRdQFRkP4L3NbLOP/Yd/tIUUg2re8qt RcAw== X-Gm-Message-State: AOJu0Yz6bF6pQPFHCU/fWH8iePEw2zng3+XRv/wmvFSCG3o66K0Q+JWX bMoqP7RHU1geM0yecMdYcOSdtWSqOiwcKuF9jVBM0eJc7e86qr9GjNmQhNc2BA== X-Gm-Gg: ATEYQzwOK7bUw6DODE9d9ciIJIZFt5vMzV8pxPA5WuoR7dFEi8E0pYQ9nzIQG+0W3AU i5f/CHf8WN2te7PqRTvSw7L+M2AziiKJzCZzIq+EJZzTGPsddwaX8e10ovs8es+02OcE6iSqvGO sMY1Ql5eaMKR6W38Nqf0jdIAKjR3KvW6BTWNYe/xFC8hS4Ay3tk3LCRrLoageG57MPHvMksZSzw MMa+UA1q6uYzedEoh/5QA95yfAgEmScU8kj7iLoi+oUr3m4qwr3Y0PBjD4wU4MwBDkEHp35P0H7 DRYiQBcOFwvJot5799aL1Vi1XcbQw843pD60Ulvp6VVaWr82mdS+UBmZEdtGwurI4KwcPnzQGRm yVTEnz4q58xe8QlIdiAF6XlUGzcyGrDkKCqUT/rsmN+J0RWDODhTUXfp3vjihl5bJGKegIZFX29 f2bxS1qQ451Z4bJKveAj80 X-Received: by 2002:a05:6808:13d1:b0:45f:59e:1e06 with SMTP id 5614622812f47-466dc9eeaa3mr8655639b6e.4.1773168071218; Tue, 10 Mar 2026 11:41:11 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:10 -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 09/15] spdx30: Skip install package CVE information Date: Tue, 10 Mar 2026 12:38:29 -0600 Message-ID: <20260310184058.533343-10-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:12 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232820 Skips adding the install package CVE information by default. This information grows exponentially, since it ends up be N_CVES * N_PACKAGES. The CVE information for a given installed package can be determined by following the "generates" link between the install package and the recipe and looking at the CVE information for the recipe, meaning that the CVE information is only included once in the SPDX document. If users still need the legacy method of including CVE information for each package, then then can set SPDX_PACKAGE_INCLUDE_VEX = "1" Signed-off-by: Joshua Watt --- meta/classes/create-spdx-3.0.bbclass | 11 ++++++++ meta/lib/oe/spdx30_tasks.py | 39 ++++++++++++++-------------- meta/lib/oeqa/selftest/cases/spdx.py | 12 +++++++++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index c3ea95b8bc..88b7ef9f42 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -45,6 +45,17 @@ SPDX_INCLUDE_VEX[doc] = "Controls what VEX information is in the output. Set to including those already fixed upstream (warning: This can be large and \ slow)." +SPDX_PACKAGE_INCLUDE_VEX ?= "0" +SPDX_PACKAGE_INCLUDE_VEX[doc] = "Link VEX information to the binary package outputs. \ + Normally, VEX information is only linked to the common recipe that `generates` the \ + binary packages, but setting this to '1' will cause it to also be linked into the \ + generated binary packages. This is off by default because linking the VEX data to \ + each package causes the SPDX output to grow very large, and the same information \ + can be determined by following the `generates` relationship back to the recipe. \ + Before recipe packages were introduced, this was the only way VEX data was \ + expressed; you may need to enable this if your downstream tools do not \ + understand how to trace back to the recipe to find VEX information." + SPDX_INCLUDE_TIMESTAMPS ?= "0" SPDX_INCLUDE_TIMESTAMPS[doc] = "Include time stamps in SPDX output. This is \ useful if you want to know when artifacts were produced and when builds \ diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index aec47d4f81..887fac813a 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -771,27 +771,28 @@ def create_spdx(d): # Collect all VEX statements from the recipe vex_statements = {} vex_patches = {} - for rel in recipe_objset.foreach_filter( - oe.spdx30.Relationship, - relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability, - ): - for cve in rel.to: - vex_statements[cve] = [] - vex_patches[cve] = [] - - for cve in vex_statements.keys(): + if (d.getVar("SPDX_PACKAGE_INCLUDE_VEX") or "") == "1": for rel in recipe_objset.foreach_filter( - oe.spdx30.security_VexVulnAssessmentRelationship, - from_=cve, + oe.spdx30.Relationship, + relationshipType=oe.spdx30.RelationshipType.hasAssociatedVulnerability, ): - vex_statements[cve].append(rel) - if rel.relationshipType == oe.spdx30.RelationshipType.fixedIn: - for patch_rel in recipe_objset.foreach_filter( - oe.spdx30.Relationship, - relationshipType=oe.spdx30.RelationshipType.patchedBy, - from_=rel, - ): - vex_patches[cve].extend(patch_rel.to) + for cve in rel.to: + vex_statements[cve] = [] + vex_patches[cve] = [] + + for cve in vex_statements.keys(): + for rel in recipe_objset.foreach_filter( + oe.spdx30.security_VexVulnAssessmentRelationship, + from_=cve, + ): + vex_statements[cve].append(rel) + if rel.relationshipType == oe.spdx30.RelationshipType.fixedIn: + for patch_rel in recipe_objset.foreach_filter( + oe.spdx30.Relationship, + relationshipType=oe.spdx30.RelationshipType.patchedBy, + from_=rel, + ): + vex_patches[cve].extend(patch_rel.to) # Write out the package SPDX data now. It is not complete as we cannot # write the runtime data, so write it to a staging area and a later task diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index efee0214fc..f1ea2694cf 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -429,3 +429,15 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): value, ["enabled", "disabled"], f"Unexpected PACKAGECONFIG value '{value}' for {key}" ) + + def test_package_vex(self): + objset = self.check_recipe_spdx( + "core-image-minimal", + "{DEPLOY_DIR_IMAGE}/core-image-minimal-{MACHINE}.rootfs.spdx.json", + extraconf="""\ + SPDX_PACKAGE_INCLUDE_VEX = "1" + """, + ) + + # Document should be fully linked + self.check_objset_missing_ids(objset) From patchwork Tue Mar 10 18:38:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83013 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAAAAFD4F30 for ; Tue, 10 Mar 2026 18:41:13 +0000 (UTC) Received: from mail-oi1-f177.google.com (mail-oi1-f177.google.com [209.85.167.177]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2666.1773168072755650809 for ; Tue, 10 Mar 2026 11:41:12 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=SSDe64ZA; spf=pass (domain: gmail.com, ip: 209.85.167.177, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f177.google.com with SMTP id 5614622812f47-466f935a82fso2066351b6e.0 for ; Tue, 10 Mar 2026 11:41:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168072; x=1773772872; 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; bh=0l9blCT/wsqpVcoJlBIomjEadTw/LWIOr1Fg6FyV5X0=; b=SSDe64ZAuNL3TJIwmy1fSF5EAUmYmcb8sCL/BFWOWjWEoRA6bZfryjmDqpMoWJLPYR BWRY6a7VwuFyKInD2l3ZHeN4LsD6IMGtRdAZodbg5YoZ/pLQFlBd05IFpuVXktX+4zh5 a76pxqkNTYYGGHPxvOYIJXTKPnBJR2BzSoQiTt7/8i+NVBdfWS1ziL481jZK675B1/tS yf9p5KOmliHI2TeOSNh2d4MGIIsEXQY2sf51O24LNZMZCfBDklCQ0G6G7+g3KFuqd/jz 5YRsFPlvm8tw+809RHIkM4yZbDw32OYHJx5nJmpdHyvXH/o3fT1Wcv+b/LMG5QfMOK6U dgbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168072; x=1773772872; 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; bh=0l9blCT/wsqpVcoJlBIomjEadTw/LWIOr1Fg6FyV5X0=; b=relFnOEnwlAzf5cqZAP5F9ftpCEcExCT/TXz43AKNMW6ckQYHvzW/e/vL+n/jjcmpg yiOE+OE4nyFNXkDJMpSN4rJH3bc1yVXQ4yjfqgS2adxcRdk4UhO+aULZPwvFQqJAseub cUZ4GEO7jxuNFQvZzbRszN5oYbk+v57HTvOCKATPHemjh1n13wiRK7PM2FfxJIU8RILs cIN4rj4Vua3jmn14qwYGsn1d+2z17VSTNXks8bgndpytkXp5uw+Lo7MPOVunQtdnuOi+ SAHDg20dyNwvPl0lldoOlFs6rZSwRFz9JVYZeGxj4OSZ34BlG/aAIhPnLRqhx/u9IkSk qSwg== X-Gm-Message-State: AOJu0YyIwtBeYUzzEGcoyOIXthG28aNIsaEkLWF+tbuu/lSwtPNzN/Ip hhrLek7fvgs/pxkCREpQJd16R/UUYBGMZkzfUmRDR3xCo5j2VIMBnWV5GLzIzA== X-Gm-Gg: ATEYQzxZJb4PIHCSYv0sFD41ubMWmOmeCboH7AQdxC2mJKOtB6lVZwNRRLNKV67aXns eu85PqG/EbkfJtANad085zfKVwkza0Dgp7HqRv+qvDKbiSM+ak/tMafaM/gVecK0hUfh6M1b+P9 ljIzkUGuJ6je2D62A8T4jhWEJ/A8NMfAGcWdBwrJLx0bQu1KTSZGKrDdw97QjXcnB2fpG2BmCtP UwiynH2n+EbMi4R7LmkeWIo0ciESnzDPDlaDEu2gqCnwrAG9cCFziyGdM1MnBVgMzmWSpqbOi7U flEtgedCgrg+qaeIp6KQXIuO/w0pbGO8UG36CWbcenTqZ6jFpmCIfHLpQI1XFgu1qHCB0SyCuSJ FiofTnQcboX29lgUFrlvfcDeULaEY6CIFJU/qI4oqU3gFH+R6lsSHAugE24h34YqiOY6VS6ECwo 1KQtSJLSInHguWIFWsEjLK X-Received: by 2002:a05:6808:1903:b0:467:1ad3:7ee with SMTP id 5614622812f47-4671ad320femr2562197b6e.40.1773168071853; Tue, 10 Mar 2026 11:41:11 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41:11 -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 10/15] dummy-sdk-package: Disable SPDX Date: Tue, 10 Mar 2026 12:38:30 -0600 Message-ID: <20260310184058.533343-11-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:13 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232821 The dummy SDK packages do not need SPDX support, and since they play some games with allarch that cause problems, it's simplest to disable their SPDX output. Signed-off-by: Joshua Watt --- meta/recipes-core/meta/dummy-sdk-package.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/recipes-core/meta/dummy-sdk-package.inc b/meta/recipes-core/meta/dummy-sdk-package.inc index bf453cac9b..71e788b0b9 100644 --- a/meta/recipes-core/meta/dummy-sdk-package.inc +++ b/meta/recipes-core/meta/dummy-sdk-package.inc @@ -4,6 +4,7 @@ LICENSE = "MIT" PACKAGE_ARCH = "all" inherit allarch +inherit nospdx INHIBIT_DEFAULT_DEPS = "1" From patchwork Tue Mar 10 18:38:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Watt X-Patchwork-Id: 83014 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10729FD4F32 for ; Tue, 10 Mar 2026 18:41:14 +0000 (UTC) Received: from mail-oi1-f180.google.com (mail-oi1-f180.google.com [209.85.167.180]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2601.1773168073592393680 for ; Tue, 10 Mar 2026 11:41:13 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=PqXScd7B; spf=pass (domain: gmail.com, ip: 209.85.167.180, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f180.google.com with SMTP id 5614622812f47-466f00535cfso2326844b6e.1 for ; Tue, 10 Mar 2026 11:41:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168073; x=1773772873; 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; bh=pH0P+1ESZgjWAPDC3epT+SOFN7MIIdYB7o7a9YkSZhs=; b=PqXScd7BIMlLSMKeYT/f2bKmJ0ydk9KGJH6SUWec5UWXtaQFk2wfPYkh8EwEqJqChD rMeFMqrlXLgSG9O6eONaxlZgtXmCXeFaY9fqR0J3u7H1lZuN4n/fhK4cW34oiS9B0pbS LWK6Ng7y8EdV8D6Dl0v+zxu17KPX3C+O9WkeMEIr9kx+OphxwMtPcXQMSoBSk4TzAXna s9GAZd8EU8pdaPK703bY1ig++oVd+qsTA4fWODULtRkipKyptvfj8RokFG+TmZn7DWE3 ueu9hXV71DlQbyTgS6kiL/GnpXYB7SsDTROh0+XQhCoWy24IIhPAGXwg5eWgrEHuNzbq LqQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168073; x=1773772873; 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; bh=pH0P+1ESZgjWAPDC3epT+SOFN7MIIdYB7o7a9YkSZhs=; b=cPzKaZHTNuat+e1aOAFPpmjqSfAIA+kFxECzTC1NL9wuIWOX+uq6tHMfiRYs/HstnM ubr0pAVQvAKltm5L8xFxqAovPG9aV4aqb8FteOwnGVpgThPWJKPTG32fjcLzr9VSZRcF kt3EZjHs9twdG/f1+NqHfzQu/4XQGpRYh3m9bRjVzRDVpY9oZIiWpIAEZRnBkOwyd0Xh riaznLk2sLfXyCQR+OgUbXGrmlTV6jN44qxteW8DUtEXbygHxmCmlbWBcanF0ytRewK1 zibZTU3HhU179Yvo6CRlimuPS6Rz/jlxsV8r5znBkvpliDr6DQg9HS3VzT+sGYKq3KqG LmJw== X-Gm-Message-State: AOJu0YzwKG1EhZmtY5teUIuPvAt1n0I8tNlbKR+g5iTCnzwZYMwWip/0 znLCT+GaOBSSMzPu8o2SDRLzsuVDGO0ma7fDM62yXEInzLkTtHFh87zI6L5SXw== X-Gm-Gg: ATEYQzz8v1mRQ0SDSjv9GXhWwJ55I4KbXdPSacD08rVrTJgoK7DgyP1MPasDZd1ZlR5 pwVedT3TZGUNFHm5xn1xAUi2pjzLMyuPPmdHVYAXIdYPmK/Nta7oROlbxeq+eLYFon3NltvXy5u WNxPN1iHeoo/Tu7cgptRsYCReMZ7qrTUgZK+dKPRXYBIhjv9T14Qs6kBV49Y2awmCvue65Dec0T FmUnpHTXD7QDo6aQPZNwkmKQbHah49ivpU7b++vh2E9rv7txZzfJ+l32c/SH9K351gM/Uf8fbCw kJXD5zcQ23dg8W4d0sfGVfwjlYD8hGrvRSYoNZ5Trp+w+FRtS6gDzj2hxhF4RNaea/aaYEB04iU B1Nk2nd0CvAB0wYygU5IveXbxT8pq9s/idyfRocM5QM8CKMSWDmnBIH9rICD8c8GoLwOMmTfPNk qkdjYS+bRXO5BpF3mbwi3F X-Received: by 2002:a05:6808:4fd4:b0:467:272e:87d with SMTP id 5614622812f47-467272e1177mr1150928b6e.14.1773168072590; Tue, 10 Mar 2026 11:41:12 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41: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 v6 11/15] spdx: Remove fatal errors for missing providers Date: Tue, 10 Mar 2026 12:38:31 -0600 Message-ID: <20260310184058.533343-12-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:14 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232822 When creating images and SDKs, do not error on missing providers. This allows recipes to use the `nospdx` inherit to prevent SPDX from being generated, but not result in an error when assembling the final image. Note that runtime packages generation already ignored missing providers, so this is changing image and SDK generation to match Signed-off-by: Joshua Watt --- meta/classes/create-spdx-2.2.bbclass | 3 ++- meta/lib/oe/spdx30_tasks.py | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass index 3288cdf75a..aa39208eae 100644 --- a/meta/classes/create-spdx-2.2.bbclass +++ b/meta/classes/create-spdx-2.2.bbclass @@ -858,7 +858,8 @@ def combine_spdx(d, rootfs_name, rootfs_deploydir, rootfs_spdxid, packages, spdx if packages: for name in sorted(packages.keys()): if name not in providers: - bb.fatal("Unable to find SPDX provider for '%s'" % name) + bb.note("Unable to find SPDX provider for '%s'" % name) + continue pkg_name, pkg_hashfn = providers[name] diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index 887fac813a..ba15d74278 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -1251,11 +1251,10 @@ def collect_build_package_inputs(d, objset, build, packages, files_by_hash=None) providers = oe.spdx_common.collect_package_providers(d) build_deps = set() - missing_providers = set() for name in sorted(packages.keys()): if name not in providers: - missing_providers.add(name) + bb.note(f"Unable to find SPDX provider for '{name}'") continue pkg_name, pkg_hashfn = providers[name] @@ -1274,11 +1273,6 @@ def collect_build_package_inputs(d, objset, build, packages, files_by_hash=None) for h, f in pkg_objset.by_sha256_hash.items(): files_by_hash.setdefault(h, set()).update(f) - if missing_providers: - bb.fatal( - f"Unable to find SPDX provider(s) for: {', '.join(sorted(missing_providers))}" - ) - if build_deps: objset.new_scoped_relationship( [build], From patchwork Tue Mar 10 18:38: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: 83017 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DEE0FD4F23 for ; Tue, 10 Mar 2026 18:41:24 +0000 (UTC) Received: from mail-oi1-f175.google.com (mail-oi1-f175.google.com [209.85.167.175]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2667.1773168074369094408 for ; Tue, 10 Mar 2026 11:41:14 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=nPwgR/AF; spf=pass (domain: gmail.com, ip: 209.85.167.175, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f175.google.com with SMTP id 5614622812f47-46726528f1cso520314b6e.0 for ; Tue, 10 Mar 2026 11:41:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168073; x=1773772873; 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; bh=XIWNp+jA9fLjpsXG4iRqhfv6oO7L/BK8ilevIn/RjTk=; b=nPwgR/AFwvAVCf5JpTuYRGo10FmOC4y49EeNGSKouduTNWuLKyndH4PmtGXomEK5yF urqyTcsnffXNk6xzbsYgE80/MGBAqebL/V2vnU7rYJUZIIc4oggFNkVcuaB6fFWhJmi2 i3HG7ZHwABZHhZLrHiZApkIspY/O/aBQEq568VxL0M8geMXkZkuF40HawXojNCJ194gs FZbxcS0I8pdggd51Flp+vRdD1cPKw+pAviHgjo48lwXF4nPwPD8GVcjgH+oVOXANcnbn r9bL+65AchZntCoPeCRS39kr3c7FmnvrugQLvSo9sGVxDdd+jLMBcdNnLr9c7ib5gB2g k51g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168073; x=1773772873; 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; bh=XIWNp+jA9fLjpsXG4iRqhfv6oO7L/BK8ilevIn/RjTk=; b=ltbt9J1/4sG70zv+fWFM/1RRoykTYN6Eb+tNjfZQw6OMlgklxNMr8XbhIfs61OFq+C p9mHDmulUxAvADahJQRBtL+ZVacv6WwJJyQttuI64sWAj36yWl50x9XOcuRHb64XmKEq 2Jm2Gg+OswZxDRky9D3NeoUj7W9kPY6oQ589Y+4WPsFVdxmqMIgzX4thDlqLHSRtKnZg VV7js6aFpzsdnBcd9boEAdfSM0MMgUBl6oLBppAF78XEWMRnYTF8QrNu0N/9Tj+yuJ8T F1nQf2ungH6tuATpkkxJNqRFvZXXR+JTtlNeS8X+59GtrwFqnTNgI3WuVdMlZ4o42jd7 JIJA== X-Gm-Message-State: AOJu0Yzi/8zWBeHznp2TnRJbVcBt1kT7xHCckQOFw3gCPVetm9UUoZxC XKoOtAug+emJDWRTFwxtRBXWBF6xMTCgAhC2HlUnp+WKPIKCxS/v+aHhUzAwRQ== X-Gm-Gg: ATEYQzypVrJDD6sccSXJolLNgRRwwaQ0M1LJejt5mFE8TvRK111jWW3/eoScmA80VWD wR0hhzP8hzbflJsT2xZwQ0nXnjL4gqLcee4JAnH0/CWJRjygqEMc5eWe/nN7cQ4do8GKZCZ3TUK qvtWeRwalm5YUN5G/GqyOfT0WA61Jux+TJiX/4HdrsuvpUHYUUMzFLZ1zYV5gohK70RPTC9+2Hn G445G1R0q25cvBd5NimkeUNIshUEzkudlxiI10OwJDTb13XLI60DGXhnpKW3WaWYv+Tt6OYKQ/l I0X7mZ5P6QjYtedI0IpcLAlJbDLCTdXwWINnGu9BlFXmUAX1Dn26NTez4ZRcADfxpNRASSXJcXz otZnYTZKEhwODJTvCOGaw2iQ7d1oRWTE02fkl/sEtLYkg8XCFON4zbqU1URKXCTOfVXmMEYgO5o +iuKcW4Lsm/OmkKyurNOor X-Received: by 2002:a05:6808:2226:b0:467:254:b90 with SMTP id 5614622812f47-46702542b39mr5180119b6e.10.1773168073335; Tue, 10 Mar 2026 11:41:13 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41: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 v6 12/15] spdx3: Use common variable for vardeps Date: Tue, 10 Mar 2026 12:38:32 -0600 Message-ID: <20260310184058.533343-13-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:24 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232823 Instead of repeating the vardeps for each SPDX task with the necessary variables, use a common variable to make it easier to manage Signed-off-by: Joshua Watt --- meta/classes/create-spdx-3.0.bbclass | 33 ++++++++++------------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 88b7ef9f42..6df66c193b 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -174,6 +174,14 @@ SPDX3_DEP_FILES = "\ ${SPDX_LICENSES}:True \ " +SPDX3_VAR_DEPS = "\ + SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ + SPDX_PACKAGE_ADDITIONAL_PURPOSE \ + SPDX_PROFILES \ + SPDX_NAMESPACE_PREFIX \ + SPDX_UUID_NAMESPACE \ + " + python do_create_recipe_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_recipe_spdx(d) @@ -185,13 +193,7 @@ do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}" do_create_recipe_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" do_create_recipe_spdx[file-checksums] += "${SPDX3_DEP_FILES}" do_create_recipe_spdx[cleandirs] = "${SPDXRECIPEDEPLOY}" -do_create_recipe_spdx[vardeps] += "\ - SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ - SPDX_PACKAGE_ADDITIONAL_PURPOSE \ - SPDX_PROFILES \ - SPDX_NAMESPACE_PREFIX \ - SPDX_UUID_NAMESPACE \ - " +do_create_recipe_spdx[vardeps] += "${SPDX3_VAR_DEPS}" python do_create_recipe_spdx_setscene () { sstate_setscene(d) @@ -222,13 +224,7 @@ do_create_spdx[depends] += " \ ${PATCHDEPENDENCY} \ ${@create_spdx_source_deps(d)} \ " -do_create_spdx[vardeps] += "\ - SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ - SPDX_PACKAGE_ADDITIONAL_PURPOSE \ - SPDX_PROFILES \ - SPDX_NAMESPACE_PREFIX \ - SPDX_UUID_NAMESPACE \ - " +do_create_spdx[vardeps] += "${SPDX3_VAR_DEPS}" python do_create_spdx_setscene () { sstate_setscene(d) @@ -249,6 +245,7 @@ do_create_package_spdx[file-checksums] += "${SPDX3_DEP_FILES}" do_create_package_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" do_create_package_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" do_create_package_spdx[rdeptask] = "do_create_spdx" +do_create_package_spdx[vardeps] += "${SPDX3_VAR_DEPS}" python do_create_package_spdx_setscene () { sstate_setscene(d) @@ -270,13 +267,7 @@ do_create_recipe_sbom[sstate-inputdirs] = "${SPDXRECIPESBOMDEPLOY}" do_create_recipe_sbom[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" do_create_recipe_sbom[file-checksums] += "${SPDX3_DEP_FILES}" do_create_recipe_sbom[cleandirs] = "${SPDXRECIPESBOMDEPLOY}" -do_create_recipe_sbom[vardeps] += "\ - SPDX_INCLUDE_BITBAKE_PARENT_BUILD \ - SPDX_PACKAGE_ADDITIONAL_PURPOSE \ - SPDX_PROFILES \ - SPDX_NAMESPACE_PREFIX \ - SPDX_UUID_NAMESPACE \ - " +do_create_recipe_sbom[vardeps] += "${SPDX3_VAR_DEPS}" python do_create_recipe_sbom_setscene () { sstate_setscene(d) From patchwork Tue Mar 10 18:38: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: 83016 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1C999FD4F1F for ; Tue, 10 Mar 2026 18:41:24 +0000 (UTC) Received: from mail-oi1-f172.google.com (mail-oi1-f172.google.com [209.85.167.172]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2668.1773168075053632632 for ; Tue, 10 Mar 2026 11:41:15 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=ZKCW6v5B; spf=pass (domain: gmail.com, ip: 209.85.167.172, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f172.google.com with SMTP id 5614622812f47-46702742c7dso667580b6e.1 for ; Tue, 10 Mar 2026 11:41:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168074; x=1773772874; 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; bh=AOEUATX1R3zaee+T2FPZecNpF7K6G1L1mqigJuVHEzo=; b=ZKCW6v5BaG4sG7JQvP/XSEc8fhKco1L4iEle9DoAwSVLwbhw8PO5m63Lc3glqjqU9T MuG7FFHcHD5yd9w+74QcIovK7CPQNQZSSC7FSYXR7nvPBDY1Wjik+jk3wYCPmTIIKfK6 jIZlNPbgKEjhiv+ebEFyfo+2B/5hi8UWuLlCqgn4fM7QW0K0e29w6uMCg+raOv6G2Wkj K9rQMoGGuerExbqcm/8zkBWBMVyIt81Sg0b6qzmOMq6dc4nbQLXp8Dx2h6elzp+emXzD BKxr4cUe2SneRiOxRjRERuxLuXAQfeTPWEwIGQwtLsO5HHUHX4BQRw+CxSCrMQDjcrQa 0riQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168074; x=1773772874; 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; bh=AOEUATX1R3zaee+T2FPZecNpF7K6G1L1mqigJuVHEzo=; b=XnnWgVSg3qhXIhLysQT6aHjHeDFOIkC+m/CXOBg/FhU/0iB/o67M/caiWsM6CDoWTC pLVbaTsLEU/mU19F1ujmBpQWEbxpGs1s3sakk9CCkFQxp0IdsTzQD4xTpEwU8VM6SMV4 XPj43JoTFC7JWt3HwLfOJCnBjde2HearBh8Htffkwd/N1Bfskvvnwf5d4oKzQriCVYJw L6TlD1dEiRkaEf4rBDnRZRR15ieaCiGm2x6wYlsKoAwjhqluKTlc3OEzaEAL3hI23wxu 45KyRQRbEAHYx2RttB3wRPLWF2+rQi50OKofi53UpAldXhwD0mm5xRyzVDlQy5zdevzT 7Y7w== X-Gm-Message-State: AOJu0YyyZw/GIW+jGToYId3/Vk/yEHX/UaslkAEX4UOuwnj99vGHBZ5j Zmd//cjWvJXPmd9WOOTXFT4EiOWegj21/KmQESj9Q4fQQDxlDwtrd3ZSTkKntg== X-Gm-Gg: ATEYQzxnusTHUBpEG/C+JQ8k/mfU7YcOvTBHcuJOfPTglxmQlaDrP/9SogLyp8j3p8p spGLujNAkjBzWftQCY2noyQSV3b6I5oL9zrGCuh7MJJVc/100rHcNpX+vSvx5stbneZpi2sgSL9 QIjy6uc7khwUx9roc3QrA/W5bnt+hwghcHZxSwqPEJOvvzw7bTwvOB4XwaXXOLhrjsHQV2k80bh glLWcQD2qAIzQjvohIxXFKpM1PUK12WBFv3cPemmYEXV4DFzTvHj/0hYi/3FpfQ9YpYwj27jKFq ToIfqS8MyF2453ofnBv2hPjKz2NBwZfNONu+JnJ8UBC36yEtEp8T60WzAi0+wHKvpb06mumovGr e+7qGFtJvojFH7uLlr9KWAjg3pzlxQRGNw7dTXAXnFRqyQ3nKk3AqJRcae65F6I3jOm/E7FEyL1 4O+jTWscbUFGfccWCAOUAD X-Received: by 2002:a05:6808:1b0e:b0:467:2020:cae9 with SMTP id 5614622812f47-4672020e208mr1909172b6e.2.1773168074156; Tue, 10 Mar 2026 11:41:14 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41: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 v6 13/15] glibc-testsuite: Do not generate SPDX Date: Tue, 10 Mar 2026 12:38:33 -0600 Message-ID: <20260310184058.533343-14-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:24 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232824 glibc-testsuite does not run on target or factor into the build supply chain, since its purpose is run tests in Qemu at build time Signed-off-by: Joshua Watt --- meta/recipes-core/glibc/glibc-testsuite_2.42.bb | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/recipes-core/glibc/glibc-testsuite_2.42.bb b/meta/recipes-core/glibc/glibc-testsuite_2.42.bb index 6477612feb..1a83a09802 100644 --- a/meta/recipes-core/glibc/glibc-testsuite_2.42.bb +++ b/meta/recipes-core/glibc/glibc-testsuite_2.42.bb @@ -32,6 +32,7 @@ do_check:append () { } inherit nopackages +inherit nospdx deltask do_stash_locale deltask do_install deltask do_populate_sysroot From patchwork Tue Mar 10 18:38: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: 83018 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 30BEFFD4F29 for ; Tue, 10 Mar 2026 18:41:24 +0000 (UTC) Received: from mail-oi1-f174.google.com (mail-oi1-f174.google.com [209.85.167.174]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2602.1773168076043869795 for ; Tue, 10 Mar 2026 11:41:16 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20230601 header.b=ceAwd209; spf=pass (domain: gmail.com, ip: 209.85.167.174, mailfrom: jpewhacker@gmail.com) Received: by mail-oi1-f174.google.com with SMTP id 5614622812f47-4672076355aso755615b6e.2 for ; Tue, 10 Mar 2026 11:41:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773168075; x=1773772875; 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; bh=MUBzgp+fyUFvBBsxz2jPyyhfEK+4QWDU2iqhGmxuUuU=; b=ceAwd209jUWemGuggcJg14wNu++twvZ2/0bTGpDDsiANzgl/Db8CzkRYAqwzHid3q7 dhYqZ/x6NgYPf92zNBbmvdNuJxtHG7CK9DO58cD8QHDj6OPzoMKo6k2GuetN4hkXhQ7n BpqrPaXmueXoRkYHBW7UGoS0Rk38g6RVF8MFHIDWPsXl5mO/yB8jp1VFQjd/Irf5+bRw dpxZGwm1pRTBdNkigEIoEcPC7J1MVGlTap0rqrg2czSiAlkkAywe9q9jOcJJALbOhIX9 fuNlR/S2OMyLn42k773a2PcK2LRXUghkf/DI3jcBParYyzLFxp9ethjj4xc6vVZBqb2h Tn9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773168075; x=1773772875; 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; bh=MUBzgp+fyUFvBBsxz2jPyyhfEK+4QWDU2iqhGmxuUuU=; b=O1HEtkYk1Am6Oc+1nMBrovvBa/numYreesr63bl0LmeQmxUMkV9ijSWdUIz1KfA/2k Y7zc8Ubhuto19czp4ukNTYMKDHj4MyqhSFpsFKQzmgGVfT3jcgX4HkKCk2nDwMO4UZ// WXQnXGmjFPmdGUTzO7rbcVFWxi59jPclzz8C70susJ3tY36o2UKqYa9dD90fkt8szzNu fAbpkN5KIRyT6pQBmQNlxL6jxd5Qk+TneoGs2tSQ0eYyhoBmRkByCUkWtD8mGKJg89wl csPZocbhUa/54fdBosAnAl1VQ7DMXl9vRj5rhv8zgb/oIv7RF4bSYR/HBjx5g35YKpa+ SF5A== X-Gm-Message-State: AOJu0YxjQG388kBUt5Pu1J3FJ5bzZfAzapI1kxl/h+b+Z3vuRX31RIJc DHTKvmpOcp5ZaqDjJfC8w12ddR8yzizixHqEvyHabu2+yc5maSBBvempNAMP0A== X-Gm-Gg: ATEYQzxmhfdPfF9fE0DpTFmjxidcdDnzLmM1TkOfYwprhOWwpYiyJcXuvhDt38zYN7d Pqv7vQRv8RM3BGqr8fKir3Yvt71rkVdzW7ycZjWSc3FuNWlDjWhg19HgppluX57ciSZwLvRSpJX R2Ibnvwec7gJ3mdZ7jd84pdwKynsI0oVsDG1FnCIPj0KRys7pid+TWY1cO1rMBhlqZbJnwn0IZy Y9X555e0p+AYm8OAnk33lExB1vBv7Cl3mldvKvlXzfDUTkZSN0Fmnnr3S5m4oG7FkUHOgWl1lna 8/axnQOUm08d2z66oEMuQ5yIse+vdF8ZOZT/K/82ZrAYlAq2p08aiEhpbw/LaCMAMtl/h1eLsOm Gz4HbUyjScuvqHnDks550jJ2qAZ7cAaHHPb+o83FK/h31MXJVorJ6bapJV2JNFZBSVQH4LhvEkq UtGNHVcfWs6ljHjJiKA8UE X-Received: by 2002:a05:6808:2217:b0:464:305e:8fcc with SMTP id 5614622812f47-466dca4e89dmr9129773b6e.20.1773168075010; Tue, 10 Mar 2026 11:41:15 -0700 (PDT) Received: from localhost.localdomain ([2601:282:4200:11c0::9891]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4671d2a7ebfsm2444524b6e.20.2026.03.10.11.41.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Mar 2026 11:41: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 v6 14/15] spdx: Remove do_collect_spdx_deps task Date: Tue, 10 Mar 2026 12:38:34 -0600 Message-ID: <20260310184058.533343-15-JPEWhacker@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260310184058.533343-1-JPEWhacker@gmail.com> References: <20260304164835.3072507-1-JPEWhacker@gmail.com> <20260310184058.533343-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 aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Tue, 10 Mar 2026 18:41:24 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/232825 Removes the do_collect_spdx_deps task. This task was added a long time ago, and appears to have been added due to a misunderstanding about how the task graph works. It is not necessary since tasks can directly call collect_direct_deps() with the appropriate task that they depend on to get their dependencies. This should fix several classes of SPDX bug where documents could not be found because the wrong deps were being looked for due to which tasks were re-run Signed-off-by: Joshua Watt --- meta/classes-recipe/nospdx.bbclass | 1 - meta/classes/create-spdx-2.2.bbclass | 22 +++++---- meta/classes/create-spdx-3.0.bbclass | 5 +- meta/classes/spdx-common.bbclass | 22 --------- meta/lib/oe/spdx30_tasks.py | 22 +++++---- meta/lib/oe/spdx_common.py | 69 +++++++++++++--------------- 6 files changed, 62 insertions(+), 79 deletions(-) diff --git a/meta/classes-recipe/nospdx.bbclass b/meta/classes-recipe/nospdx.bbclass index 90e14442ba..7c99fcd1ec 100644 --- a/meta/classes-recipe/nospdx.bbclass +++ b/meta/classes-recipe/nospdx.bbclass @@ -4,7 +4,6 @@ # SPDX-License-Identifier: MIT # -deltask do_collect_spdx_deps deltask do_create_recipe_spdx deltask do_create_spdx deltask do_create_spdx_runtime diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass index aa39208eae..1c43156559 100644 --- a/meta/classes/create-spdx-2.2.bbclass +++ b/meta/classes/create-spdx-2.2.bbclass @@ -277,7 +277,7 @@ def add_package_sources_from_debug(d, package_doc, spdx_package, package, packag add_package_sources_from_debug[vardepsexclude] += "STAGING_KERNEL_DIR" -def collect_dep_recipes(d, doc, spdx_recipe): +def collect_dep_recipes(d, doc, spdx_recipe, direct_deps): import json from pathlib import Path import oe.sbom @@ -290,9 +290,7 @@ def collect_dep_recipes(d, doc, spdx_recipe): dep_recipes = [] - deps = oe.spdx_common.get_spdx_deps(d) - - for dep in deps: + for dep in direct_deps: # If this dependency is not calculated in the taskhash skip it. # Otherwise, it can result in broken links since this task won't # rebuild and see the new SPDX ID if the dependency changes @@ -405,7 +403,7 @@ do_create_recipe_spdx() { : } do_create_recipe_spdx[noexec] = "1" -addtask do_create_recipe_spdx after do_collect_spdx_deps +addtask do_create_recipe_spdx python do_create_spdx() { @@ -532,7 +530,8 @@ python do_create_spdx() { if archive is not None: recipe.packageFileName = str(recipe_archive.name) - dep_recipes = collect_dep_recipes(d, doc, recipe) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + dep_recipes = collect_dep_recipes(d, doc, recipe, direct_deps) doc_sha1 = oe.sbom.write_doc(d, doc, pkg_arch, "recipes", indent=get_json_indent(d)) dep_recipes.append(oe.sbom.DepRecipe(doc, doc_sha1, recipe)) @@ -603,7 +602,7 @@ python do_create_spdx() { } do_create_spdx[vardepsexclude] += "BB_NUMBER_THREADS" # NOTE: depending on do_unpack is a hack that is necessary to get it's dependencies for archive the source -addtask do_create_spdx after do_create_recipe_spdx do_package do_packagedata do_unpack do_patch do_collect_spdx_deps before do_populate_sdk do_build do_rm_work +addtask do_create_spdx after do_create_recipe_spdx do_package do_packagedata do_unpack do_patch before do_populate_sdk do_build do_rm_work SSTATETASKS += "do_create_spdx" do_create_spdx[sstate-inputdirs] = "${SPDXDEPLOY}" @@ -638,7 +637,9 @@ python do_create_runtime_spdx() { license_data = oe.spdx_common.load_spdx_license_data(d) - providers = oe.spdx_common.collect_package_providers(d) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + + providers = oe.spdx_common.collect_package_providers(d, direct_deps) pkg_arch = d.getVar("SSTATE_PKGARCH") package_archs = d.getVar("SPDX_MULTILIB_SSTATE_ARCHS").split() package_archs.reverse() @@ -760,6 +761,7 @@ addtask do_create_runtime_spdx_setscene do_create_runtime_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" do_create_runtime_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" +do_create_runtime_spdx[deptask] = "do_create_spdx" do_create_runtime_spdx[rdeptask] = "do_create_spdx" do_rootfs[recrdeptask] += "do_create_spdx do_create_runtime_spdx" @@ -829,7 +831,9 @@ def combine_spdx(d, rootfs_name, rootfs_deploydir, rootfs_spdxid, packages, spdx license_data = oe.spdx_common.load_spdx_license_data(d) - providers = oe.spdx_common.collect_package_providers(d) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + + providers = oe.spdx_common.collect_package_providers(d, direct_deps) package_archs = d.getVar("SPDX_MULTILIB_SSTATE_ARCHS").split() package_archs.reverse() diff --git a/meta/classes/create-spdx-3.0.bbclass b/meta/classes/create-spdx-3.0.bbclass index 6df66c193b..862e656b2c 100644 --- a/meta/classes/create-spdx-3.0.bbclass +++ b/meta/classes/create-spdx-3.0.bbclass @@ -186,13 +186,14 @@ python do_create_recipe_spdx() { import oe.spdx30_tasks oe.spdx30_tasks.create_recipe_spdx(d) } -addtask do_create_recipe_spdx after do_collect_spdx_deps +addtask do_create_recipe_spdx SSTATETASKS += "do_create_recipe_spdx" do_create_recipe_spdx[sstate-inputdirs] = "${SPDXRECIPEDEPLOY}" do_create_recipe_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" do_create_recipe_spdx[file-checksums] += "${SPDX3_DEP_FILES}" do_create_recipe_spdx[cleandirs] = "${SPDXRECIPEDEPLOY}" +do_create_recipe_spdx[deptask] += "do_create_recipe_spdx" do_create_recipe_spdx[vardeps] += "${SPDX3_VAR_DEPS}" python do_create_recipe_spdx_setscene () { @@ -208,7 +209,6 @@ addtask do_create_spdx after \ do_unpack \ do_patch \ do_create_recipe_spdx \ - do_collect_spdx_deps \ do_deploy_source_date_epoch \ do_populate_sysroot do_package do_packagedata \ before do_populate_sdk do_populate_sdk_ext do_build do_rm_work @@ -244,6 +244,7 @@ do_create_package_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" do_create_package_spdx[file-checksums] += "${SPDX3_DEP_FILES}" do_create_package_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" do_create_package_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" +do_create_package_spdx[deptask] = "do_create_spdx" do_create_package_spdx[rdeptask] = "do_create_spdx" do_create_package_spdx[vardeps] += "${SPDX3_VAR_DEPS}" diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass index abf2332bee..4b40cbf75c 100644 --- a/meta/classes/spdx-common.bbclass +++ b/meta/classes/spdx-common.bbclass @@ -87,28 +87,6 @@ def create_spdx_source_deps(d): return " ".join(deps) -python do_collect_spdx_deps() { - # This task calculates the build time dependencies of the recipe, and is - # required because while a task can deptask on itself, those dependencies - # do not show up in BB_TASKDEPDATA. To work around that, this task does the - # deptask on do_create_recipe_spdx and writes out the dependencies it finds, then - # downstream tasks read in the found dependencies when writing the actual - # SPDX document - import json - import oe.spdx_common - from pathlib import Path - - spdx_deps_file = Path(d.getVar("SPDXDEPS")) - - deps = oe.spdx_common.collect_direct_deps(d, "do_create_recipe_spdx") - - with spdx_deps_file.open("w") as f: - json.dump(deps, f) -} -addtask do_collect_spdx_deps -do_collect_spdx_deps[deptask] = "do_create_recipe_spdx" -do_collect_spdx_deps[dirs] = "${SPDXDIR}" - oe.spdx_common.collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" oe.spdx_common.collect_direct_deps[vardeps] += "DEPENDS" oe.spdx_common.collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index ba15d74278..76f3338fb8 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -298,13 +298,11 @@ def get_package_sources_from_debug( return dep_source_files -def collect_dep_objsets(d, subdir, fn_prefix, obj_type, **attr_filter): - deps = oe.spdx_common.get_spdx_deps(d) - +def collect_dep_objsets(d, direct_deps, subdir, fn_prefix, obj_type, **attr_filter): dep_objsets = [] dep_objs = set() - for dep in deps: + for dep in direct_deps: bb.debug(1, "Fetching SPDX for dependency %s" % (dep.pn)) dep_obj, dep_objset = oe.sbom30.find_root_obj_in_jsonld( d, subdir, fn_prefix + dep.pn, obj_type, **attr_filter @@ -551,8 +549,10 @@ def create_recipe_spdx(d): ) ) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_recipe_spdx") + dep_objsets, dep_recipes = collect_dep_objsets( - d, "static", "static-", oe.spdx30.software_Package + d, direct_deps, "static", "static-", oe.spdx30.software_Package ) if dep_recipes: @@ -753,8 +753,10 @@ def create_spdx(d): build_inputs |= files index_sources_by_hash(files, dep_sources) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + dep_objsets, dep_builds = collect_dep_objsets( - d, "builds", "build-", oe.spdx30.build_Build + d, direct_deps, "builds", "build-", oe.spdx30.build_Build ) if dep_builds: @@ -1071,7 +1073,9 @@ def create_package_spdx(d): deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) deploydir = Path(d.getVar("SPDXRUNTIMEDEPLOY")) - providers = oe.spdx_common.collect_package_providers(d) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + + providers = oe.spdx_common.collect_package_providers(d, direct_deps) pkg_arch = d.getVar("SSTATE_PKGARCH") if get_is_native(d): @@ -1248,7 +1252,9 @@ def write_bitbake_spdx(d): def collect_build_package_inputs(d, objset, build, packages, files_by_hash=None): import oe.sbom30 - providers = oe.spdx_common.collect_package_providers(d) + direct_deps = oe.spdx_common.collect_direct_deps(d, "do_create_spdx") + + providers = oe.spdx_common.collect_package_providers(d, direct_deps) build_deps = set() diff --git a/meta/lib/oe/spdx_common.py b/meta/lib/oe/spdx_common.py index 3aaf2a9c8b..c0ef11f199 100644 --- a/meta/lib/oe/spdx_common.py +++ b/meta/lib/oe/spdx_common.py @@ -38,7 +38,7 @@ def extract_licenses(filename): def is_work_shared_spdx(d): - return '/work-shared/' in d.getVar('S') + return "/work-shared/" in d.getVar("S") def load_spdx_license_data(d): @@ -77,12 +77,15 @@ def process_sources(d): return True -@dataclass(frozen=True) +@dataclass(frozen=True, eq=True, order=True) class Dep(object): pn: str hashfn: str in_taskhash: bool + def to_tuple(self): + return (self.pn, self.hashfn, self.in_taskhash) + def collect_direct_deps(d, dep_task): """ @@ -105,7 +108,9 @@ def collect_direct_deps(d, dep_task): ) if not dep_task in depflags: - bb.fatal(f"Task {dep_task} was not found in any dependency flag of {pn}:{current_task}") + bb.fatal( + f"Task {dep_task} was not found in any dependency flag of {pn}:{current_task}" + ) for this_dep in taskdepdata.values(): if this_dep[0] == pn and this_dep[1] == current_task: @@ -118,25 +123,14 @@ def collect_direct_deps(d, dep_task): for dep_name in this_dep.deps: dep_data = taskdepdata[dep_name] if dep_data.taskname == dep_task and dep_data.pn != pn: - deps.add((dep_data.pn, dep_data.hashfn, dep_name in this_dep.taskhash_deps)) + deps.add( + Dep(dep_data.pn, dep_data.hashfn, dep_name in this_dep.taskhash_deps) + ) return sorted(deps) -def get_spdx_deps(d): - """ - Reads the SPDX dependencies JSON file and returns the data - """ - spdx_deps_file = Path(d.getVar("SPDXDEPS")) - - deps = [] - with spdx_deps_file.open("r") as f: - for d in json.load(f): - deps.append(Dep(*d)) - return deps - - -def collect_package_providers(d): +def collect_package_providers(d, direct_deps): """ Returns a dictionary where each RPROVIDES is mapped to the package that provides it @@ -145,16 +139,15 @@ def collect_package_providers(d): providers = {} - deps = collect_direct_deps(d, "do_create_spdx") - deps.append((d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)) + all_deps = direct_deps + [Dep(d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)] - for dep_pn, dep_hashfn, _ in deps: + for dep in all_deps: localdata = d - recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) + recipe_data = oe.packagedata.read_pkgdata(dep.pn, localdata) if not recipe_data: localdata = bb.data.createCopy(d) localdata.setVar("PKGDATA_DIR", "${PKGDATA_DIR_SDK}") - recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) + recipe_data = oe.packagedata.read_pkgdata(dep.pn, localdata) for pkg in recipe_data.get("PACKAGES", "").split(): pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, localdata) @@ -171,7 +164,7 @@ def collect_package_providers(d): rprovides.add(pkg) for r in rprovides: - providers[r] = (pkg, dep_hashfn) + providers[r] = (pkg, dep.hashfn) return providers @@ -202,25 +195,21 @@ def get_patched_src(d): bb.build.exec_func("do_unpack", d) if d.getVar("SRC_URI") != "": - if bb.data.inherits_class('dos2unix', d): - bb.build.exec_func('do_convert_crlf_to_lf', d) + if bb.data.inherits_class("dos2unix", d): + bb.build.exec_func("do_convert_crlf_to_lf", d) bb.build.exec_func("do_patch", d) # Copy source from work-share to spdx_workdir if is_work_shared_spdx(d): - share_src = d.getVar('S') + share_src = d.getVar("S") d.setVar("WORKDIR", spdx_workdir) d.setVar("STAGING_DIR_NATIVE", spdx_sysroot_native) # Copy source to ${SPDXWORK}, same basename dir of ${S}; - src_dir = ( - spdx_workdir - + "/" - + os.path.basename(share_src) - ) + src_dir = spdx_workdir + "/" + os.path.basename(share_src) # For kernel souce, rename suffix dir 'kernel-source' # to ${BP} (${BPN}-${PV}) if bb.data.inherits_class("kernel", d): - src_dir = spdx_workdir + "/" + d.getVar('BP') + src_dir = spdx_workdir + "/" + d.getVar("BP") bb.note(f"copyhardlinktree {share_src} to {src_dir}") oe.path.copyhardlinktree(share_src, src_dir) @@ -233,7 +222,9 @@ def get_patched_src(d): def has_task(d, task): - return bool(d.getVarFlag(task, "task", False)) and not bool(d.getVarFlag(task, "noexec", False)) + return bool(d.getVarFlag(task, "task", False)) and not bool( + d.getVarFlag(task, "noexec", False) + ) def fetch_data_to_uri(fd, name): @@ -243,8 +234,8 @@ def fetch_data_to_uri(fd, name): uri = fd.type # crate: is not a valid URL. Use url field instead if exist - if uri == "crate" and hasattr(fd,"url"): - return fd.url + if uri == "crate" and hasattr(fd, "url"): + return fd.url # Map gitsm to git, since gitsm:// is not a valid URI protocol if uri == "gitsm": @@ -259,11 +250,13 @@ def fetch_data_to_uri(fd, name): return uri -def is_compiled_source (filename, compiled_sources, types): + +def is_compiled_source(filename, compiled_sources, types): """ Check if the file is a compiled file """ import os + # If we don't have compiled source, we assume all are compiled. if not compiled_sources: return True @@ -278,11 +271,13 @@ def is_compiled_source (filename, compiled_sources, types): # Check that the file is in the list return filename in compiled_sources + def get_compiled_sources(d): """ Get list of compiled sources from debug information and normalize the paths """ import itertools + source_info = oe.package.read_debugsources_info(d) if not source_info: bb.debug(1, "Do not have debugsources.list. Skipping")