[PATCH v4 00/10] Add SBOM generation with debsbom

25 views
Skip to first unread message

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:52 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
This patchset adds proper SBOM generation in the two standard formats
SPDX and CycloneDX during the rootfs generation process.

The generation is itself is handled by a SBOM generator `debsbom` [1]
which is developed as an open source project at Siemens. It is still
early in development, but it has enough features for what we require
in isar. The required dependencies which are not yet available as
Debian packages were minimally packaged directly in isar too.

This is a followup of the previous RFC [2]. Since then the series has
changed a lot. The SBOM generation was moved from a simple OE lib to
`debsbom`. This also meant the introduction of a separate chroot was
necessary. The SBOM generation process was also moved from the image
step to the rootfs step, along with a lot of minor changes and
improvements.

[1] https://github.com/siemens/debsbom
[2] https://groups.google.com/g/isar-users/c/8L-CF4BJY0I/m/p0N3o_zfAAAJ

Changes since v3:

- fix issue on external bullseye initramfs (we now disable sbom generation
on all unsupported distros rootfs instances)
- update debsbom to v0.4.0
- rebased onto next

Changes since v2:

- fix issues when HOST_ARCH != DISTRO_ARCH on derived distributions
- update debsbom to v0.3.0, which fixes the Origin: bug reported in v2
- generate SBOM for imager as well and create merged sbom of .wic image
- resend imager manifest + wic manifest patches to reduce conflicts

Note, that the patches p1-p5 are most important as they add basic SBOM
support. The remaining patches address the imager + .wic bom part,
which also can be merged later on.

Changes since v1:

- remove tarball
- refactor packaging (auto-derive python dependencies)
- only build missing packages (varies on bookworm, trixie, noble)
- add ubuntu support
- only generate sboms for supported distributions (bookworm/jammy and
onwards)
- update debsbom (includes bug fixes and more information for source
packages)

Christoph Steiger (3):
meta: package python libraries for SBOM generation
meta: package python3-debsbom
meta: add SBOM generation with debsbom

Felix Moessbauer (7):
refactor: move get_rootfs_distro from sdk into rootfs
override distro vendor in SBOM on Ubuntu
add support to add imager dependencies to BOM
wic: create uniform manifest describing all image components
qemuamd64: add IMAGER_BOM entries
imager: create SBOM of IMAGER_BOM packages
wic: create uniform SBOM describing all image components

doc/user_manual.md | 1 +
meta-isar/conf/distro/ubuntu-common.inc | 2 +
meta-isar/conf/machine/qemuamd64.conf | 1 +
meta/classes/image-tools-extension.bbclass | 29 +++++++++
meta/classes/image.bbclass | 7 ++
meta/classes/imagetypes_wic.bbclass | 30 +++++++++
meta/classes/initramfs.bbclass | 3 +-
meta/classes/rootfs.bbclass | 23 ++++++-
meta/classes/sbom.bbclass | 64 +++++++++++++++++++
meta/classes/sdk.bbclass | 10 +--
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
.../python3-beartype/files/rules | 8 +++
.../python3-beartype_0.19.0.bb | 29 +++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 +++
.../python3-cyclonedx-lib_9.1.0.bb | 48 ++++++++++++++
...icense-description-in-pyproject.toml.patch | 28 ++++++++
.../python3-debsbom/files/rules | 8 +++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++
.../python3-packageurl/files/rules | 8 +++
.../python3-packageurl_0.16.0.bb | 33 ++++++++++
.../python3-py-serializable/files/rules | 8 +++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++
.../python3-spdx-tools/files/rules | 25 ++++++++
.../python3-spdx-tools_0.8.3.bb | 46 +++++++++++++
25 files changed, 522 insertions(+), 11 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:53 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package python libraries for SBOM generation in isar. The packages are
unfortunately not (yet) packaged in Debian, thats why we need to do it
here. With these libraries it is now possible to easily create CDX and
SPDX SBOMs in different file formats.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
.../python3-beartype/files/rules | 8 ++++
.../python3-beartype_0.19.0.bb | 29 +++++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 ++++
.../python3-cyclonedx-lib_9.1.0.bb | 48 +++++++++++++++++++
.../python3-packageurl/files/rules | 8 ++++
.../python3-packageurl_0.16.0.bb | 33 +++++++++++++
.../python3-py-serializable/files/rules | 8 ++++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++++++
.../python3-spdx-tools/files/rules | 25 ++++++++++
.../python3-spdx-tools_0.8.3.bb | 46 ++++++++++++++++++
11 files changed, 252 insertions(+)
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

diff --git a/meta/recipes-support/python3-beartype/files/rules b/meta/recipes-support/python3-beartype/files/rules
new file mode 100644
index 00000000..0ca517a1
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = beartype
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
new file mode 100644
index 00000000..b8bc2708
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
@@ -0,0 +1,29 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/beartype-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), dh-python, python3-all, python3-setuptools, pybuild-plugin-pyproject, python3-hatchling"
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+# this is 01/01/1980, any earlier and zip in the wheel building process will not accept it
+DEBIAN_CHANGELOG_TIMESTAMP = "315532800"
+DESCRIPTION = "Unbearably fast near-real-time hybrid runtime-static type-checking in pure Python."
+
+SRC_URI = "\
+ https://github.com/beartype/beartype/archive/refs/tags/v0.19.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e7ad00eebf527d60f30e0b391209b561dabd2074b608c50e26c94c2d8250a6cd"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
new file mode 100644
index 00000000..cc736a36
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
@@ -0,0 +1 @@
+pyproject.toml
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/rules b/meta/recipes-support/python3-cyclonedx-lib/files/rules
new file mode 100644
index 00000000..fe72dd1a
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = cyclonedx-python-lib
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
new file mode 100644
index 00000000..738ed1b3
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
@@ -0,0 +1,48 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+DEPENDS:append:bookworm = " python3-packageurl python3-py-serializable"
+DEPENDS:append:noble = " python3-packageurl python3-py-serializable"
+
+S = "${WORKDIR}/cyclonedx_python_lib-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-poetry, \
+ python3-py-serializable, \
+ python3-packageurl, \
+ python3-sortedcontainers, \
+ python3-ddt, \
+ python3-defusedxml, \
+ python3-license-expression, \
+ python3-jsonschema, \
+ python3-lxml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/CycloneDX/cyclonedx-python-lib/releases/download/v9.1.0/cyclonedx_python_lib-9.1.0.tar.gz \
+ file://rules \
+ file://pybuild.testfiles \
+ "
+SRC_URI[sha256sum] = "86935f2c88a7b47a529b93c724dbd3e903bc573f6f8bd977628a7ca1b5dadea1"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ cp "${WORKDIR}"/pybuild.testfiles "${S}"/debian
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-packageurl/files/rules b/meta/recipes-support/python3-packageurl/files/rules
new file mode 100644
index 00000000..50e1b74c
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = packageurl-python
+export PYBUILD_SYSTEM = distutils
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
new file mode 100644
index 00000000..27209429
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
@@ -0,0 +1,33 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/packageurl_python-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "A purl aka. Package URL parser and builder"
+
+SRC_URI = "\
+ https://github.com/package-url/packageurl-python/releases/download/v0.16.0/packageurl_python-0.16.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "69e3bf8a3932fe9c2400f56aaeb9f86911ecee2f9398dbe1b58ec34340be365d"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-py-serializable/files/rules b/meta/recipes-support/python3-py-serializable/files/rules
new file mode 100644
index 00000000..0cf845dd
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = py-serializable
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
new file mode 100644
index 00000000..5bc48c0f
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
@@ -0,0 +1,38 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/py_serializable-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = " \
+ dh-sequence-python3, \
+ pybuild-plugin-pyproject, \
+ python3-all, \
+ python3-defusedxml, \
+ python3-lxml, \
+ python3-poetry-core, \
+ python3-setuptools, \
+ xmldiff, \
+"
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/madpah/serializable/releases/download/v2.0.0/py_serializable-2.0.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e9e6491dd7d29c31daf1050232b57f9657f9e8a43b867cca1ff204752cf420a5"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-spdx-tools/files/rules b/meta/recipes-support/python3-spdx-tools/files/rules
new file mode 100644
index 00000000..ac87528a
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/files/rules
@@ -0,0 +1,25 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = spdx-tools
+export PYBUILD_SYSTEM = distutils
+
+# skip tests that require hard-to-package dependencies and tests that rely on relative file paths
+# TODO: figure out a way to make these tests work
+export PYBUILD_TEST_ARGS=--ignore tests/spdx3/validation/json_ld/test_shacl_validation.py \
+ -k 'not test_examples \
+ and not test_parse_from_file \
+ and not test_annotation_parser \
+ and not test_snippet_parser \
+ and not test_creation_info_parser \
+ and not test_json_ld_writer \
+ and not test_extracted_licensing_info_parser \
+ and not test_parse_file \
+ and not test_package_parser \
+ and not test_relationship_parser \
+ and not test_graph_parsing_function \
+ and not test_license_expression_parser \
+ '
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
new file mode 100644
index 00000000..30d090a9
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
@@ -0,0 +1,46 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/tools-python-${PV}"
+
+DEPENDS:append:bookworm = " python3-beartype"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ python3-beartype, \
+ python3-semantic-version, \
+ python3-license-expression, \
+ python3-pytest <!nocheck>, \
+ python3-rdflib, \
+ python3-uritools, \
+ python3-ply, \
+ python3-click, \
+ python3-xmltodict, \
+ python3-yaml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+DEB_BUILD_PROFILES += "nocheck"
+DEB_BUILD_OPTIONS += "nocheck"
+
+DESCRIPTION = "SPDX parser and tools."
+
+SRC_URI = "\
+ https://github.com/spdx/tools-python/archive/refs/tags/v0.8.3.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "17cb0140adbaefb58819c9d5d56060dc6a70c673a854fa9bd882ecfa4e062a7f"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:53 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package the python tool debsbom for SBOM generation for Debian based
distributions.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
...icense-description-in-pyproject.toml.patch | 28 ++++++++++++
.../python3-debsbom/files/rules | 8 ++++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++++++++
3 files changed, 81 insertions(+)
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb

