On Fri, Jun 5, 2026 at 8:16 AM Joshua Watt <[email protected]> wrote:
>
> 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.

"but *not* using the method described in this patch, please try the
method listed below"

Need more coffee :)

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