@@ -36,6 +36,22 @@ 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 explicit license analysis \
+ (manual review or external scanning tools) has been performed and a license \
+ conclusion has been reached. When unset or empty, no concluded license is \
+ included in the SBOM, indicating that no license analysis was performed. \
+ When differences from the declared LICENSE 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. \
+ Supports package-specific overrides via SPDX_CONCLUDED_LICENSE:${PN}. \
+ This allows tracking license analysis results in SBOM while maintaining recipe \
+ LICENSE field for build compatibility. \
+ Example: SPDX_CONCLUDED_LICENSE = 'MIT & Apache-2.0' or \
+ SPDX_CONCLUDED_LICENSE:${PN} = 'MIT & Apache-2.0'"
+
SPDX_MULTILIB_SSTATE_ARCHS ??= "${SSTATE_ARCHS}"
python () {
@@ -712,6 +712,20 @@ def create_spdx(d):
oe.spdx30.RelationshipType.hasDeclaredLicense,
[oe.sbom30.get_element_link_id(package_spdx_license)],
)
+
+ # 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")
+ if concluded_license_str:
+ concluded_spdx_license = add_license_expression(
+ d, build_objset, concluded_license_str, license_data
+ )
+
+ 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()