diff --git a/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch b/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
new file mode 100644
index 00000000..c9137e25
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
@@ -0,0 +1,28 @@
+From 8f926ab0ed1585656ba7de80a82cc802c3ccbdbf Mon Sep 17 00:00:00 2001
+From: Christoph Steiger <christop...@siemens.com>
+Date: Mon, 8 Sep 2025 17:17:49 +0200
+Subject: [PATCH 1/1] Use old license description in pyproject.toml
+
+Older setuptools versions may require a different license field.
+
+Signed-off-by: Christoph Steiger <christop...@siemens.com>
+---
+ pyproject.toml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/pyproject.toml b/pyproject.toml
+index cc34bdb..701da4a 100644
+--- a/pyproject.toml
++++ b/pyproject.toml
+@@ -22,7 +22,7 @@ maintainers = [
+ ]
+ description = "Generate SBOMs for Debian-based distributions."
+ readme = "README.md"
+-license = "MIT"
++license = {text = "MIT"}
+ classifiers = [
+ "Intended Audience :: Developers",
+ "Operating System :: POSIX :: Linux",
+--
+2.39.5
+
diff --git a/meta/recipes-support/python3-debsbom/files/rules b/meta/recipes-support/python3-debsbom/files/rules
new file mode 100644
index 00000000..a414114d
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = debsbom
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
new file mode 100644
index 00000000..410f358a
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
@@ -0,0 +1,45 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "python3-spdx-tools"
+DEPENDS:append:bookworm = " python3-packageurl python3-cyclonedx-lib"
+DEPENDS:append:noble = " python3-packageurl python3-cyclonedx-lib"
+
+S = "${WORKDIR}/git"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-packageurl, \
+ python3-cyclonedx-lib, \
+ python3-spdx-tools, \
+ python3-debian, \
+ python3-requests, \
+ python3-zstandard, \
+ "
+
+DEBIAN_DEPENDS = "python3-apt, \${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "debsbom generates SBOMs for Debian based distributions."
+
+SRC_URI = "git://github.com/siemens/debsbom.git;protocol=https;branch=main; \
+ file://rules \
+ file://0001-Use-old-license-description-in-pyproject.toml.patch \
+ "
+SRCREV = "a600f60966d08803eb17bfb81eb8828921497453"

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:55 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
When generating an SBOM for Ubuntu, the vendor component of the PURL
needs to be ubuntu (instead of debian). We now set it accordingly.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta-isar/conf/distro/ubuntu-common.inc | 2 ++
1 file changed, 2 insertions(+)

diff --git a/meta-isar/conf/distro/ubuntu-common.inc b/meta-isar/conf/distro/ubuntu-common.inc
index f1e8a1d6..ffc41afe 100644
--- a/meta-isar/conf/distro/ubuntu-common.inc
+++ b/meta-isar/conf/distro/ubuntu-common.inc
@@ -45,3 +45,5 @@ SYSTEMD_BOOTLOADER_INSTALL:jammy = "systemd:${DISTRO_ARCH}"

# snapshot mirror for reproducible builds
DISTRO_APT_SNAPSHOT_PREMIRROR ??= "(http|https)://archive.ubuntu.com/(.*) https://snapshot.ubuntu.com/\2/${ISAR_APT_SNAPSHOT_DATE_INTERNAL}\n"
+
+SBOM_BASE_DISTRO_VENDOR ?= "ubuntu"
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:56 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
From: Christoph Steiger <christop...@siemens.com>

Generate SBOMs for every rootfs that is created. These SBOMs are placed
in the image deploy directory.

For the generation a small chroot with debsbom installed is created and
from that the rootfs of the image is scanned.

The sbom generation is bound to the rootfs feature `generate-sbom`
which is activated per default now.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image.bbclass | 1 +
meta/classes/initramfs.bbclass | 3 +-
meta/classes/rootfs.bbclass | 14 +++-
meta/classes/sbom.bbclass | 64 +++++++++++++++++++
meta/classes/sdk.bbclass | 2 +-
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
6 files changed, 111 insertions(+), 3 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb

diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index 1fa71c17..29324920 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass
@@ -99,6 +99,7 @@ ROOTFS_FEATURES += "\
clean-log-files \
clean-debconf-cache \
populate-systemd-preset \
+ generate-sbom \
"
ROOTFS_PACKAGES += "${IMAGE_PREINSTALL} ${@isar_multiarch_packages('IMAGE_INSTALL', d)}"
ROOTFS_MANIFEST_DEPLOY_DIR ?= "${DEPLOY_DIR_IMAGE}"
diff --git a/meta/classes/initramfs.bbclass b/meta/classes/initramfs.bbclass
index 862bd873..570780e1 100644
--- a/meta/classes/initramfs.bbclass
+++ b/meta/classes/initramfs.bbclass
@@ -22,11 +22,12 @@ INITRAMFS_FULLNAME = "${PN}-${DISTRO}-${MACHINE}"
# Bill-of-material
ROOTFS_MANIFEST_DEPLOY_DIR = "${DEPLOY_DIR_IMAGE}"
ROOTFS_PACKAGE_SUFFIX = "${INITRAMFS_FULLNAME}"
+SBOM_DISTRO_NAME:append = "-initramfs"

DEPENDS += "${INITRAMFS_INSTALL}"

ROOTFSDIR = "${INITRAMFS_ROOTFS}"
-ROOTFS_FEATURES = "generate-manifest"
+ROOTFS_FEATURES = "generate-manifest generate-sbom"
ROOTFS_PACKAGES = "${INITRAMFS_GENERATOR_PKG} ${INITRAMFS_PREINSTALL} ${INITRAMFS_INSTALL}"

# validate if have incompatible packages in the installation list
diff --git a/meta/classes/rootfs.bbclass b/meta/classes/rootfs.bbclass
index c045bfc0..b3ca9e16 100644
--- a/meta/classes/rootfs.bbclass
+++ b/meta/classes/rootfs.bbclass
@@ -3,6 +3,8 @@

inherit deb-dl-dir

+inherit sbom
+
ROOTFS_ARCH ?= "${DISTRO_ARCH}"
ROOTFS_DISTRO ?= "${DISTRO}"

@@ -28,11 +30,18 @@ INITRD_IMAGE ?= ""
# available features are:
# 'clean-package-cache' - delete package cache from rootfs
# 'generate-manifest' - generate a package manifest of the rootfs into ${ROOTFS_MANIFEST_DEPLOY_DIR}
+# 'generate-sbom' - generate a SBOM of the rootfs into ${DEPLOY_DIR_SBOM}
# 'export-dpkg-status' - exports /var/lib/dpkg/status file to ${ROOTFS_DPKGSTATUS_DEPLOY_DIR}
# 'clean-log-files' - delete log files that are not owned by packages
# 'populate-systemd-preset' - enable systemd units according to systemd presets
+
# 'generate-initrd' - generate debian default initrd
ROOTFS_FEATURES += "${@ 'generate-initrd' if d.getVar('INITRD_IMAGE') == '' else ''}"
+# only supported from bookworm / jammy on
+ROOTFS_FEATURES:remove:buster = "generate-sbom"
+ROOTFS_FEATURES:remove:bullseye = "generate-sbom"
+ROOTFS_FEATURES:remove:jammy = "generate-sbom"
+ROOTFS_FEATURES:remove:focal = "generate-sbom"

ROOTFS_APT_ARGS="install --yes -o Debug::pkgProblemResolver=yes"

@@ -478,6 +487,9 @@ cache_dbg_pkgs() {
fi
}

+# The sbom generator needs the apt-cache, hence run before cleaning it
+ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'do_generate_sbom', '', d)}"
+
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-package-cache', 'rootfs_postprocess_clean_package_cache', '', d)}"
rootfs_postprocess_clean_package_cache() {
sudo -E chroot '${ROOTFSDIR}' \
@@ -647,7 +659,7 @@ python do_rootfs() {
}
addtask rootfs before do_build

-do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config"
+do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'sbom-chroot:do_sbomchroot_deploy', '', d)}"

SSTATETASKS += "do_rootfs_install"
SSTATECREATEFUNCS += "rootfs_install_sstate_prepare"
diff --git a/meta/classes/sbom.bbclass b/meta/classes/sbom.bbclass
new file mode 100644
index 00000000..fd41296c
--- /dev/null
+++ b/meta/classes/sbom.bbclass
@@ -0,0 +1,64 @@
+# This software is a part of ISAR.
+# Copyright (C) 2025 Siemens
+#
+# SPDX-License-Identifier: MIT
+
+# sbom type to generate, accepted are "cdx" or "spdx"
+SBOM_TYPES ?= "spdx cdx"
+
+SBOM_DEBSBOM_TYPE_ARGS = "${@"-t " + " -t ".join(d.getVar("SBOM_TYPES").split())}"
+
+# general user variables
+SBOM_DISTRO_SUPPLIER ?= "ISAR"
+SBOM_DISTRO_NAME ?= "ISAR-Debian-GNU-Linux"
+SBOM_DISTRO_VERSION ?= "1"
+SBOM_DISTRO_SUMMARY ?= "Linux distribution built with ISAR"
+SBOM_BASE_DISTRO_VENDOR ??= "debian"
+SBOM_DOCUMENT_UUID ?= ""
+
+# SPDX specific user variables
+SBOM_SPDX_NAMESPACE_PREFIX ?= "https://spdx.org/spdxdocs"
+
+DEPLOY_DIR_SBOM = "${DEPLOY_DIR_IMAGE}"
+
+SBOM_DIR = "${DEPLOY_DIR}/sbom"
+SBOM_CHROOT = "${SBOM_DIR}/sbom-chroot"
+
+# adapted from the isar-cip-core image_uuid.bbclass
+def generate_document_uuid(d, warn_not_repr=True):
+ import uuid
+
+ base_hash = d.getVar("BB_TASKHASH")
+ if base_hash is None:
+ if warn_not_repr:
+ bb.warn("no BB_TASKHASH available, SBOM UUID is not reproducible")
+ return uuid.uuid4()
+ return str(uuid.UUID(base_hash[:32], version=4))
+
+def sbom_doc_uuid(d):
+ if not d.getVar("SBOM_DOCUMENT_UUID"):
+ d.setVar("SBOM_DOCUMENT_UUID", generate_document_uuid(d))
+
+generate_sbom() {
+ sudo mkdir -p ${SBOM_CHROOT}/mnt/rootfs ${SBOM_CHROOT}/mnt/deploy-dir
+
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ --bind ${ROOTFSDIR} /mnt/rootfs \
+ --bind ${DEPLOY_DIR_SBOM} /mnt/deploy-dir \
+ -- debsbom -v generate ${SBOM_DEBSBOM_TYPE_ARGS} -r /mnt/rootfs -o /mnt/deploy-dir/'${PN}-${DISTRO}-${MACHINE}' \
+ --distro-name '${SBOM_DISTRO_NAME}' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber '${SBOM_DOCUMENT_UUID}' \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-'${SBOM_DOCUMENT_UUID}' \
+ --timestamp $TIMESTAMP
+}
+
+python do_generate_sbom() {
+ sbom_doc_uuid(d)
+ bb.build.exec_func("generate_sbom", d)
+}
diff --git a/meta/classes/sdk.bbclass b/meta/classes/sdk.bbclass
index 00cae0da..d57269e5 100644
--- a/meta/classes/sdk.bbclass
+++ b/meta/classes/sdk.bbclass
@@ -47,7 +47,7 @@ SDK_PREINSTALL += " \
ROOTFS_ARCH:class-sdk = "${HOST_ARCH}"
ROOTFS_DISTRO:class-sdk = "${@get_rootfs_distro(d)}"
ROOTFS_PACKAGES:class-sdk = "sdk-files ${SDK_TOOLCHAIN} ${SDK_PREINSTALL} ${@isar_multiarch_packages('SDK_INSTALL', d)}"
-ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status"
+ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status generate-sbom"
ROOTFS_MANIFEST_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"
ROOTFS_DPKGSTATUS_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"

diff --git a/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
new file mode 100644
index 00000000..58200382
--- /dev/null
+++ b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
@@ -0,0 +1,30 @@
+# This software is a part of ISAR.
+#
+# Copyright (C) 2025 Siemens
+
+LICENSE = "gpl-2.0"
+LIC_FILES_CHKSUM = "file://${LAYERDIR_core}/licenses/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
+
+PV = "1.0"
+
+inherit rootfs
+
+ROOTFS_ARCH = "${HOST_ARCH}"
+ROOTFS_DISTRO = "${@get_rootfs_distro(d)}"
+ROOTFS_BASE_DISTRO = "${HOST_BASE_DISTRO}"
+
+ROOTFS_FEATURES = "no-generate-initrd"
+ROOTFS_INSTALL_COMMAND:remove = "rootfs_restore_initrd_tooling"
+
+# additional packages for the SBOM chroot
+SBOM_IMAGE_INSTALL = "python3-debsbom"
+DEPENDS += "python3-debsbom"
+
+ROOTFSDIR = "${WORKDIR}/rootfs"
+ROOTFS_PACKAGES = "${SBOM_IMAGE_INSTALL}"
+
+do_sbomchroot_deploy[dirs] = "${SBOM_DIR}"
+do_sbomchroot_deploy() {
+ ln -Tfsr "${ROOTFSDIR}" "${SBOM_CHROOT}"
+}
+addtask do_sbomchroot_deploy before do_build after do_rootfs
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:58 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single BOM.

After creating the wic image, we collect the individual manifest files
(rootfs, initrd, imaging), deduplicate it and deploy it into the image
deploy dir (as .wic.manifest).

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index fb0b81a9..c75d481d 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -196,4 +196,9 @@ EOIMAGER
sudo chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
sudo chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
rm -rf ${IMAGE_ROOTFS}/../pseudo
+
+ cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
+ ${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
+ ${WORKDIR}/imager.manifest 2>/dev/null \
+ | sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
}
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:24:59 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
Currently the imager dependencies which end up in the image are not
tracked in any BOM (e.g. the manifest file). As these cannot be
automatically derived from the IMAGER_INSTALL packages, we add a new
variable IMAGER_BOM that takes a list of binary packages which are
looked-up using dpkg-query during imaging and added to a local manifest.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
doc/user_manual.md | 1 +
meta/classes/image-tools-extension.bbclass | 7 +++++++
meta/classes/image.bbclass | 6 ++++++
3 files changed, 14 insertions(+)

