From ab65078675f4a3875d3063f5ea43f1a89eeb52d4 Mon Sep 17 00:00:00 2001
From: ckyrouac <ckyrouac@redhat.com>
Date: Tue, 13 Jan 2026 11:29:09 -0500
Subject: [PATCH 1/3] install: Fix bug in mount point check

This fixes a regression from https://github.com/bootc-dev/bootc/pull/1727
by removing the unnecessary mount point check prior to the recursive
function call. Also adds some tracing statements and updates the
integration test to validate the mount check works for this scenario:

/boot/efi mounted with contents in /boot/efi/EFI/firmware/foo

Signed-off-by: ckyrouac <ckyrouac@redhat.com>
---
 crates/lib/src/install.rs               |  5 ++++-
 crates/tests-integration/src/install.rs | 24 +++++++++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs
index 90826b49f..105e2b3c1 100644
--- a/crates/lib/src/install.rs
+++ b/crates/lib/src/install.rs
@@ -1874,8 +1874,10 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
 /// /var/lib/containers (a mount point).
 #[context("Requiring directory contains only mount points")]
 fn require_dir_contains_only_mounts(parent_fd: &Dir, dir_name: &str) -> Result<()> {
+    tracing::trace!("Checking directory {dir_name} for non-mount entries");
     let Some(dir_fd) = parent_fd.open_dir_noxdev(dir_name)? else {
         // The directory itself is a mount point
+        tracing::trace!("{dir_name} is a mount point");
         return Ok(());
     };
 
@@ -1884,6 +1886,7 @@ fn require_dir_contains_only_mounts(parent_fd: &Dir, dir_name: &str) -> Result<(
     }
 
     for entry in dir_fd.entries()? {
+        tracing::trace!("Checking entry in {dir_name}");
         let entry = DirEntryUtf8::from_cap_std(entry?);
         let entry_name = entry.file_name()?;
 
@@ -1892,7 +1895,7 @@ fn require_dir_contains_only_mounts(parent_fd: &Dir, dir_name: &str) -> Result<(
         }
 
         let etype = entry.file_type()?;
-        if etype == FileType::dir() && dir_fd.open_dir_noxdev(&entry_name)?.is_some() {
+        if etype == FileType::dir() {
             require_dir_contains_only_mounts(&dir_fd, &entry_name)?;
         } else {
             anyhow::bail!("Found entry in {dir_name}: {entry_name}");
diff --git a/crates/tests-integration/src/install.rs b/crates/tests-integration/src/install.rs
index 0c39c475e..80a967978 100644
--- a/crates/tests-integration/src/install.rs
+++ b/crates/tests-integration/src/install.rs
@@ -99,6 +99,10 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
                 let sh = &xshell::Shell::new()?;
                 reset_root(sh, image)?;
 
+                // Clean up any leftover LVM state from previous failed runs
+                let _ = cmd!(sh, "sudo vgchange -an BL").ignore_status().run();
+                let _ = cmd!(sh, "sudo vgremove -f BL").ignore_status().run();
+
                 // Create work directory for the test
                 let tmpd = sh.create_temp_dir()?;
                 let work_dir = tmpd.path();
@@ -153,13 +157,13 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
                     cmd!(sh, "sudo partprobe {loop_dev}").run()?;
                     std::thread::sleep(std::time::Duration::from_secs(2));
 
-                    let loop_part2 = format!("{}p2", loop_dev); // EFI
-                    let loop_part3 = format!("{}p3", loop_dev); // Boot
+                    let efi_part2 = format!("{}p2", loop_dev); // EFI
+                    let root_part3 = format!("{}p3", loop_dev); // Boot
                     let loop_part4 = format!("{}p4", loop_dev); // LVM
 
                     // Create filesystems on boot partitions
-                    cmd!(sh, "sudo mkfs.vfat -F32 {loop_part2}").run()?;
-                    cmd!(sh, "sudo mkfs.ext4 -F {loop_part3}").run()?;
+                    cmd!(sh, "sudo mkfs.vfat -F32 {efi_part2}").run()?;
+                    cmd!(sh, "sudo mkfs.ext4 -F {root_part3}").run()?;
 
                     // Setup LVM
                     cmd!(sh, "sudo pvcreate {loop_part4}").run()?;
@@ -178,7 +182,7 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
                         .read()?
                         .trim()
                         .to_string();
-                    let boot_uuid = cmd!(sh, "sudo blkid -s UUID -o value {loop_part2}")
+                    let boot_uuid = cmd!(sh, "sudo blkid -s UUID -o value {efi_part2}")
                         .read()?
                         .trim()
                         .to_string();
@@ -190,9 +194,15 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
 
                     cmd!(sh, "sudo mount /dev/BL/root02 {target}").run()?;
                     cmd!(sh, "sudo mkdir -p {target}/boot").run()?;
-                    cmd!(sh, "sudo mount {loop_part3} {target}/boot").run()?;
+                    cmd!(sh, "sudo mount {root_part3} {target}/boot").run()?;
                     cmd!(sh, "sudo mkdir -p {target}/boot/efi").run()?;
-                    cmd!(sh, "sudo mount {loop_part2} {target}/boot/efi").run()?;
+                    cmd!(sh, "sudo mount {efi_part2} {target}/boot/efi").run()?;
+
+                    // Create EFI directory structure with some files (simulating existing EFI content)
+                    // This tests that bootc correctly handles /boot/efi as a mount point
+                    cmd!(sh, "sudo mkdir -p {target}/boot/efi/EFI/fedora").run()?;
+                    cmd!(sh, "sudo touch {target}/boot/efi/EFI/fedora/shimx64.efi").run()?;
+                    cmd!(sh, "sudo touch {target}/boot/efi/EFI/fedora/grubx64.efi").run()?;
 
                     // Critical: Mount /var as a separate partition
                     cmd!(sh, "sudo mkdir -p {target}/var").run()?;

From 03a2567458c0fa56a0b3bdd925a990d01bf22042 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Wed, 14 Jan 2026 08:30:35 -0500
Subject: [PATCH 2/3] ci: Add gating property to allow non-blocking test
 failures

Add a `gating` matrix property to test-integration jobs.
Jobs with `gating: false` use `continue-on-error: true`, allowing
them to fail without blocking PR merges.

Mark fedora-44 as non-gating due to a grub2 regression in the base
image (https://bugzilla.redhat.com/show_bug.cgi?id=2429501).

Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
---
 .github/workflows/ci.yml | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5ae021397..26c23e322 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -154,11 +154,24 @@ jobs:
       matrix:
         test_os: [fedora-42, fedora-43, fedora-44, centos-9, centos-10]
         variant: [ostree, composefs-sealeduki-sdboot]
+        gating: [true]
         exclude:
           # centos-9 UKI is experimental/broken (https://github.com/bootc-dev/bootc/issues/1812)
           - test_os: centos-9
             variant: composefs-sealeduki-sdboot
-
+          - test_os: fedora-44
+            gating: true
+        include:
+          # fedora-44 non-gating due to grub2 regression
+          # https://bugzilla.redhat.com/show_bug.cgi?id=2429501
+          - test_os: fedora-44
+            gating: false
+            variant: ostree
+          - test_os: fedora-44
+            gating: false
+            variant: composefs-sealeduki-sdboot
+    # Non-gating jobs are allowed to fail without blocking the PR
+    continue-on-error: ${{ !matrix.gating }}
     runs-on: ubuntu-24.04
 
     steps:

From 8b4d6ac5ac6937330ac41cb65d255341c0e9bb46 Mon Sep 17 00:00:00 2001
From: ckyrouac <ckyrouac@redhat.com>
Date: Wed, 14 Jan 2026 11:13:04 -0500
Subject: [PATCH 3/3] install: Reduce disk space usage of mount test

It was using 12G, reduce it down to 1G to avoid the github runner
running out of space.

Signed-off-by: ckyrouac <ckyrouac@redhat.com>
---
 crates/tests-integration/src/install.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/crates/tests-integration/src/install.rs b/crates/tests-integration/src/install.rs
index 80a967978..de3a8dbe0 100644
--- a/crates/tests-integration/src/install.rs
+++ b/crates/tests-integration/src/install.rs
@@ -109,7 +109,7 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
 
                 // Create a disk image with partitions for root and var
                 let disk_img = work_dir.join("disk.img");
-                let size = 12 * 1024 * 1024 * 1024;
+                let size = 1024 * 1024 * 1024; // 1 GiB
                 let disk_file = std::fs::File::create(&disk_img)?;
                 disk_file.set_len(size)?;
                 drop(disk_file);
@@ -170,8 +170,8 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
                     cmd!(sh, "sudo vgcreate BL {loop_part4}").run()?;
 
                     // Create logical volumes
-                    cmd!(sh, "sudo lvcreate -L 4G -n var02 BL").run()?;
-                    cmd!(sh, "sudo lvcreate -L 5G -n root02 BL").run()?;
+                    cmd!(sh, "sudo lvcreate -L 100M -n var02 BL").run()?;
+                    cmd!(sh, "sudo lvcreate -L 100M -n root02 BL").run()?;
 
                     // Create filesystems on logical volumes
                     cmd!(sh, "sudo mkfs.ext4 -F /dev/BL/var02").run()?;
