On Fri, Jun 5, 2026 at 6:05 AM Peter Marko via lists.openembedded.org <[email protected]> wrote: > > From: Peter Marko <[email protected]> > > SPDX should not list packages which were removed from rootfs as installed. > > The list of installed packages does not contain them directly, but as > dependencies of other installed packages. > > Siwtch them to "other" to keep them in SPDX as part of the build and > installation process.
I agree the packages should be removed from the rootfs, but using the method described. Instead, the list of removed packages should be passed to collect_build_package_inputs(), and anything removed should skip having it's files added to files_by_hash (but, should still be added to build_deps, since it is a build dependency). This will prevent that rootfs package from "containing" the files for removed packages, and break the linkage between the rootfs and the removed packages. I'm not exactly sure the reasoning behind changing the type the "other", but we should not be doing that. > > Signed-off-by: Peter Marko <[email protected]> > --- > meta/classes-recipe/create-spdx-image-3.0.bbclass | 7 +++++++ > meta/lib/oe/rootfs.py | 6 ++++++ > meta/lib/oe/sbom30.py | 8 +++++++- > meta/lib/oe/spdx30_tasks.py | 14 +++++++++++++- > 4 files changed, 33 insertions(+), 2 deletions(-) > > diff --git a/meta/classes-recipe/create-spdx-image-3.0.bbclass > b/meta/classes-recipe/create-spdx-image-3.0.bbclass > index 15a91e90e2..dfbd2961b3 100644 > --- a/meta/classes-recipe/create-spdx-image-3.0.bbclass > +++ b/meta/classes-recipe/create-spdx-image-3.0.bbclass > @@ -6,6 +6,7 @@ > # SPDX image tasks > > SPDX_ROOTFS_PACKAGES = "${SPDXDIR}/rootfs-packages.json" > +SPDX_ROOTFS_REMOVED_PACKAGES = "${SPDXDIR}/rootfs-removed-packages.json" > SPDXIMAGEDEPLOYDIR = "${SPDXDIR}/image-deploy" > SPDXROOTFSDEPLOY = "${SPDXDIR}/rootfs-deploy" > > @@ -15,14 +16,20 @@ python spdx_collect_rootfs_packages() { > from oe.rootfs import image_list_installed_packages > > root_packages_file = Path(d.getVar("SPDX_ROOTFS_PACKAGES")) > + root_removed_packages_file = > Path(d.getVar("SPDX_ROOTFS_REMOVED_PACKAGES")) > > packages = image_list_installed_packages(d) > if not packages: > packages = {} > > + removed_packages = (d.getVar("ROOTFS_REMOVED_PACKAGES") or "").split() > + > root_packages_file.parent.mkdir(parents=True, exist_ok=True) > with root_packages_file.open("w") as f: > json.dump(packages, f) > + > + with root_removed_packages_file.open("w") as f: > + json.dump(removed_packages, f) > } > ROOTFS_POSTUNINSTALL_COMMAND =+ "spdx_collect_rootfs_packages" > > diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py > index 5eee48f587..b8830596ed 100644 > --- a/meta/lib/oe/rootfs.py > +++ b/meta/lib/oe/rootfs.py > @@ -261,10 +261,13 @@ class Rootfs(object, metaclass=ABCMeta): > > > def _uninstall_unneeded(self): > + removed_pkgs = set() > + > # Remove the run-postinsts package if no delayed postinsts are found > delayed_postinsts = self._get_delayed_postinsts() > if delayed_postinsts is None: > if > os.path.exists(self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/init.d/run-postinsts")) > or > os.path.exists(self.d.expand("${IMAGE_ROOTFS}${systemd_system_unitdir}/run-postinsts.service")): > + removed_pkgs.add("run-postinsts") > self.pm.remove(["run-postinsts"]) > > image_rorfs = bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs", > @@ -285,6 +288,7 @@ class Rootfs(object, metaclass=ABCMeta): > # to be uninstalled or to be managed correctly otherwise. > provider = self.d.getVar("VIRTUAL-RUNTIME_update-alternatives") > pkgs_to_remove = sorted([pkg for pkg in pkgs_installed if pkg in > unneeded_pkgs], key=lambda x: x == provider) > + removed_pkgs.update(pkgs_to_remove) > > # update-alternatives provider is removed in its own remove() > # call because all package managers do not guarantee the packages > @@ -296,6 +300,8 @@ class Rootfs(object, metaclass=ABCMeta): > if len(pkgs_to_remove) > 0: > self.pm.remove([pkgs_to_remove[-1]], False) > > + self.d.setVar("ROOTFS_REMOVED_PACKAGES", " > ".join(sorted(removed_pkgs))) > + > if delayed_postinsts: > self._save_postinsts() > if image_rorfs: > diff --git a/meta/lib/oe/sbom30.py b/meta/lib/oe/sbom30.py > index b379ff947c..4fa32266fa 100644 > --- a/meta/lib/oe/sbom30.py > +++ b/meta/lib/oe/sbom30.py > @@ -1122,7 +1122,7 @@ def find_by_spdxid(d, spdxid, *, required=False): > return find_jsonld(d, *jsonld_hash_path(hash_id(spdxid)), > required=required) > > > -def create_sbom(d, name, root_elements, add_objectsets=[]): > +def create_sbom(d, name, root_elements, add_objectsets=[], > removed_packages=[]): > objset = ObjectSet.new_objset(d, name) > > sbom = objset.add( > @@ -1142,6 +1142,12 @@ def create_sbom(d, name, root_elements, > add_objectsets=[]): > + "\n ".join(sorted(list(missing_spdxids))) > ) > > + if removed_packages: > + for pkg in objset.foreach_type(oe.spdx30.software_Package): > + if pkg.name in removed_packages and pkg.software_primaryPurpose > == oe.spdx30.software_SoftwarePurpose.install: > + pkg.software_primaryPurpose = > oe.spdx30.software_SoftwarePurpose.other > + bb.note("Reclassified removed package %s SPDX entry from > install to other" % pkg.name) > + > # Filter out internal extensions from final SBoMs > objset.remove_internal_extensions() > > diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py > index 7cc46d579b..18c68f47de 100644 > --- a/meta/lib/oe/spdx30_tasks.py > +++ b/meta/lib/oe/spdx30_tasks.py > @@ -1532,6 +1532,7 @@ def create_image_sbom_spdx(d): > image_link_name = d.getVar("IMAGE_LINK_NAME") > imgdeploydir = Path(d.getVar("SPDXIMAGEDEPLOYDIR")) > machine = d.getVar("MACHINE") > + root_removed_packages_file = > Path(d.getVar("SPDX_ROOTFS_REMOVED_PACKAGES")) > > spdx_path = imgdeploydir / (image_name + ".spdx.json") > > @@ -1553,7 +1554,18 @@ def create_image_sbom_spdx(d): > for o in image_objset.foreach_root(oe.spdx30.software_File): > root_elements.append(oe.sbom30.get_element_link_id(o)) > > - objset, sbom = oe.sbom30.create_sbom(d, image_name, root_elements) > + try: > + with root_removed_packages_file.open("r") as f: > + removed_packages = json.load(f) > + except FileNotFoundError: > + removed_packages = [] > + > + objset, sbom = oe.sbom30.create_sbom( > + d, > + image_name, > + root_elements, > + removed_packages=removed_packages, > + ) > > # Set supplier on root elements if SPDX_IMAGE_SUPPLIER is defined > supplier = objset.new_agent("SPDX_IMAGE_SUPPLIER", add=False) > > >
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#238169): https://lists.openembedded.org/g/openembedded-core/message/238169 Mute This Topic: https://lists.openembedded.org/mt/119660891/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