diff --git a/doc/user_manual.md b/doc/user_manual.md
index efe65a51..46c15b21 100644
--- a/doc/user_manual.md
+++ b/doc/user_manual.md
@@ -455,6 +455,7 @@ Some other variables include:
- `FILESEXTRAPATHS` - The default directories BitBake uses when it processes recipes are initially defined by the FILESPATH variable. You can extend FILESPATH variable by using FILESEXTRAPATHS.
- `FILESOVERRIDES` - A subset of OVERRIDES used by the build system for creating FILESPATH. The FILESOVERRIDES variable uses overrides to automatically extend the FILESPATH variable.
- `IMAGER_INSTALL` - The list of package dependencies for an imager like wic.
+ - `IMAGER_BOM` - The list of packages that should be added to the image BOM (e.g. the bootloader). These packages must also be available in the imager rootfs.

---

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 3f284b39..2027effb 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -18,6 +18,7 @@ SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"

imager_run() {
local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
+ local_bom="${@(d.getVar("BOM_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"

schroot_create_configs
insert_mounts
@@ -68,6 +69,12 @@ EOAPT

schroot -r -c ${session_id} "$@"

+ if [ -n "${local_bom}" ]; then
+ schroot -r -c ${session_id} -d / -- \
+ dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
+ ${WORKDIR}/imager.manifest
+ fi
+
schroot -e -c ${session_id}

remove_mounts
diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index 29324920..f3c3ed98 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass
@@ -216,6 +216,7 @@ python() {

imager_install = set()
imager_build_deps = set()
+ imager_bom = set()
conversion_install = set()
for bt in basetypes:
local_imager_install = set()
@@ -246,6 +247,8 @@ python() {
local_imager_install.add(dep)
for dep in (d.getVar('IMAGER_BUILD_DEPS:' + bt_clean) or '').split():
imager_build_deps.add(dep)
+ for dep in (d.getVar('IMAGER_BOM:' + bt_clean) or '').split():
+ imager_bom.add(dep)

# construct image command
image_cmd = localdata.getVar('IMAGE_CMD:' + bt_clean)
@@ -320,11 +323,14 @@ python() {
bb.build.addtask(task, 'do_image', after, d)

# set per type imager dependencies
+ d.setVar('BOM_image_%s' % bt_clean, d.getVar('IMAGER_BOM'))
+ d.appendVar('BOM_image_%s' % bt_clean, ' ' + ' '.join(sorted(imager_bom)))
d.setVar('INSTALL_image_%s' % bt_clean, d.getVar('IMAGER_INSTALL'))
d.appendVar('INSTALL_image_%s' % bt_clean, ' ' + ' '.join(sorted(local_imager_install | local_conversion_install)))
d.appendVarFlag(task, 'vardeps', ' INSTALL_image_%s' % bt_clean)

d.appendVar('IMAGER_INSTALL', ' ' + ' '.join(sorted(imager_install | conversion_install)))
+ d.appendVar('IMAGER_BOM', ' ' + ' '.join(sorted(imager_bom)))
d.appendVar('IMAGER_BUILD_DEPS', ' ' + ' '.join(sorted(imager_build_deps)))
}

--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:25:00 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
This uses the same interface as the .manifest file, but adds the
packagse to an SBOM.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image-tools-extension.bbclass | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 2027effb..95f003d0 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -73,6 +73,8 @@ EOAPT
schroot -r -c ${session_id} -d / -- \
dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
${WORKDIR}/imager.manifest
+
+ ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'generate_imager_sbom', '', d)}
fi

schroot -e -c ${session_id}
@@ -80,3 +82,23 @@ EOAPT
remove_mounts
schroot_delete_configs
}
+
+generate_imager_sbom() {
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ --bind $schroot_dir /mnt/rootfs \
+ --bind ${WORKDIR} /mnt/deploy-dir \
+ -- debsbom -vv generate ${SBOM_DEBSBOM_TYPE_ARGS} \
+ --from-pkglist -r /mnt/rootfs -o /mnt/deploy-dir/imager \
+ --distro-name '${SBOM_DISTRO_NAME}-Imager' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \
+ --timestamp $TIMESTAMP \
+ < ${WORKDIR}/imager.manifest
+}
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:25:00 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
To give an example how to add components to the imager BOM, we set the
corresponding variable for the qemuamd64 target.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta-isar/conf/machine/qemuamd64.conf | 1 +
1 file changed, 1 insertion(+)

diff --git a/meta-isar/conf/machine/qemuamd64.conf b/meta-isar/conf/machine/qemuamd64.conf
index 7d5987c6..8d0753a8 100644
--- a/meta-isar/conf/machine/qemuamd64.conf
+++ b/meta-isar/conf/machine/qemuamd64.conf
@@ -7,6 +7,7 @@ KERNEL_NAME ?= "amd64"

IMAGE_FSTYPES ?= "wic"
WKS_FILE ?= "sdimage-efi"
+IMAGER_BOM:wic += "${GRUB_BOOTLOADER_INSTALL}"
IMAGER_INSTALL:wic += "${GRUB_BOOTLOADER_INSTALL}"

QEMU_ARCH ?= "x86_64"
--
2.51.0

Felix Moessbauer

unread,
Nov 17, 2025, 8:25:01 AMNov 17
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single SBOM.

After creating the wic image, we collect the individual sbom files
(rootfs, initrd, imaging) and semantically merge it with the debsbom
tool. The merge SBOM is then deployed as .wic.(spdx|cdx).json next to
the wic image.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index c75d481d..fe31e4e6 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -201,4 +201,29 @@ EOIMAGER
${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
${WORKDIR}/imager.manifest 2>/dev/null \
| sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
+
+ for bomtype in ${SBOM_TYPES}; do
+ merge_wic_sbom $bomtype
+ done
+}
+
+merge_wic_sbom() {
+ BOMTYPE="$1"
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+
+ cat ${IMAGE_FULLNAME}.${bomtype}.json \
+ ${INITRD_DEPLOY_FILE}.${bomtype}.json \
+ ${WORKDIR}/imager.${bomtype}.json 2>/dev/null | \
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ -- debsbom -v merge -t $BOMTYPE \
+ --distro-name '${SBOM_DISTRO_NAME}-Image' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \
+ --timestamp $TIMESTAMP - -o - \
+ > ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.$bomtype.json
}
--
2.51.0

Quirin Gylstorff

unread,
Nov 19, 2025, 10:55:12 AMNov 19
to isar-...@googlegroups.com, Felix Moessbauer
This breaks the build of custom initrds on next
3f55e8574865de46bb795b60c3c3569567494aa7.

For cip-core I got:

ERROR: cip-core-initramfs-1.0-r0 do_rootfs_postprocess:
ExecutionError('/work/build/tmp/work/cip-core-trixie-amd64/cip-core-initramfs-qemu-amd64/1.0-r0/temp/run.generate_sbom.161385',
1, None, None)
ERROR: Logfile of failure stored in:
/work/build/tmp/work/cip-core-trixie-amd64/cip-core-initramfs-qemu-amd64/1.0-r0/temp/log.do_rootfs_postprocess.161385
Log data follows:
| DEBUG: Executing python function do_rootfs_postprocess
| DEBUG: Executing shell function rootfs_do_mounts
| DEBUG: Shell function rootfs_do_mounts finished
| DEBUG: Executing shell function rootfs_do_qemu
| DEBUG: Shell function rootfs_do_qemu finished
| DEBUG: Executing python function do_generate_sbom
| DEBUG: Executing shell function generate_sbom
| bwrap: Can't find source path
/work/build/tmp/deploy/images/qemu-amd64: No such file or directory
| WARNING: exit code 1 from a shell command.
| DEBUG: Python function do_generate_sbom finished
| DEBUG: Executing shell function rootfs_do_umounts
| DEBUG: Shell function rootfs_do_umounts finished
| DEBUG: Python function do_rootfs_postprocess finished
ERROR: Task
(/work/build/../../repo/recipes-initramfs/cip-core-initramfs/cip-core-initramfs.bb:do_rootfs_postprocess)
failed with exit code '1'

The integration is at
https://gitlab.com/cip-project/cip-core/isar-cip-core/-/tree/qg/add-debsbom?ref_type=heads

Quirin

Zhihang Wei

unread,
Nov 19, 2025, 11:58:59 AMNov 19
to Quirin Gylstorff, isar-...@googlegroups.com, Felix Moessbauer
Can you try master branch, or an earlier next at
49d4f8d81264b50e5d9c43a9d235c2a729164d28?
I suspect this is related with a mistake I made last Friday when
clearing the conflict to merge
"image: introduce IMAGE_INITRD, deprecate INITRD_IMAGE
<https://github.com/ilbers/isar/commit/c3c4e72cbfc4099308469802f5a912c29a990f72>"
to next.

Zhihang

Quirin Gylstorff

unread,
Nov 20, 2025, 6:07:57 AMNov 20
to Zhihang Wei, isar-...@googlegroups.com, Felix Moessbauer
The error also occurs on 49d4f8d8. See
https://gitlab.com/cip-project/cip-core/isar-cip-core/-/jobs/12155333533.

Quirin > I suspect this is related with a mistake I made last Friday when

MOESSBAUER, Felix

unread,
Nov 24, 2025, 4:16:47 AM (11 days ago) Nov 24
to quirin.g...@siemens.com, isar-...@googlegroups.com, w...@ilbers.de
This looks like a race condition. Rebuilding or building with sstate-
cache does not run into this issue.

Looking into it.

Felix
>

--
Siemens AG
Linux Expert Center
Friedrich-Ludwig-Bauer-Str. 3
85748 Garching, Germany

Felix Moessbauer

unread,
Nov 24, 2025, 6:46:59 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This patchset adds proper SBOM generation in the two standard formats
SPDX and CycloneDX during the rootfs generation process.

The generation is itself is handled by a SBOM generator `debsbom` [1]
which is developed as an open source project at Siemens. It is still
early in development, but it has enough features for what we require
in isar. The required dependencies which are not yet available as
Debian packages were minimally packaged directly in isar too.

This is a followup of the previous RFC [2]. Since then the series has
changed a lot. The SBOM generation was moved from a simple OE lib to
`debsbom`. This also meant the introduction of a separate chroot was
necessary. The SBOM generation process was also moved from the image
step to the rootfs step, along with a lot of minor changes and
improvements.

[1] https://github.com/siemens/debsbom
[2] https://groups.google.com/g/isar-users/c/8L-CF4BJY0I/m/p0N3o_zfAAAJ

Changes since v4:

- rebased onto next
- fix race condition on creation of ${DEPLOY_DIR_SBOM} (aka ${DEPLOY_DIR_IMAGE})
meta/classes/sbom.bbclass | 65 +++++++++++++++++++
meta/classes/sdk.bbclass | 10 +--
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
.../python3-beartype/files/rules | 8 +++
.../python3-beartype_0.19.0.bb | 29 +++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 +++
.../python3-cyclonedx-lib_9.1.0.bb | 48 ++++++++++++++
...icense-description-in-pyproject.toml.patch | 28 ++++++++
.../python3-debsbom/files/rules | 8 +++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++
.../python3-packageurl/files/rules | 8 +++
.../python3-packageurl_0.16.0.bb | 33 ++++++++++
.../python3-py-serializable/files/rules | 8 +++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++
.../python3-spdx-tools/files/rules | 25 +++++++
.../python3-spdx-tools_0.8.3.bb | 46 +++++++++++++
25 files changed, 523 insertions(+), 11 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

