From a4b9c7259defda5a7b1b771a736cadc7ec01d4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20V=C3=ADtov=C3=A1?= Date: Tue, 9 Jun 2026 13:51:48 +0200 Subject: [PATCH] imgtestlib: handle missing sources key in tests Prevent a KeyError crash when accessing org.osbuild.curl for missing sources. This commit also reconciles dropped changes in imgtestlib. During the time when the imgtestlib split PR was open [1], some changes were merged and the PR had to be rebased. During the rebase, I (AK) missed some of the changes that were already merged, essentially reverting them. I went through all functions that were in the monolithic imgtestlib and made sure to bring in all changes that were dropped and adapted them to newer changes. [1] https://github.com/osbuild/images/pull/2383 Co-authored-by: Achilleas Koutsou --- test/scripts/imgtestlib/core.py | 49 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/test/scripts/imgtestlib/core.py b/test/scripts/imgtestlib/core.py index 38dd0534b4..e0d23a1ee2 100644 --- a/test/scripts/imgtestlib/core.py +++ b/test/scripts/imgtestlib/core.py @@ -39,6 +39,7 @@ "image-installer", "minimal-installer", "network-installer", "qcow2", "generic-qcow2", "cloud-qcow2", "wsl", "generic-wsl", + "bootc-generic-iso", ] } @@ -434,22 +435,44 @@ def can_boot_test(manifest_fname, manifest_data, image_type, arch, distro, bluep return False if image_type in ["qcow2", "generic-qcow2", "cloud-qcow2", "image-installer", "minimal-installer", - "network-installer", "everything-network-installer"]: + "network-installer", "everything-network-installer", "bootc-generic-iso"]: if blueprint.get("customizations", {}).get("fips") and distro.startswith("fedora"): print(" not bootable: fips on fedora is unstable, fails with e.g. dracut:" "FATAL: FIPS integrity test failed") return False - # Note that this needs adjustment when we switch to librepo - urls = [src["url"] for src in manifest_data["sources"]["org.osbuild.curl"]["items"].values()] - if not any("ssh-server" in url for url in urls): - # This can happen e.g. when an image is build with the "minimal: true" customization. - # We could use guestfs to inject keys, see PR#1995 - print(f" not bootable: ssh-server not found in manifest {manifest_fname} ({arch} {image_type})") - return False - # We need jq in the image many images do not have it - # (e.g. centos-9/rhel-9 with releasever config) so skip those too - if not any("jq" in url for url in urls): - print(f" not bootable: jq not found in {manifest_fname} ({arch} {image_type})") - return False + if not image_type.startswith("bootc-") and not _is_bootc_manifest(manifest_data): + # Note that this needs adjustment when we switch to librepo + curl_items = manifest_data.get("sources", {}).get("org.osbuild.curl", {}).get("items", {}) + if not curl_items: + print(f" not bootable: no org.osbuild.curl source in manifest {manifest_fname} ({arch} {image_type})") + print(" (parsing librepo sources not implemented yet") + return False + urls = [src["url"] for src in curl_items.values()] + if not any("ssh-server" in url for url in urls): + # This can happen e.g. when an image is build with the "minimal: true" customization. + # We could use guestfs to inject keys, see PR#1995 + print(f" not bootable: ssh-server not found in manifest {manifest_fname} ({arch} {image_type})") + return False + + # We need jq in the image many images do not have it + # (e.g. centos-9/rhel-9 with releasever config) so skip those too + if not any("jq" in url for url in urls): + print(f" not bootable: jq not found in {manifest_fname} ({arch} {image_type})") + return False return True + + +def _is_bootc_manifest(manifest_data): + """ + Check if the manifest is a bootc manifest by looking for the + `org.osbuild.bootc.install-to-filesystem` stage in any of the pipelines + other than the build pipeline. + """ + for pipeline in manifest_data.get("pipelines", []): + if pipeline.get("name") == "build": + continue + for stage in pipeline.get("stages", []): + if stage.get("type") == "org.osbuild.bootc.install-to-filesystem": + return True + return False