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