--
2.51.0

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:02 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This helper is rootfs (not sdk) specific and can be re-used to reliably
compute the distro of a rootfs (also transient ones like the ones used
by sbuild). As the SDK always is included into a rootfs, we just move it
there and make it reusable.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/rootfs.bbclass | 9 +++++++++
meta/classes/sdk.bbclass | 8 --------
2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/meta/classes/rootfs.bbclass b/meta/classes/rootfs.bbclass
index e1179e61..c045bfc0 100644
--- a/meta/classes/rootfs.bbclass
+++ b/meta/classes/rootfs.bbclass
@@ -43,6 +43,15 @@ ROOTFS_PACKAGE_SUFFIX ?= "${PN}-${DISTRO}-${DISTRO_ARCH}"
# path to deploy stubbed versions of initrd update scripts during do_rootfs_install
ROOTFS_STUBS_DIR = "/usr/local/isar-sbin"

+# helper to compute the rootfs distro also under cross building
+def get_rootfs_distro(d):
+ host_arch = d.getVar('HOST_ARCH')
+ distro_arch = d.getVar('DISTRO_ARCH')
+ if host_arch == distro_arch:
+ return d.getVar('DISTRO')
+ else:
+ return d.getVar('HOST_DISTRO')
+
# Useful environment variables:
export E = "${@ isar_export_proxies(d)}"
export DEBIAN_FRONTEND = "noninteractive"
diff --git a/meta/classes/sdk.bbclass b/meta/classes/sdk.bbclass
index 46436d97..00cae0da 100644
--- a/meta/classes/sdk.bbclass
+++ b/meta/classes/sdk.bbclass
@@ -43,14 +43,6 @@ SDK_PREINSTALL += " \
devscripts \
equivs"

-def get_rootfs_distro(d):
- host_arch = d.getVar('HOST_ARCH')
- distro_arch = d.getVar('DISTRO_ARCH')
- if host_arch == distro_arch:
- return d.getVar('DISTRO')
- else:
- return d.getVar('HOST_DISTRO')
-
# rootfs/image overrides for the SDK
ROOTFS_ARCH:class-sdk = "${HOST_ARCH}"
ROOTFS_DISTRO:class-sdk = "${@get_rootfs_distro(d)}"
--
2.51.0

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:05 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package python libraries for SBOM generation in isar. The packages are
unfortunately not (yet) packaged in Debian, thats why we need to do it
here. With these libraries it is now possible to easily create CDX and
SPDX SBOMs in different file formats.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
.../python3-beartype/files/rules | 8 ++++
.../python3-beartype_0.19.0.bb | 29 +++++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 ++++
.../python3-cyclonedx-lib_9.1.0.bb | 48 +++++++++++++++++++
.../python3-packageurl/files/rules | 8 ++++
.../python3-packageurl_0.16.0.bb | 33 +++++++++++++
.../python3-py-serializable/files/rules | 8 ++++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++++++
.../python3-spdx-tools/files/rules | 25 ++++++++++
.../python3-spdx-tools_0.8.3.bb | 46 ++++++++++++++++++
11 files changed, 252 insertions(+)
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

diff --git a/meta/recipes-support/python3-beartype/files/rules b/meta/recipes-support/python3-beartype/files/rules
new file mode 100644
index 00000000..0ca517a1
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = beartype
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
new file mode 100644
index 00000000..b8bc2708
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
@@ -0,0 +1,29 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/beartype-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), dh-python, python3-all, python3-setuptools, pybuild-plugin-pyproject, python3-hatchling"
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+# this is 01/01/1980, any earlier and zip in the wheel building process will not accept it
+DEBIAN_CHANGELOG_TIMESTAMP = "315532800"
+DESCRIPTION = "Unbearably fast near-real-time hybrid runtime-static type-checking in pure Python."
+
+SRC_URI = "\
+ https://github.com/beartype/beartype/archive/refs/tags/v0.19.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e7ad00eebf527d60f30e0b391209b561dabd2074b608c50e26c94c2d8250a6cd"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
new file mode 100644
index 00000000..cc736a36
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
@@ -0,0 +1 @@
+pyproject.toml
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/rules b/meta/recipes-support/python3-cyclonedx-lib/files/rules
new file mode 100644
index 00000000..fe72dd1a
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = cyclonedx-python-lib
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
new file mode 100644
index 00000000..738ed1b3
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
@@ -0,0 +1,48 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+DEPENDS:append:bookworm = " python3-packageurl python3-py-serializable"
+DEPENDS:append:noble = " python3-packageurl python3-py-serializable"
+
+S = "${WORKDIR}/cyclonedx_python_lib-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-poetry, \
+ python3-py-serializable, \
+ python3-packageurl, \
+ python3-sortedcontainers, \
+ python3-ddt, \
+ python3-defusedxml, \
+ python3-license-expression, \
+ python3-jsonschema, \
+ python3-lxml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/CycloneDX/cyclonedx-python-lib/releases/download/v9.1.0/cyclonedx_python_lib-9.1.0.tar.gz \
+ file://rules \
+ file://pybuild.testfiles \
+ "
+SRC_URI[sha256sum] = "86935f2c88a7b47a529b93c724dbd3e903bc573f6f8bd977628a7ca1b5dadea1"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ cp "${WORKDIR}"/pybuild.testfiles "${S}"/debian
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-packageurl/files/rules b/meta/recipes-support/python3-packageurl/files/rules
new file mode 100644
index 00000000..50e1b74c
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = packageurl-python
+export PYBUILD_SYSTEM = distutils
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
new file mode 100644
index 00000000..27209429
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
@@ -0,0 +1,33 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/packageurl_python-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "A purl aka. Package URL parser and builder"
+
+SRC_URI = "\
+ https://github.com/package-url/packageurl-python/releases/download/v0.16.0/packageurl_python-0.16.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "69e3bf8a3932fe9c2400f56aaeb9f86911ecee2f9398dbe1b58ec34340be365d"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-py-serializable/files/rules b/meta/recipes-support/python3-py-serializable/files/rules
new file mode 100644
index 00000000..0cf845dd
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = py-serializable
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
new file mode 100644
index 00000000..5bc48c0f
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
@@ -0,0 +1,38 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/py_serializable-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = " \
+ dh-sequence-python3, \
+ pybuild-plugin-pyproject, \
+ python3-all, \
+ python3-defusedxml, \
+ python3-lxml, \
+ python3-poetry-core, \
+ python3-setuptools, \
+ xmldiff, \
+"
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/madpah/serializable/releases/download/v2.0.0/py_serializable-2.0.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e9e6491dd7d29c31daf1050232b57f9657f9e8a43b867cca1ff204752cf420a5"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-spdx-tools/files/rules b/meta/recipes-support/python3-spdx-tools/files/rules
new file mode 100644
index 00000000..ac87528a
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/files/rules
@@ -0,0 +1,25 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = spdx-tools
+export PYBUILD_SYSTEM = distutils
+
+# skip tests that require hard-to-package dependencies and tests that rely on relative file paths
+# TODO: figure out a way to make these tests work
+export PYBUILD_TEST_ARGS=--ignore tests/spdx3/validation/json_ld/test_shacl_validation.py \
+ -k 'not test_examples \
+ and not test_parse_from_file \
+ and not test_annotation_parser \
+ and not test_snippet_parser \
+ and not test_creation_info_parser \
+ and not test_json_ld_writer \
+ and not test_extracted_licensing_info_parser \
+ and not test_parse_file \
+ and not test_package_parser \
+ and not test_relationship_parser \
+ and not test_graph_parsing_function \
+ and not test_license_expression_parser \
+ '
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
new file mode 100644
index 00000000..30d090a9
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
@@ -0,0 +1,46 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/tools-python-${PV}"
+
+DEPENDS:append:bookworm = " python3-beartype"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ python3-beartype, \
+ python3-semantic-version, \
+ python3-license-expression, \
+ python3-pytest <!nocheck>, \
+ python3-rdflib, \
+ python3-uritools, \
+ python3-ply, \
+ python3-click, \
+ python3-xmltodict, \
+ python3-yaml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+DEB_BUILD_PROFILES += "nocheck"
+DEB_BUILD_OPTIONS += "nocheck"
+
+DESCRIPTION = "SPDX parser and tools."
+
+SRC_URI = "\
+ https://github.com/spdx/tools-python/archive/refs/tags/v0.8.3.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "17cb0140adbaefb58819c9d5d56060dc6a70c673a854fa9bd882ecfa4e062a7f"

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:09 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package the python tool debsbom for SBOM generation for Debian based
distributions.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
...icense-description-in-pyproject.toml.patch | 28 ++++++++++++
.../python3-debsbom/files/rules | 8 ++++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++++++++
3 files changed, 81 insertions(+)
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb

diff --git a/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch b/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
new file mode 100644
new file mode 100644
index 00000000..a414114d
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = debsbom
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
new file mode 100644
index 00000000..410f358a
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
@@ -0,0 +1,45 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "python3-spdx-tools"
+DEPENDS:append:bookworm = " python3-packageurl python3-cyclonedx-lib"
+DEPENDS:append:noble = " python3-packageurl python3-cyclonedx-lib"
+
+S = "${WORKDIR}/git"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-packageurl, \
+ python3-cyclonedx-lib, \
+ python3-spdx-tools, \
+ python3-debian, \
+ python3-requests, \
+ python3-zstandard, \
+ "
+
+DEBIAN_DEPENDS = "python3-apt, \${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "debsbom generates SBOMs for Debian based distributions."
+
+SRC_URI = "git://github.com/siemens/debsbom.git;protocol=https;branch=main; \
+ file://rules \
+ file://0001-Use-old-license-description-in-pyproject.toml.patch \
+ "
+SRCREV = "a600f60966d08803eb17bfb81eb8828921497453"

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:14 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
From: Christoph Steiger <christop...@siemens.com>

Generate SBOMs for every rootfs that is created. These SBOMs are placed
in the image deploy directory.

For the generation a small chroot with debsbom installed is created and
from that the rootfs of the image is scanned.

The sbom generation is bound to the rootfs feature `generate-sbom`
which is activated per default now.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image.bbclass | 1 +
meta/classes/initramfs.bbclass | 3 +-
meta/classes/rootfs.bbclass | 14 +++-
meta/classes/sbom.bbclass | 65 +++++++++++++++++++
meta/classes/sdk.bbclass | 2 +-
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
6 files changed, 112 insertions(+), 3 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb

diff --git a/meta/classes/rootfs.bbclass b/meta/classes/rootfs.bbclass
index c045bfc0..b3ca9e16 100644
--- a/meta/classes/rootfs.bbclass
+++ b/meta/classes/rootfs.bbclass
-do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config"
+do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'sbom-chroot:do_sbomchroot_deploy', '', d)}"

SSTATETASKS += "do_rootfs_install"
SSTATECREATEFUNCS += "rootfs_install_sstate_prepare"
diff --git a/meta/classes/sbom.bbclass b/meta/classes/sbom.bbclass
new file mode 100644
index 00000000..3ed755d9
--- /dev/null
+++ b/meta/classes/sbom.bbclass
@@ -0,0 +1,65 @@
+# This software is a part of ISAR.
+# Copyright (C) 2025 Siemens
+#
+# SPDX-License-Identifier: MIT
+
+ -- debsbom -v generate ${SBOM_DEBSBOM_TYPE_ARGS} -r /mnt/rootfs -o /mnt/deploy-dir/'${PN}-${DISTRO}-${MACHINE}' \
+ --distro-name '${SBOM_DISTRO_NAME}' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber '${SBOM_DOCUMENT_UUID}' \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-'${SBOM_DOCUMENT_UUID}' \
+ --timestamp $TIMESTAMP
+}
+
+do_generate_sbom[dirs] += "${DEPLOY_DIR_SBOM}"
+python do_generate_sbom() {
+ sbom_doc_uuid(d)
+ bb.build.exec_func("generate_sbom", d)
+}
diff --git a/meta/classes/sdk.bbclass b/meta/classes/sdk.bbclass
index 00cae0da..d57269e5 100644
--- a/meta/classes/sdk.bbclass
+++ b/meta/classes/sdk.bbclass
@@ -47,7 +47,7 @@ SDK_PREINSTALL += " \
ROOTFS_ARCH:class-sdk = "${HOST_ARCH}"
ROOTFS_DISTRO:class-sdk = "${@get_rootfs_distro(d)}"
ROOTFS_PACKAGES:class-sdk = "sdk-files ${SDK_TOOLCHAIN} ${SDK_PREINSTALL} ${@isar_multiarch_packages('SDK_INSTALL', d)}"
-ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status"
+ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status generate-sbom"
ROOTFS_MANIFEST_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"
ROOTFS_DPKGSTATUS_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"

