On Thu, Dec 18, 2025 at 5:02 AM Stefano Tondo via
lists.openembedded.org <[email protected]>
wrote:
>
> From: Stefano Tondo <[email protected]>
>
> 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
>
> By default, concluded license equals declared license (indicating no
> separate license analysis was performed). When differences are found,
> users should:
>
> 1. Preferably: Correct the LICENSE field in the recipe and contribute
>    the fix upstream to OpenEmbedded
> 2. Alternatively: Set SPDX_CONCLUDED_LICENSE locally in your layer when
>    upstream contribution is not immediately possible or when the license
>    conclusion is environment-specific
>
> This variable allows tracking license analysis results in the SBOM while
> maintaining the recipe LICENSE field for build system compatibility.
>
> The variable is initialized in spdx-common.bbclass with comprehensive
> documentation explaining its purpose, usage guidelines, and examples.
>
> Example usage in recipe or layer:
>   SPDX_CONCLUDED_LICENSE = "MIT & Apache-2.0"
>
> Signed-off-by: Stefano Tondo <[email protected]>
> ---
>  meta/classes/spdx-common.bbclass | 13 +++++++++++++
>  meta/lib/oe/spdx30_tasks.py      | 21 +++++++++++++++++++++
>  2 files changed, 34 insertions(+)
>
> diff --git a/meta/classes/spdx-common.bbclass 
> b/meta/classes/spdx-common.bbclass
> index ca0416d1c7..3ca4c70cc0 100644
> --- a/meta/classes/spdx-common.bbclass
> +++ b/meta/classes/spdx-common.bbclass
> @@ -36,6 +36,19 @@ SPDX_LICENSES ??= 
> "${COREBASE}/meta/files/spdx-licenses.json"
>
>  SPDX_CUSTOM_ANNOTATION_VARS ??= ""
>
> +SPDX_CONCLUDED_LICENSE ??= ""
> +SPDX_CONCLUDED_LICENSE[doc] = "The license concluded by manual or external \
> +    license analysis. This should only be set when license analysis (manual 
> review \
> +    or external scanning tools) identifies differences from the declared 
> LICENSE. \
> +    When unset or empty, the concluded license defaults to the declared 
> license, \
> +    indicating no separate analysis was performed. When differences are 
> found, the \
> +    preferred approach is to correct the LICENSE field in the recipe and 
> contribute \
> +    the fix upstream to OpenEmbedded. Use this variable locally only when 
> upstream \
> +    contribution is not immediately possible or when the license conclusion 
> is \
> +    environment-specific. This allows tracking license analysis results in 
> SBOM \
> +    while maintaining recipe LICENSE field for build compatibility. \
> +    Example: SPDX_CONCLUDED_LICENSE = 'MIT & Apache-2.0'"
> +

It's unfortunate that the concluded license can't use an actual SPDX
license string; using an OE license string means converting.

Presumably, the reason for doing this is so that you can do:

SPDX_CONCLUDED_LICENSE = "${LICENSE}"

Is that a valid use case? If not, we should use an actual SPDX license
string instead.

>  SPDX_MULTILIB_SSTATE_ARCHS ??= "${SSTATE_ARCHS}"
>
>  python () {
> diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py
> index 286a08ed9b..84d70f6f72 100644
> --- a/meta/lib/oe/spdx30_tasks.py
> +++ b/meta/lib/oe/spdx30_tasks.py
> @@ -712,6 +712,27 @@ def create_spdx(d):
>                  oe.spdx30.RelationshipType.hasDeclaredLicense,
>                  [oe.sbom30.get_element_link_id(package_spdx_license)],
>              )
> +
> +            # Add concluded license relationship
> +            # Use SPDX_CONCLUDED_LICENSE if set, otherwise default to 
> declared license
> +            concluded_license_str = d.getVar("SPDX_CONCLUDED_LICENSE")
> +            if concluded_license_str:
> +                # Use explicitly set concluded license
> +                if concluded_license_str != package_license and 
> concluded_license_str != d.getVar("LICENSE"):
> +                    concluded_spdx_license = add_license_expression(
> +                        d, build_objset, concluded_license_str, license_data
> +                    )

You can't make the concluded license default to the declared license.
The concluded license is the license that you (then end user)
determines is applicable, and we can't have the core code making that
assumption for users. If no concluded license is explicitly set by the
user, then it should not be in the SPDX.

> +                else:
> +                    concluded_spdx_license = package_spdx_license
> +            else:
> +                # Default: concluded = declared (no analysis performed)
> +                concluded_spdx_license = package_spdx_license
> +
> +            pkg_objset.new_relationship(
> +                [spdx_package],
> +                oe.spdx30.RelationshipType.hasConcludedLicense,
> +                [oe.sbom30.get_element_link_id(concluded_spdx_license)],
> +            )
>
>              # NOTE: CVE Elements live in the recipe collection
>              all_cves = set()
> --
> 2.52.0
>
>
> 
>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#228875): 
https://lists.openembedded.org/g/openembedded-core/message/228875
Mute This Topic: https://lists.openembedded.org/mt/116840957/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to