> -----Original Message-----
> From: Joshua Watt <[email protected]>
> Sent: Friday, June 5, 2026 4:16 PM
> To: Marko, Peter (FT D EU SK BFS1) <[email protected]>
> Cc: [email protected]
> Subject: Re: [OE-core] [PATCH 2/2] rootfs,spdx: handle removed packages
> 
> 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).

I have tried several approaches here but all without success until now..
The problem is that these removed packages are "rdepends" and not "depends".
Thus in collect_build_package_inputs they are not present yet.
And even if they would be, the rdepends would anyway add it back later.

SPDX entries for rdepend clauses are added in expand_collection function.
I obviously cannot remove the rdepends clause when the recipe sbom is created.

The best approach probably is to remove the rdepends when iterating over sbomx 
in expand_collection.
Would you agree when I try to send a patch in that direction?
Or do you have any other suggestion?

> 
> 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.

Well, "other" because there was no good value for that available in enum 
(installation helper).

> 
> >
> > 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 (#238242): 
https://lists.openembedded.org/g/openembedded-core/message/238242
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]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to