diff --git a/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
new file mode 100644
index 00000000..58200382
--- /dev/null
+++ b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
@@ -0,0 +1,30 @@
+# This software is a part of ISAR.
+#
+# Copyright (C) 2025 Siemens
+
+LICENSE = "gpl-2.0"
+LIC_FILES_CHKSUM = "file://${LAYERDIR_core}/licenses/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
+
+PV = "1.0"
+
+inherit rootfs
+
+ROOTFS_ARCH = "${HOST_ARCH}"
+ROOTFS_DISTRO = "${@get_rootfs_distro(d)}"
+ROOTFS_BASE_DISTRO = "${HOST_BASE_DISTRO}"
+
+ROOTFS_FEATURES = "no-generate-initrd"
+ROOTFS_INSTALL_COMMAND:remove = "rootfs_restore_initrd_tooling"
+
+# additional packages for the SBOM chroot
+SBOM_IMAGE_INSTALL = "python3-debsbom"
+DEPENDS += "python3-debsbom"
+
+ROOTFSDIR = "${WORKDIR}/rootfs"
+ROOTFS_PACKAGES = "${SBOM_IMAGE_INSTALL}"
+
+do_sbomchroot_deploy[dirs] = "${SBOM_DIR}"
+do_sbomchroot_deploy() {
+ ln -Tfsr "${ROOTFSDIR}" "${SBOM_CHROOT}"
+}
+addtask do_sbomchroot_deploy before do_build after do_rootfs
--
2.51.0

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:18 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
When generating an SBOM for Ubuntu, the vendor component of the PURL
needs to be ubuntu (instead of debian). We now set it accordingly.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:20 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
Currently the imager dependencies which end up in the image are not
tracked in any BOM (e.g. the manifest file). As these cannot be
automatically derived from the IMAGER_INSTALL packages, we add a new
variable IMAGER_BOM that takes a list of binary packages which are
looked-up using dpkg-query during imaging and added to a local manifest.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
doc/user_manual.md | 1 +
meta/classes/image-tools-extension.bbclass | 7 +++++++
meta/classes/image.bbclass | 6 ++++++
3 files changed, 14 insertions(+)

diff --git a/doc/user_manual.md b/doc/user_manual.md
index efe65a51..46c15b21 100644
--- a/doc/user_manual.md
+++ b/doc/user_manual.md
@@ -455,6 +455,7 @@ Some other variables include:
- `FILESEXTRAPATHS` - The default directories BitBake uses when it processes recipes are initially defined by the FILESPATH variable. You can extend FILESPATH variable by using FILESEXTRAPATHS.
- `FILESOVERRIDES` - A subset of OVERRIDES used by the build system for creating FILESPATH. The FILESOVERRIDES variable uses overrides to automatically extend the FILESPATH variable.
- `IMAGER_INSTALL` - The list of package dependencies for an imager like wic.
+ - `IMAGER_BOM` - The list of packages that should be added to the image BOM (e.g. the bootloader). These packages must also be available in the imager rootfs.

---

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 3f284b39..2027effb 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -18,6 +18,7 @@ SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"

imager_run() {
local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
+ local_bom="${@(d.getVar("BOM_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"

schroot_create_configs
insert_mounts
@@ -68,6 +69,12 @@ EOAPT

schroot -r -c ${session_id} "$@"

+ if [ -n "${local_bom}" ]; then
+ schroot -r -c ${session_id} -d / -- \
+ dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
+ ${WORKDIR}/imager.manifest
+ fi
+
schroot -e -c ${session_id}

remove_mounts
diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index 29324920..f3c3ed98 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:23 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single BOM.

After creating the wic image, we collect the individual manifest files
(rootfs, initrd, imaging), deduplicate it and deploy it into the image
deploy dir (as .wic.manifest).

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index fb0b81a9..c75d481d 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -196,4 +196,9 @@ EOIMAGER
sudo chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
sudo chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
rm -rf ${IMAGE_ROOTFS}/../pseudo
+
+ cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
+ ${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
+ ${WORKDIR}/imager.manifest 2>/dev/null \
+ | sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
}
--
2.51.0

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:28 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
To give an example how to add components to the imager BOM, we set the
corresponding variable for the qemuamd64 target.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:32 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This uses the same interface as the .manifest file, but adds the
packagse to an SBOM.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image-tools-extension.bbclass | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 2027effb..95f003d0 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -73,6 +73,8 @@ EOAPT
schroot -r -c ${session_id} -d / -- \
dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
${WORKDIR}/imager.manifest
+
+ ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'generate_imager_sbom', '', d)}
fi

schroot -e -c ${session_id}
@@ -80,3 +82,23 @@ EOAPT
remove_mounts
schroot_delete_configs
}
+
+generate_imager_sbom() {
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ --bind $schroot_dir /mnt/rootfs \
+ --bind ${WORKDIR} /mnt/deploy-dir \
+ -- debsbom -vv generate ${SBOM_DEBSBOM_TYPE_ARGS} \
+ --from-pkglist -r /mnt/rootfs -o /mnt/deploy-dir/imager \
+ --distro-name '${SBOM_DISTRO_NAME}-Imager' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \
+ --timestamp $TIMESTAMP \
+ < ${WORKDIR}/imager.manifest
+}
--
2.51.0

Felix Moessbauer

unread,
Nov 24, 2025, 6:47:34 AM (11 days ago) Nov 24
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single SBOM.

