From e3236a8b34e86712463130ba8edc6a8707c7ed0d Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Tue, 22 Jul 2025 11:31:13 -0700 Subject: [PATCH] org.osbuild.grub2.iso.legacy: Add support for default menu selection Currently the grub2 menu defaults to the first entry. This adds support for setting the default to a later entry. The default in the official boot.iso is entry 1 -- booting with the iso checksum check. This includes a test for the new behavior. --- stages/org.osbuild.grub2.iso.legacy | 13 ++++++++++- stages/org.osbuild.grub2.iso.legacy.meta.json | 4 ++++ stages/test/test_grub2_iso_legacy.py | 23 ++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/stages/org.osbuild.grub2.iso.legacy b/stages/org.osbuild.grub2.iso.legacy index dec0c3a7..1259ea63 100755 --- a/stages/org.osbuild.grub2.iso.legacy +++ b/stages/org.osbuild.grub2.iso.legacy @@ -8,7 +8,7 @@ import osbuild.api # The main grub2 configuration file template. Used for BIOS. # NOTE: Changes to this should also be applied to the org.osbuild.grub2.iso stage -GRUB2_CFG_TEMPLATE = """ +GRUB2_CFG_TEMPLATE = """$defaultentry function load_video { insmod all_video } @@ -58,6 +58,9 @@ menuentry 'Install ${product} ${version} in FIPS mode' --class fedora --class gn } """ +DEFAULT_ENTRY_TEMPLATE = """set default="${default}" +""" + def main(root, options): name = options["product"]["name"] @@ -67,6 +70,7 @@ def main(root, options): kopts = options["kernel"].get("opts") cfg = options.get("config", {}) timeout = cfg.get("timeout", 60) + default = cfg.get("default") # None indicates not set fips = options.get("fips", False) grub2dir = os.path.join(root, "boot", "grub2") @@ -85,9 +89,16 @@ def main(root, options): "isolabel": isolabel, "root": " ".join(kopts), "timeout": timeout, + "defaultentry": "", "fipsentry": "" } + # Insert default menu selection + if default is not None: + default_tmpl = string.Template(DEFAULT_ENTRY_TEMPLATE) + defaultentry = default_tmpl.safe_substitute({"default": default}) + tplt_variables["defaultentry"] = defaultentry + # Insert optional fips menu entry if fips: fips_tmpl = string.Template(FIPS_ENTRY_TEMPLATE) diff --git a/stages/org.osbuild.grub2.iso.legacy.meta.json b/stages/org.osbuild.grub2.iso.legacy.meta.json index 7869d6ae..2c9e9609 100644 --- a/stages/org.osbuild.grub2.iso.legacy.meta.json +++ b/stages/org.osbuild.grub2.iso.legacy.meta.json @@ -60,6 +60,10 @@ "type": "integer", "minimum": 0, "default": 60 + }, + "default": { + "description": "Default menu entry", + "type": "integer" } } } diff --git a/stages/test/test_grub2_iso_legacy.py b/stages/test/test_grub2_iso_legacy.py index 32b6654b..92145a83 100644 --- a/stages/test/test_grub2_iso_legacy.py +++ b/stages/test/test_grub2_iso_legacy.py @@ -58,13 +58,18 @@ menuentry 'Install Fedora-IoT 41 in FIPS mode' --class fedora --class gnu-linux } """ +CONFIG_DEFAULT = """set default="1" +""" + @patch("shutil.copytree") @pytest.mark.parametrize("test_data,expected_conf", [ # default ({}, CONFIG_PART_1 + CONFIG_PART_2), # fips menu enable - ({"fips": True}, CONFIG_PART_1 + CONFIG_FIPS + CONFIG_PART_2) + ({"fips": True}, CONFIG_PART_1 + CONFIG_FIPS + CONFIG_PART_2), + # default to menu entry 1 + ({"config": {"default": 1, "timeout": 10}}, CONFIG_DEFAULT + CONFIG_PART_1 + CONFIG_PART_2) ]) def test_grub2_iso_legacy_smoke(mocked_copytree, tmp_path, stage_module, test_data, expected_conf): treedir = tmp_path / "tree" @@ -151,6 +156,22 @@ def test_grub2_iso_legacy_smoke(mocked_copytree, tmp_path, stage_module, test_da "fips": True, }, "", ), + # good + default + ( + { + "isolabel": "an-isolabel", + "product": { + "name": "a-name", + "version": "a-version", + }, + "kernel": { + "dir": "/path/to", + }, + "config": { + "default": 1 + } + }, "", + ), ]) def test_schema_validation(stage_schema, test_data, expected_err): test_input = {