>From 4b9338d0083d1b79319a82e9e6858c553ea3111c Mon Sep 17 00:00:00 2001 From: Stefano Tondo <[email protected]> Date: Mon, 16 Feb 2026 21:40:14 +0100 Subject: [OE-core][PATCH] oeqa/selftest: Add test for SPDX_CONCLUDED_LICENSE behavior
Add a selftest for the SPDX_CONCLUDED_LICENSE variable (introduced in commit bb21c6a429) to verify the conditional behavior doesn't change or break, as requested during review. The test verifies three scenarios: 1. Global SPDX_CONCLUDED_LICENSE creates a hasConcludedLicense relationship on the package 2. Package-specific override (SPDX_CONCLUDED_LICENSE:<pkg>) takes precedence over the global value 3. When unset, no hasConcludedLicense relationship is added Signed-off-by: Stefano Tondo <[email protected]> --- meta/lib/oeqa/selftest/cases/spdx.py | 112 +++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index 41ef52fce1..13386ef648 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -146,6 +146,118 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", ) + def test_concluded_license(self): + """ + Test that SPDX_CONCLUDED_LICENSE creates a hasConcludedLicense + relationship with correct conditional behavior: + + 1. When SPDX_CONCLUDED_LICENSE is set, a hasConcludedLicense + relationship is added to the package + 2. Package-specific overrides (SPDX_CONCLUDED_LICENSE:<pkg>) + take precedence over the global value + 3. When unset, no hasConcludedLicense relationship is present + """ + # Test 1: Verify hasConcludedLicense is created when variable is set + objset = self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", + extraconf="""\ + SPDX_CONCLUDED_LICENSE = "MIT" + """, + ) + + # Find base-files package + for pkg in objset.foreach_type(oe.spdx30.software_Package): + if "base-files" in pkg.name: + break + else: + self.assertTrue(False, "Unable to find base-files package") + + # Verify hasConcludedLicense relationship exists + for rel in objset.foreach_type(oe.spdx30.Relationship): + if ( + rel.relationshipType + == oe.spdx30.RelationshipType.hasConcludedLicense + and any(pkg._id == f._id for f in rel.from_) + ): + self.assertGreater( + len(rel.to), + 0, + "hasConcludedLicense should reference a license", + ) + break + else: + self.assertTrue( + False, + "SPDX_CONCLUDED_LICENSE should create hasConcludedLicense relationship", + ) + + # Test 2: Verify package-specific override takes precedence + objset = self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", + extraconf="""\ + SPDX_CONCLUDED_LICENSE = "GPL-2.0-only" + SPDX_CONCLUDED_LICENSE:base-files = "BSD-3-Clause" + """, + ) + + for pkg in objset.foreach_type(oe.spdx30.software_Package): + if "base-files" in pkg.name: + break + else: + self.assertTrue(False, "Unable to find base-files package") + + for rel in objset.foreach_type(oe.spdx30.Relationship): + if ( + rel.relationshipType + == oe.spdx30.RelationshipType.hasConcludedLicense + and any(pkg._id == f._id for f in rel.from_) + ): + # Verify the concluded license is the package-specific one + for to_id in rel.to: + for lic in objset.foreach_type( + oe.spdx30.simplelicensing_AnyLicenseInfo + ): + if lic._id == to_id._id and hasattr( + lic, "simplelicensing_licenseExpression" + ): + self.assertIn( + "BSD-3-Clause", + lic.simplelicensing_licenseExpression, + "Package-specific override should take precedence", + ) + break + break + else: + self.assertTrue( + False, + "Package-specific SPDX_CONCLUDED_LICENSE should create relationship", + ) + + # Test 3: Verify no hasConcludedLicense when variable is unset + objset = self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", + ) + + for pkg in objset.foreach_type(oe.spdx30.software_Package): + if "base-files" in pkg.name: + break + else: + self.assertTrue(False, "Unable to find base-files package") + + for rel in objset.foreach_type(oe.spdx30.Relationship): + if ( + rel.relationshipType + == oe.spdx30.RelationshipType.hasConcludedLicense + and any(pkg._id == f._id for f in rel.from_) + ): + self.assertTrue( + False, + "No hasConcludedLicense should exist when SPDX_CONCLUDED_LICENSE is unset", + ) + def test_gcc_include_source(self): objset = self.check_recipe_spdx( "gcc", -- 2.53.0 ________________________________ From: Ross Burton <[email protected]> Sent: Tuesday, February 10, 2026 13:19 To: [email protected] <[email protected]> Cc: [email protected] <[email protected]>; Tondo, Stefano (ext) (SI B PRO AUT PD ZUG SW 2) <[email protected]>; Marko, Peter (FT D EU SK BFS1) <[email protected]>; Freihofer, Adrian (SI B PRO TI EAC CCP) <[email protected]>; Joshua Watt <[email protected]> Subject: Re: [OE-core] [PATCH v4] spdx30_tasks: Add concluded license support with SPDX_CONCLUDED_LICENSE Hi Stefano, > On 7 Jan 2026, at 18:15, Stefano Tondo via lists.openembedded.org > <[email protected]> wrote: > Add hasConcludedLicense relationship to SBOM packages with support for > manual license conclusion override via SPDX_CONCLUDED_LICENSE variable. > > The concluded license represents the license determination after manual > or external license analysis. This should be set manually in recipes or > layers when: > > 1. Manual license review identifies differences from the declared LICENSE > 2. External license scanning tools detect additional license information > 3. Legal review concludes a different license applies > > The hasConcludedLicense relationship is ONLY added to the SBOM when > SPDX_CONCLUDED_LICENSE is explicitly set. When unset or empty, no > concluded license is included in the SBOM, correctly indicating that > no license analysis was performed (per SPDX semantics). Could you add a test case to oeqa to this, so that we know the conditional behaviour doesn’t change or break? Thanks Ross
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#231224): https://lists.openembedded.org/g/openembedded-core/message/231224 Mute This Topic: https://lists.openembedded.org/mt/117139043/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