After creating the wic image, we collect the individual sbom files
(rootfs, initrd, imaging) and semantically merge it with the debsbom
tool. The merge SBOM is then deployed as .wic.(spdx|cdx).json next to
the wic image.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index c75d481d..fe31e4e6 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -201,4 +201,29 @@ EOIMAGER
${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
${WORKDIR}/imager.manifest 2>/dev/null \
| sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
+
+ for bomtype in ${SBOM_TYPES}; do
+ merge_wic_sbom $bomtype
+ done
+}
+
+merge_wic_sbom() {
+ BOMTYPE="$1"
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+
+ cat ${IMAGE_FULLNAME}.${bomtype}.json \
+ ${INITRD_DEPLOY_FILE}.${bomtype}.json \
+ ${WORKDIR}/imager.${bomtype}.json 2>/dev/null | \
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ -- debsbom -v merge -t $BOMTYPE \
+ --distro-name '${SBOM_DISTRO_NAME}-Image' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \

Zhihang Wei

unread,
Nov 27, 2025, 9:36:00 AM (8 days ago) Nov 27
to Felix Moessbauer, isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com
Hi,
A CI failure occured in full test suite:
citest.py:CustomizationsTest.test_single_customization

Log follows:
builder@13751127e9ed:/work/testsuite$ avocado run
citest.py:CustomizationsTest.test_single_customization
JOB ID     : 5a0c694b516485d29feccb614eb23dddb0b667af
JOB LOG    :
/tmp/tmpo3rzdofv/avocado/job-results/job-2025-11-27T10.47-5a0c694/job.log
 (1/1) citest.py:CustomizationsTest.test_single_customization: STARTED
ERROR: mc:qemuamd64-bullseye:isar-image-ci-1.0-r0 do_image_tar:
ExecutionError('/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/run.do_image_tar.8314',
1, None, None)
ERROR: Logfile of failure stored in:
/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/log.do_image_tar.8314
ERROR: Task
(mc:qemuamd64-bullseye:/work/meta-test/recipes-core/images/isar-image-ci.bb:do_image_tar)
failed with exit code '1'
ERROR: mc:qemuamd64-bullseye:isar-image-ci-1.0-r0 do_image_cpio:
ExecutionError('/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/run.do_image_cpio.8315',
1, None, None)
ERROR: Logfile of failure stored in:
/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/log.do_image_cpio.8315
ERROR: Task
(mc:qemuamd64-bullseye:/work/meta-test/recipes-core/images/isar-image-ci.bb:do_image_cpio)
failed with exit code '1'
ERROR: mc:qemuamd64-bullseye:isar-image-ci-1.0-r0 do_image_wic:
ExecutionError('/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/run.do_image_wic.8316',
1, None, None)
ERROR: Logfile of failure stored in:
/work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-qemuamd64/1.0-r0/temp/log.do_image_wic.8316

In all of these three failed tasks, error log includes:
dpkg-query: no packages found matching grub-efi-amd64-bin


To redo the test using avocado:
1. Have a clean clone of isar, checkout to branch next and apply your
patches:
$ git clone -b next https://github.com/ilbers/isar.git
$ cd isar
$ git am /path-to/0001-my-contribution-to-isar.patch
2. Run kas shell, setup CI prerequisites (avocado, qemu) and cleanup:
$ ./kas/kas-container shell kas/isar.yaml --command \
    "rm -rf /work/build/conf && /work/scripts/ci_setup.sh"
4.Run the failed test in fast:
$ cd /work/testsuite
$ avocado run citest.py:CustomizationsTest.test_single_customization$

Zhihang

MOESSBAUER, Felix

unread,
Nov 28, 2025, 9:32:11 AM (7 days ago) Nov 28
to isar-...@googlegroups.com, w...@ilbers.de, Steiger, Christoph, quirin.g...@siemens.com, cedric.h...@siemens.com, Kiszka, Jan
Hi, I was scratching my head how this could fail, but well ... it is a
badly written test:

In isar-image-ci [1], we do a ton conditional IMAGER_INSTALL:append and
IMAGER_INSTALL:remove, which are not aligned at all with the machine
configs.

Please add the following line to that section:

IMAGER_BOM:remove:qemuamd64:debian-bullseye ?=
"${GRUB_BOOTLOADER_INSTALL}"

This then should be added to p8. If you confirm that this works, I can
also send out a new version of the sbom series.

Anyways, I would be really happy if we could get rid of machine
manipulation parts in an image recipe. This is IMHO an anti-pattern.

[1]https://github.com/ilbers/isar/blob/master/meta-test/recipes-core/images/isar-image-ci.bb#L25

Felix
> --
> You received this message because you are subscribed to the Google Groups "isar-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/isar-users/1e26bd54-623a-48f0-a400-34a454ba4993%40ilbers.de.

cedric.h...@siemens.com

unread,
Nov 28, 2025, 9:35:50 AM (7 days ago) Nov 28
to isar-...@googlegroups.com, MOESSBAUER, Felix, w...@ilbers.de, Steiger, Christoph, quirin.g...@siemens.com, Kiszka, Jan
On Fri, 2025-11-28 at 14:32 +0000, Moessbauer, Felix (FT RPD CED OES-
> > image-ci-qemuamd64/1.0-r0/temp/run.do_image_cpio.8315',
> > 1, None, None)
> > ERROR: Logfile of failure stored in:
> > /work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-
> > qemuamd64/1.0-r0/temp/log.do_image_cpio.8315
> > ERROR: Task
> > (mc:qemuamd64-bullseye:/work/meta-test/recipes-core/images/isar-
> > image-ci.bb:do_image_cpio)
> > failed with exit code '1'
> > ERROR: mc:qemuamd64-bullseye:isar-image-ci-1.0-r0 do_image_wic:
> > ExecutionError('/work/build/tmp/work/debian-bullseye-amd64/isar-
> > image-ci-qemuamd64/1.0-r0/temp/run.do_image_wic.8316',
> > 1, None, None)
> > ERROR: Logfile of failure stored in:
> > /work/build/tmp/work/debian-bullseye-amd64/isar-image-ci-
Agreed. I would love to see our machine-specific (and image-specific)
variables prefixed with MACHINE_ (and respectively IMAGE_) to make the
scope very clear. This would also ease the job of linters and reviewers

>
> [1]
> https://git/
> hub.com%2Filbers%2Fisar%2Fblob%2Fmaster%2Fmeta-test%2Frecipes-
> core%2Fimages%2Fisar-image-
> ci.bb%23L25&data=05%7C02%7Ccedric.hombourger%40siemens.com%7Cbdd44d79
> b4084dc0182508de2e8ae81e%7C38ae3bcd95794fd4addab42e1495d55a%7C1%7C0%7
> C638999371287144635%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsI
> lYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7
> C0%7C%7C%7C&sdata=6KUi2SiAHEg5o4MCLaKH8g1UNqmZ5FdtqnO%2FeCXVLMs%3D&re
> served=0
Cedric Hombourger
Siemens AG
http://www.siemens.com/

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:36 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package python libraries for SBOM generation in isar. The packages are
unfortunately not (yet) packaged in Debian, thats why we need to do it
here. With these libraries it is now possible to easily create CDX and
SPDX SBOMs in different file formats.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
.../python3-beartype/files/rules | 8 ++++
.../python3-beartype_0.19.0.bb | 29 +++++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 ++++
.../python3-cyclonedx-lib_9.1.0.bb | 48 +++++++++++++++++++
.../python3-packageurl/files/rules | 8 ++++
.../python3-packageurl_0.16.0.bb | 33 +++++++++++++
.../python3-py-serializable/files/rules | 8 ++++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++++++
.../python3-spdx-tools/files/rules | 25 ++++++++++
.../python3-spdx-tools_0.8.3.bb | 46 ++++++++++++++++++
11 files changed, 252 insertions(+)
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

diff --git a/meta/recipes-support/python3-beartype/files/rules b/meta/recipes-support/python3-beartype/files/rules
new file mode 100644
index 00000000..0ca517a1
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = beartype
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
new file mode 100644
index 00000000..b8bc2708
--- /dev/null
+++ b/meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
@@ -0,0 +1,29 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/beartype-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), dh-python, python3-all, python3-setuptools, pybuild-plugin-pyproject, python3-hatchling"
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+# this is 01/01/1980, any earlier and zip in the wheel building process will not accept it
+DEBIAN_CHANGELOG_TIMESTAMP = "315532800"
+DESCRIPTION = "Unbearably fast near-real-time hybrid runtime-static type-checking in pure Python."
+
+SRC_URI = "\
+ https://github.com/beartype/beartype/archive/refs/tags/v0.19.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e7ad00eebf527d60f30e0b391209b561dabd2074b608c50e26c94c2d8250a6cd"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
new file mode 100644
index 00000000..cc736a36
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
@@ -0,0 +1 @@
+pyproject.toml
diff --git a/meta/recipes-support/python3-cyclonedx-lib/files/rules b/meta/recipes-support/python3-cyclonedx-lib/files/rules
new file mode 100644
index 00000000..fe72dd1a
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = cyclonedx-python-lib
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
new file mode 100644
index 00000000..738ed1b3
--- /dev/null
+++ b/meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
@@ -0,0 +1,48 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+DEPENDS:append:bookworm = " python3-packageurl python3-py-serializable"
+DEPENDS:append:noble = " python3-packageurl python3-py-serializable"
+
+S = "${WORKDIR}/cyclonedx_python_lib-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-poetry, \
+ python3-py-serializable, \
+ python3-packageurl, \
+ python3-sortedcontainers, \
+ python3-ddt, \
+ python3-defusedxml, \
+ python3-license-expression, \
+ python3-jsonschema, \
+ python3-lxml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/CycloneDX/cyclonedx-python-lib/releases/download/v9.1.0/cyclonedx_python_lib-9.1.0.tar.gz \
+ file://rules \
+ file://pybuild.testfiles \
+ "
+SRC_URI[sha256sum] = "86935f2c88a7b47a529b93c724dbd3e903bc573f6f8bd977628a7ca1b5dadea1"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ cp "${WORKDIR}"/pybuild.testfiles "${S}"/debian
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-packageurl/files/rules b/meta/recipes-support/python3-packageurl/files/rules
new file mode 100644
index 00000000..50e1b74c
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = packageurl-python
+export PYBUILD_SYSTEM = distutils
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
new file mode 100644
index 00000000..27209429
--- /dev/null
+++ b/meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
@@ -0,0 +1,33 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/packageurl_python-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "debhelper (>= 11~), \
+ dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "A purl aka. Package URL parser and builder"
+
+SRC_URI = "\
+ https://github.com/package-url/packageurl-python/releases/download/v0.16.0/packageurl_python-0.16.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "69e3bf8a3932fe9c2400f56aaeb9f86911ecee2f9398dbe1b58ec34340be365d"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-py-serializable/files/rules b/meta/recipes-support/python3-py-serializable/files/rules
new file mode 100644
index 00000000..0cf845dd
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = py-serializable
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
new file mode 100644
index 00000000..5bc48c0f
--- /dev/null
+++ b/meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
@@ -0,0 +1,38 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/py_serializable-${PV}"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = " \
+ dh-sequence-python3, \
+ pybuild-plugin-pyproject, \
+ python3-all, \
+ python3-defusedxml, \
+ python3-lxml, \
+ python3-poetry-core, \
+ python3-setuptools, \
+ xmldiff, \
+"
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "Library for serializing and deserializing Python Objects to and from JSON and XML."
+
+SRC_URI = "\
+ https://github.com/madpah/serializable/releases/download/v2.0.0/py_serializable-2.0.0.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "e9e6491dd7d29c31daf1050232b57f9657f9e8a43b867cca1ff204752cf420a5"
+
+do_prepare_build[cleandirs] += "${S}/debian"
+do_prepare_build() {
+ deb_debianize
+}
diff --git a/meta/recipes-support/python3-spdx-tools/files/rules b/meta/recipes-support/python3-spdx-tools/files/rules
new file mode 100644
index 00000000..ac87528a
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/files/rules
@@ -0,0 +1,25 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = spdx-tools
+export PYBUILD_SYSTEM = distutils
+
+# skip tests that require hard-to-package dependencies and tests that rely on relative file paths
+# TODO: figure out a way to make these tests work
+export PYBUILD_TEST_ARGS=--ignore tests/spdx3/validation/json_ld/test_shacl_validation.py \
+ -k 'not test_examples \
+ and not test_parse_from_file \
+ and not test_annotation_parser \
+ and not test_snippet_parser \
+ and not test_creation_info_parser \
+ and not test_json_ld_writer \
+ and not test_extracted_licensing_info_parser \
+ and not test_parse_file \
+ and not test_package_parser \
+ and not test_relationship_parser \
+ and not test_graph_parsing_function \
+ and not test_license_expression_parser \
+ '
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
new file mode 100644
index 00000000..30d090a9
--- /dev/null
+++ b/meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb
@@ -0,0 +1,46 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/tools-python-${PV}"
+
+DEPENDS:append:bookworm = " python3-beartype"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ python3-beartype, \
+ python3-semantic-version, \
+ python3-license-expression, \
+ python3-pytest <!nocheck>, \
+ python3-rdflib, \
+ python3-uritools, \
+ python3-ply, \
+ python3-click, \
+ python3-xmltodict, \
+ python3-yaml, \
+ "
+
+DEBIAN_DEPENDS = "\${python3:Depends}, \${misc:Depends}"
+DEB_BUILD_PROFILES += "nocheck"
+DEB_BUILD_OPTIONS += "nocheck"
+
+DESCRIPTION = "SPDX parser and tools."
+
+SRC_URI = "\
+ https://github.com/spdx/tools-python/archive/refs/tags/v0.8.3.tar.gz \
+ file://rules \
+ "
+SRC_URI[sha256sum] = "17cb0140adbaefb58819c9d5d56060dc6a70c673a854fa9bd882ecfa4e062a7f"

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:36 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This patchset adds proper SBOM generation in the two standard formats
SPDX and CycloneDX during the rootfs generation process.

The generation is itself is handled by a SBOM generator `debsbom` [1]
which is developed as an open source project at Siemens. It is still
early in development, but it has enough features for what we require
in isar. The required dependencies which are not yet available as
Debian packages were minimally packaged directly in isar too.

This is a followup of the previous RFC [2]. Since then the series has
changed a lot. The SBOM generation was moved from a simple OE lib to
`debsbom`. This also meant the introduction of a separate chroot was
necessary. The SBOM generation process was also moved from the image
step to the rootfs step, along with a lot of minor changes and
improvements.

[1] https://github.com/siemens/debsbom
[2] https://groups.google.com/g/isar-users/c/8L-CF4BJY0I/m/p0N3o_zfAAAJ

Changes since v5:

- fix isar-image-ci on qemuamd64-bullseye (set IMAGER_BOM according to
machine changes made in image file)
.../recipes-core/images/isar-image-ci.bb | 1 +
meta/classes/image-tools-extension.bbclass | 29 +++++++++
meta/classes/image.bbclass | 7 ++
meta/classes/imagetypes_wic.bbclass | 30 +++++++++
meta/classes/initramfs.bbclass | 3 +-
meta/classes/rootfs.bbclass | 23 ++++++-
meta/classes/sbom.bbclass | 65 +++++++++++++++++++
meta/classes/sdk.bbclass | 10 +--
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
.../python3-beartype/files/rules | 8 +++
.../python3-beartype_0.19.0.bb | 29 +++++++++
.../files/pybuild.testfiles | 1 +
.../python3-cyclonedx-lib/files/rules | 8 +++
.../python3-cyclonedx-lib_9.1.0.bb | 48 ++++++++++++++
...icense-description-in-pyproject.toml.patch | 28 ++++++++
.../python3-debsbom/files/rules | 8 +++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++
.../python3-packageurl/files/rules | 8 +++
.../python3-packageurl_0.16.0.bb | 33 ++++++++++
.../python3-py-serializable/files/rules | 8 +++
.../python3-py-serializable_2.0.0.bb | 38 +++++++++++
.../python3-spdx-tools/files/rules | 25 +++++++
.../python3-spdx-tools_0.8.3.bb | 46 +++++++++++++
26 files changed, 524 insertions(+), 11 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
create mode 100644 meta/recipes-support/python3-beartype/files/rules
create mode 100644 meta/recipes-support/python3-beartype/python3-beartype_0.19.0.bb
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/pybuild.testfiles
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/files/rules
create mode 100644 meta/recipes-support/python3-cyclonedx-lib/python3-cyclonedx-lib_9.1.0.bb
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
create mode 100644 meta/recipes-support/python3-packageurl/files/rules
create mode 100644 meta/recipes-support/python3-packageurl/python3-packageurl_0.16.0.bb
create mode 100644 meta/recipes-support/python3-py-serializable/files/rules
create mode 100644 meta/recipes-support/python3-py-serializable/python3-py-serializable_2.0.0.bb
create mode 100644 meta/recipes-support/python3-spdx-tools/files/rules
create mode 100644 meta/recipes-support/python3-spdx-tools/python3-spdx-tools_0.8.3.bb

--
2.51.0

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:36 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This helper is rootfs (not sdk) specific and can be re-used to reliably
compute the distro of a rootfs (also transient ones like the ones used
by sbuild). As the SDK always is included into a rootfs, we just move it
there and make it reusable.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/rootfs.bbclass | 9 +++++++++
meta/classes/sdk.bbclass | 8 --------
2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/meta/classes/rootfs.bbclass b/meta/classes/rootfs.bbclass
index 70d4bfb8..3027c4dd 100644
--- a/meta/classes/rootfs.bbclass
+++ b/meta/classes/rootfs.bbclass
@@ -44,6 +44,15 @@ ROOTFS_PACKAGE_SUFFIX ?= "${PN}-${DISTRO}-${DISTRO_ARCH}"
# path to deploy stubbed versions of initrd update scripts during do_rootfs_install
ROOTFS_STUBS_DIR = "/usr/local/isar-sbin"

+# helper to compute the rootfs distro also under cross building
+def get_rootfs_distro(d):
+ host_arch = d.getVar('HOST_ARCH')
+ distro_arch = d.getVar('DISTRO_ARCH')
+ if host_arch == distro_arch:
+ return d.getVar('DISTRO')
+ else:
+ return d.getVar('HOST_DISTRO')
+
# Useful environment variables:
export E = "${@ isar_export_proxies(d)}"
export DEBIAN_FRONTEND = "noninteractive"
diff --git a/meta/classes/sdk.bbclass b/meta/classes/sdk.bbclass
index 5933b52a..81d3c65e 100644
--- a/meta/classes/sdk.bbclass
+++ b/meta/classes/sdk.bbclass
@@ -43,14 +43,6 @@ SDK_PREINSTALL += " \
devscripts \
equivs"

-def get_rootfs_distro(d):
- host_arch = d.getVar('HOST_ARCH')
- distro_arch = d.getVar('DISTRO_ARCH')
- if host_arch == distro_arch:
- return d.getVar('DISTRO')
- else:
- return d.getVar('HOST_DISTRO')
-
# rootfs/image overrides for the SDK
ROOTFS_ARCH:class-sdk = "${HOST_ARCH}"
ROOTFS_DISTRO:class-sdk = "${@get_rootfs_distro(d)}"
--
2.51.0

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:38 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com
From: Christoph Steiger <christop...@siemens.com>

Package the python tool debsbom for SBOM generation for Debian based
distributions.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
---
...icense-description-in-pyproject.toml.patch | 28 ++++++++++++
.../python3-debsbom/files/rules | 8 ++++
.../python3-debsbom/python3-debsbom_0.4.0.bb | 45 +++++++++++++++++++
3 files changed, 81 insertions(+)
create mode 100644 meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
create mode 100644 meta/recipes-support/python3-debsbom/files/rules
create mode 100644 meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb

diff --git a/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch b/meta/recipes-support/python3-debsbom/files/0001-Use-old-license-description-in-pyproject.toml.patch
new file mode 100644
new file mode 100644
index 00000000..a414114d
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/files/rules
@@ -0,0 +1,8 @@
+#!/usr/bin/make -f
+
+#export DH_VERBOSE = 1
+export PYBUILD_NAME = debsbom
+export PYBUILD_SYSTEM = pyproject
+
+%:
+ dh $@ --with python3 --buildsystem=pybuild
diff --git a/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
new file mode 100644
index 00000000..410f358a
--- /dev/null
+++ b/meta/recipes-support/python3-debsbom/python3-debsbom_0.4.0.bb
@@ -0,0 +1,45 @@
+# This software is a part of ISAR.
+# Copyright (c) Siemens, 2025
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "python3-spdx-tools"
+DEPENDS:append:bookworm = " python3-packageurl python3-cyclonedx-lib"
+DEPENDS:append:noble = " python3-packageurl python3-cyclonedx-lib"
+
+S = "${WORKDIR}/git"
+
+MAINTAINER = "Christoph Steiger <christop...@siemens.com>"
+DPKG_ARCH = "all"
+DEBIAN_BUILD_DEPENDS = "dh-python, \
+ python3-all, \
+ python3-setuptools, \
+ pybuild-plugin-pyproject, \
+ python3-packageurl, \
+ python3-cyclonedx-lib, \
+ python3-spdx-tools, \
+ python3-debian, \
+ python3-requests, \
+ python3-zstandard, \
+ "
+
+DEBIAN_DEPENDS = "python3-apt, \${python3:Depends}, \${misc:Depends}"
+
+DESCRIPTION = "debsbom generates SBOMs for Debian based distributions."
+
+SRC_URI = "git://github.com/siemens/debsbom.git;protocol=https;branch=main; \
+ file://rules \
+ file://0001-Use-old-license-description-in-pyproject.toml.patch \
+ "
+SRCREV = "a600f60966d08803eb17bfb81eb8828921497453"

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:39 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
From: Christoph Steiger <christop...@siemens.com>

Generate SBOMs for every rootfs that is created. These SBOMs are placed
in the image deploy directory.

For the generation a small chroot with debsbom installed is created and
from that the rootfs of the image is scanned.

The sbom generation is bound to the rootfs feature `generate-sbom`
which is activated per default now.

Signed-off-by: Christoph Steiger <christop...@siemens.com>
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image.bbclass | 1 +
meta/classes/initramfs.bbclass | 3 +-
meta/classes/rootfs.bbclass | 14 +++-
meta/classes/sbom.bbclass | 65 +++++++++++++++++++
meta/classes/sdk.bbclass | 2 +-
.../sbom-chroot/sbom-chroot.bb | 30 +++++++++
6 files changed, 112 insertions(+), 3 deletions(-)
create mode 100644 meta/classes/sbom.bbclass
create mode 100644 meta/recipes-devtools/sbom-chroot/sbom-chroot.bb

diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index b030024f..da7910b2 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass
@@ -99,6 +99,7 @@ ROOTFS_FEATURES += "\
clean-log-files \
clean-debconf-cache \
populate-systemd-preset \
+ generate-sbom \
"
ROOTFS_PACKAGES += "${IMAGE_PREINSTALL} ${@isar_multiarch_packages('IMAGE_INSTALL', d)}"
ROOTFS_VARDEPS += "IMAGE_INSTALL"
diff --git a/meta/classes/initramfs.bbclass b/meta/classes/initramfs.bbclass
index 862bd873..570780e1 100644
--- a/meta/classes/initramfs.bbclass
+++ b/meta/classes/initramfs.bbclass
@@ -22,11 +22,12 @@ INITRAMFS_FULLNAME = "${PN}-${DISTRO}-${MACHINE}"
# Bill-of-material
ROOTFS_MANIFEST_DEPLOY_DIR = "${DEPLOY_DIR_IMAGE}"
ROOTFS_PACKAGE_SUFFIX = "${INITRAMFS_FULLNAME}"
+SBOM_DISTRO_NAME:append = "-initramfs"

DEPENDS += "${INITRAMFS_INSTALL}"

ROOTFSDIR = "${INITRAMFS_ROOTFS}"
-ROOTFS_FEATURES = "generate-manifest"
+ROOTFS_FEATURES = "generate-manifest generate-sbom"
ROOTFS_PACKAGES = "${INITRAMFS_GENERATOR_PKG} ${INITRAMFS_PREINSTALL} ${INITRAMFS_INSTALL}"

# validate if have incompatible packages in the installation list
diff --git a/meta/classes/rootfs.bbclass b/meta/classes/rootfs.bbclass
index 3027c4dd..2c45a9c7 100644
--- a/meta/classes/rootfs.bbclass
+++ b/meta/classes/rootfs.bbclass
@@ -3,6 +3,8 @@

inherit deb-dl-dir

+inherit sbom
+
ROOTFS_ARCH ?= "${DISTRO_ARCH}"
ROOTFS_DISTRO ?= "${DISTRO}"

@@ -29,11 +31,18 @@ INITRD_IMAGE ?= ""
# available features are:
# 'clean-package-cache' - delete package cache from rootfs
# 'generate-manifest' - generate a package manifest of the rootfs into ${ROOTFS_MANIFEST_DEPLOY_DIR}
+# 'generate-sbom' - generate a SBOM of the rootfs into ${DEPLOY_DIR_SBOM}
# 'export-dpkg-status' - exports /var/lib/dpkg/status file to ${ROOTFS_DPKGSTATUS_DEPLOY_DIR}
# 'clean-log-files' - delete log files that are not owned by packages
# 'populate-systemd-preset' - enable systemd units according to systemd presets
+
# 'generate-initrd' - generate debian default initrd
ROOTFS_FEATURES += "${@ 'generate-initrd' if d.getVar('INITRD_IMAGE') == '' else ''}"
+# only supported from bookworm / jammy on
+ROOTFS_FEATURES:remove:buster = "generate-sbom"
+ROOTFS_FEATURES:remove:bullseye = "generate-sbom"
+ROOTFS_FEATURES:remove:jammy = "generate-sbom"
+ROOTFS_FEATURES:remove:focal = "generate-sbom"

ROOTFS_APT_ARGS="install --yes -o Debug::pkgProblemResolver=yes"

@@ -480,6 +489,9 @@ cache_dbg_pkgs() {
fi
}

+# The sbom generator needs the apt-cache, hence run before cleaning it
+ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'do_generate_sbom', '', d)}"
+
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-package-cache', 'rootfs_postprocess_clean_package_cache', '', d)}"
rootfs_postprocess_clean_package_cache() {
sudo -E chroot '${ROOTFSDIR}' \
@@ -649,7 +661,7 @@ python do_rootfs() {
}
addtask rootfs before do_build

-do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config"
+do_rootfs_postprocess[depends] = "base-apt:do_cache isar-apt:do_cache_config ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'sbom-chroot:do_sbomchroot_deploy', '', d)}"

SSTATETASKS += "do_rootfs_install"
SSTATECREATEFUNCS += "rootfs_install_sstate_prepare"
diff --git a/meta/classes/sbom.bbclass b/meta/classes/sbom.bbclass
new file mode 100644
index 00000000..3ed755d9
--- /dev/null
+++ b/meta/classes/sbom.bbclass
@@ -0,0 +1,65 @@
+# This software is a part of ISAR.
+# Copyright (C) 2025 Siemens
+#
+# SPDX-License-Identifier: MIT
+
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ --bind ${ROOTFSDIR} /mnt/rootfs \
+ --bind ${DEPLOY_DIR_SBOM} /mnt/deploy-dir \
+ -- debsbom -v generate ${SBOM_DEBSBOM_TYPE_ARGS} -r /mnt/rootfs -o /mnt/deploy-dir/'${PN}-${DISTRO}-${MACHINE}' \
+ --distro-name '${SBOM_DISTRO_NAME}' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber '${SBOM_DOCUMENT_UUID}' \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-'${SBOM_DOCUMENT_UUID}' \
+ --timestamp $TIMESTAMP
+}
+
+do_generate_sbom[dirs] += "${DEPLOY_DIR_SBOM}"
+python do_generate_sbom() {
+ sbom_doc_uuid(d)
+ bb.build.exec_func("generate_sbom", d)
+}
diff --git a/meta/classes/sdk.bbclass b/meta/classes/sdk.bbclass
index 81d3c65e..17b56bcf 100644
--- a/meta/classes/sdk.bbclass
+++ b/meta/classes/sdk.bbclass
@@ -48,7 +48,7 @@ ROOTFS_ARCH:class-sdk = "${HOST_ARCH}"
ROOTFS_DISTRO:class-sdk = "${@get_rootfs_distro(d)}"
ROOTFS_PACKAGES:class-sdk = "sdk-files ${SDK_TOOLCHAIN} ${SDK_PREINSTALL} ${@isar_multiarch_packages('SDK_INSTALL', d)}"
ROOTFS_VARDEPS:class-sdk = "SDK_INSTALL SDK_INCLUDE_ISAR_APT"
-ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status"
+ROOTFS_FEATURES:append:class-sdk = " clean-package-cache generate-manifest export-dpkg-status generate-sbom"
ROOTFS_MANIFEST_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"
ROOTFS_DPKGSTATUS_DEPLOY_DIR:class-sdk = "${DEPLOY_DIR_SDKCHROOT}"

diff --git a/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
new file mode 100644
index 00000000..58200382
--- /dev/null
+++ b/meta/recipes-devtools/sbom-chroot/sbom-chroot.bb
@@ -0,0 +1,30 @@
+# This software is a part of ISAR.
+#

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:40 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single BOM.

After creating the wic image, we collect the individual manifest files
(rootfs, initrd, imaging), deduplicate it and deploy it into the image
deploy dir (as .wic.manifest).

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index fb0b81a9..c75d481d 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -196,4 +196,9 @@ EOIMAGER
sudo chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
sudo chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
rm -rf ${IMAGE_ROOTFS}/../pseudo
+
+ cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
+ ${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
+ ${WORKDIR}/imager.manifest 2>/dev/null \
+ | sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
}
--
2.51.0

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:40 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
Currently the imager dependencies which end up in the image are not
tracked in any BOM (e.g. the manifest file). As these cannot be
automatically derived from the IMAGER_INSTALL packages, we add a new
variable IMAGER_BOM that takes a list of binary packages which are
looked-up using dpkg-query during imaging and added to a local manifest.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
doc/user_manual.md | 1 +
meta/classes/image-tools-extension.bbclass | 7 +++++++
meta/classes/image.bbclass | 6 ++++++
3 files changed, 14 insertions(+)

diff --git a/doc/user_manual.md b/doc/user_manual.md
index 4df122a8..6d08ef71 100644
--- a/doc/user_manual.md
+++ b/doc/user_manual.md
@@ -449,6 +449,7 @@ Some other variables include:
- `FILESEXTRAPATHS` - The default directories BitBake uses when it processes recipes are initially defined by the FILESPATH variable. You can extend FILESPATH variable by using FILESEXTRAPATHS.
- `FILESOVERRIDES` - A subset of OVERRIDES used by the build system for creating FILESPATH. The FILESOVERRIDES variable uses overrides to automatically extend the FILESPATH variable.
- `IMAGER_INSTALL` - The list of package dependencies for an imager like wic.
+ - `IMAGER_BOM` - The list of packages that should be added to the image BOM (e.g. the bootloader). These packages must also be available in the imager rootfs.

---

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 3f284b39..2027effb 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -18,6 +18,7 @@ SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"

imager_run() {
local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
+ local_bom="${@(d.getVar("BOM_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"

schroot_create_configs
insert_mounts
@@ -68,6 +69,12 @@ EOAPT

schroot -r -c ${session_id} "$@"

+ if [ -n "${local_bom}" ]; then
+ schroot -r -c ${session_id} -d / -- \
+ dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
+ ${WORKDIR}/imager.manifest
+ fi
+
schroot -e -c ${session_id}

remove_mounts
diff --git a/meta/classes/image.bbclass b/meta/classes/image.bbclass
index da7910b2..5a42c230 100644
--- a/meta/classes/image.bbclass
+++ b/meta/classes/image.bbclass
@@ -217,6 +217,7 @@ python() {

imager_install = set()
imager_build_deps = set()
+ imager_bom = set()
conversion_install = set()
for bt in basetypes:
local_imager_install = set()
@@ -247,6 +248,8 @@ python() {
local_imager_install.add(dep)
for dep in (d.getVar('IMAGER_BUILD_DEPS:' + bt_clean) or '').split():
imager_build_deps.add(dep)
+ for dep in (d.getVar('IMAGER_BOM:' + bt_clean) or '').split():
+ imager_bom.add(dep)

# construct image command
image_cmd = localdata.getVar('IMAGE_CMD:' + bt_clean)
@@ -321,11 +324,14 @@ python() {

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:40 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
When generating an SBOM for Ubuntu, the vendor component of the PURL
needs to be ubuntu (instead of debian). We now set it accordingly.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta-isar/conf/distro/ubuntu-common.inc | 2 ++
1 file changed, 2 insertions(+)

diff --git a/meta-isar/conf/distro/ubuntu-common.inc b/meta-isar/conf/distro/ubuntu-common.inc
index dbfeed4a..8b9964c8 100644
--- a/meta-isar/conf/distro/ubuntu-common.inc
+++ b/meta-isar/conf/distro/ubuntu-common.inc
@@ -42,3 +42,5 @@ SYSTEMD_BOOTLOADER_INSTALL:jammy = "systemd:${DISTRO_ARCH}"

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:41 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
To give an example how to add components to the imager BOM, we set the
corresponding variable for the qemuamd64 target. As the isar-image-ci
changes the bootloader of the qemuamd64 machine, we also need to
reflect that change in the IMAGER_BOM entry.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta-isar/conf/machine/qemuamd64.conf | 1 +
meta-test/recipes-core/images/isar-image-ci.bb | 1 +
2 files changed, 2 insertions(+)

diff --git a/meta-isar/conf/machine/qemuamd64.conf b/meta-isar/conf/machine/qemuamd64.conf
index 7d5987c6..8d0753a8 100644
--- a/meta-isar/conf/machine/qemuamd64.conf
+++ b/meta-isar/conf/machine/qemuamd64.conf
@@ -7,6 +7,7 @@ KERNEL_NAME ?= "amd64"

IMAGE_FSTYPES ?= "wic"
WKS_FILE ?= "sdimage-efi"
+IMAGER_BOM:wic += "${GRUB_BOOTLOADER_INSTALL}"
IMAGER_INSTALL:wic += "${GRUB_BOOTLOADER_INSTALL}"

QEMU_ARCH ?= "x86_64"
diff --git a/meta-test/recipes-core/images/isar-image-ci.bb b/meta-test/recipes-core/images/isar-image-ci.bb
index 9133da74..961a3057 100644
--- a/meta-test/recipes-core/images/isar-image-ci.bb
+++ b/meta-test/recipes-core/images/isar-image-ci.bb
@@ -24,6 +24,7 @@ WKS_FILE:qemuamd64:debian-bullseye ?= "sdimage-efi-btrfs"
IMAGE_INSTALL:append:qemuamd64:debian-bullseye = " expand-on-first-boot"
IMAGER_INSTALL:remove:qemuamd64:debian-bullseye ?= "${GRUB_BOOTLOADER_INSTALL}"
IMAGER_INSTALL:append:qemuamd64:debian-bullseye ?= " ${SYSTEMD_BOOTLOADER_INSTALL} btrfs-progs"
+IMAGER_BOM:wic = "${SYSTEMD_BOOTLOADER_INSTALL}"
IMAGE_PREINSTALL:append:qemuamd64:debian-bullseye ?= " btrfs-progs"
# Explicitly remove from wic since it is set in qemuamd64.conf:
IMAGER_INSTALL:wic:remove:qemuamd64:debian-bullseye ?= "${GRUB_BOOTLOADER_INSTALL}"
--
2.51.0

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:42 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
This uses the same interface as the .manifest file, but adds the
packagse to an SBOM.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/image-tools-extension.bbclass | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/meta/classes/image-tools-extension.bbclass b/meta/classes/image-tools-extension.bbclass
index 2027effb..95f003d0 100644
--- a/meta/classes/image-tools-extension.bbclass
+++ b/meta/classes/image-tools-extension.bbclass
@@ -73,6 +73,8 @@ EOAPT
schroot -r -c ${session_id} -d / -- \
dpkg-query -W -f='${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' ${local_bom} > \
${WORKDIR}/imager.manifest
+
+ ${@bb.utils.contains('ROOTFS_FEATURES', 'generate-sbom', 'generate_imager_sbom', '', d)}
fi

schroot -e -c ${session_id}
@@ -80,3 +82,23 @@ EOAPT
remove_mounts
schroot_delete_configs
}
+
+generate_imager_sbom() {
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ --bind $schroot_dir /mnt/rootfs \
+ --bind ${WORKDIR} /mnt/deploy-dir \
+ -- debsbom -vv generate ${SBOM_DEBSBOM_TYPE_ARGS} \
+ --from-pkglist -r /mnt/rootfs -o /mnt/deploy-dir/imager \
+ --distro-name '${SBOM_DISTRO_NAME}-Imager' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --distro-arch '${DISTRO_ARCH}' \
+ --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \
+ --timestamp $TIMESTAMP \
+ < ${WORKDIR}/imager.manifest
+}
--
2.51.0

Felix Moessbauer

unread,
Dec 1, 2025, 3:58:42 AM (4 days ago) Dec 1
to isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, jan.k...@siemens.com, quirin.g...@siemens.com, Felix Moessbauer
A wic image consists of potentially many different components. All these
should be covered by a single SBOM.

After creating the wic image, we collect the individual sbom files
(rootfs, initrd, imaging) and semantically merge it with the debsbom
tool. The merge SBOM is then deployed as .wic.(spdx|cdx).json next to
the wic image.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
meta/classes/imagetypes_wic.bbclass | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/meta/classes/imagetypes_wic.bbclass b/meta/classes/imagetypes_wic.bbclass
index c75d481d..fe31e4e6 100644
--- a/meta/classes/imagetypes_wic.bbclass
+++ b/meta/classes/imagetypes_wic.bbclass
@@ -201,4 +201,29 @@ EOIMAGER
${DEPLOY_DIR_IMAGE}/${INITRD_DEPLOY_FILE}.manifest \
${WORKDIR}/imager.manifest 2>/dev/null \
| sort | uniq > "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic.manifest"
+
+ for bomtype in ${SBOM_TYPES}; do
+ merge_wic_sbom $bomtype
+ done
+}
+
+merge_wic_sbom() {
+ BOMTYPE="$1"
+ TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
+ sbom_document_uuid="${@d.getVar('SBOM_DOCUMENT_UUID') or generate_document_uuid(d, False)}"
+
+ cat ${IMAGE_FULLNAME}.${bomtype}.json \
+ ${INITRD_DEPLOY_FILE}.${bomtype}.json \
+ ${WORKDIR}/imager.${bomtype}.json 2>/dev/null | \
+ bwrap \
+ --unshare-user \
+ --unshare-pid \
+ --bind ${SBOM_CHROOT} / \
+ -- debsbom -v merge -t $BOMTYPE \
+ --distro-name '${SBOM_DISTRO_NAME}-Image' --distro-supplier '${SBOM_DISTRO_SUPPLIER}' \
+ --distro-version '${SBOM_DISTRO_VERSION}' --base-distro-vendor '${SBOM_BASE_DISTRO_VENDOR}' \
+ --cdx-serialnumber $sbom_document_uuid \
+ --spdx-namespace '${SBOM_SPDX_NAMESPACE_PREFIX}'-$sbom_document_uuid \

Jan Kiszka

unread,
Dec 1, 2025, 4:15:20 AM (4 days ago) Dec 1
to Felix Moessbauer, isar-...@googlegroups.com, christop...@siemens.com, cedric.h...@siemens.com, quirin.g...@siemens.com
New classes should go into the right category already, then rebasing is
easier for whoever has to do it in the light of
https://patchwork.isar-build.org/project/isar/list/?series=1780. Look at
the dracut series.

Jan

--
Siemens AG, Foundational Technologies
Linux Expert Center

MOESSBAUER, Felix

unread,
Dec 3, 2025, 8:32:20 AM (2 days ago) Dec 3
to isar-...@googlegroups.com, Kiszka, Jan, Steiger, Christoph, quirin.g...@siemens.com, cedric.h...@siemens.com
Hi, according to my interpretation of the use-more-classes series and
the dracut series, the sbom class is already correct. The sbom series
also cleanly applies and works on top of the use-more-classes series.

Felix

>
> Jan
>
> --
> Siemens AG, Foundational Technologies
> Linux Expert Center

Bouska, Zdenek

unread,
10:08 AM (2 hours ago) 10:08 AM
to MOESSBAUER, Felix, isar-...@googlegroups.com, Steiger, Christoph, cedric.h...@siemens.com, Kiszka, Jan, quirin.g...@siemens.com
> This patchset adds proper SBOM generation in the two standard formats
> SPDX and CycloneDX during the rootfs generation process.

libre2-11 (provider of virtual package libre2-11-absl20240722) is
missing as dependency of libgrpc29t64 in
build/tmp/deploy/images/qemuamd64/isar-image-base-debian-trixie-qemuamd64.wic.cdx.json
See dependencies on Debian Trixie [1].

Reproduce by a bit older isar so that this patchset works:
2efd5d4ca3b4abf2386fe0089594029becdf2801
$ isar/kas/kas-container build trixie-grpc.yml
$ cat trixie-grpc.yml
header:
version: 14

build_system: isar

machine: qemuamd64
distro: debian-trixie

target: mc:qemuamd64-trixie:isar-image-base

repos:
isar:
path: isar
layers:
meta:
meta-isar:

local_conf_header:
meta-custom: |
IMAGE_PREINSTALL:append = " libgrpc29t64"


[1] https://packages.debian.org/trixie/libgrpc29t64

Thank you for pushing debsbom to isar!
Zdenek Bouska

--
Siemens, s.r.o
Foundational Technologies
Reply all
Reply to author
Forward
0 new messages