From 957336b8f8b0650aef371659768020f72108d41b Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 23 Sep 2026 06:49:26 -0400 Subject: [PATCH] lints: Don't require ostree bits on composefs-native images The baseimage-root lint insists on an /ostree -> sysroot/ostree symlink, and baseimage-composefs warns unless ostree's prepare-root.conf enables composefs. Both are meaningless for images that are only ever deployed with the composefs backend, and just force them to carry ostree cruft. Use the presence of /usr/lib/composefs/setup-root-conf.toml (even if empty) as the signal that an image is composefs-native, mirroring how prepare-root.conf signals ostree. If /ostree is present anyway it is still validated, and /sysroot is still required since both backends mount the physical root there. Closes: #2256 Generated-by: AI Signed-off-by: Colin Walters --- crates/lib/src/lints.rs | 51 ++++++++++++++++++++++++- docs/src/bootc-images.md | 6 ++- docs/src/man/bootc-setup-root-conf.5.md | 5 +++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/crates/lib/src/lints.rs b/crates/lib/src/lints.rs index aa41e9cfd4..fb0b2f73e2 100644 --- a/crates/lib/src/lints.rs +++ b/crates/lib/src/lints.rs @@ -573,12 +573,17 @@ fn check_api_dirs(root: &Dir, _config: &LintExecutionConfig) -> LintResult { static LINT_COMPOSEFS: Lint = Lint::new_warning( "baseimage-composefs", indoc! { r#" -Check that composefs is enabled for ostree. More in +Check that composefs is enabled for ostree. Skipped for composefs-native +images, i.e. those that ship /usr/lib/composefs/setup-root-conf.toml. More in . "#}, check_composefs, ); fn check_composefs(dir: &Dir, _config: &LintExecutionConfig) -> LintResult { + // ostree's prepare-root.conf is irrelevant for composefs-native images. + if is_composefs_native(dir)? { + return lint_ok(); + } if let Err(e) = check_prepareroot_composefs_norecurse(dir)? { return Ok(Err(e)); } @@ -592,6 +597,20 @@ fn check_composefs(dir: &Dir, _config: &LintExecutionConfig) -> LintResult { lint_ok() } +/// The setup-root configuration, relative to the root directory. +fn setup_root_conf_path() -> &'static str { + bootc_initramfs_setup::SETUP_ROOT_CONF_PATH.trim_start_matches('/') +} + +/// Whether the image is intended to be deployed only with the composefs +/// backend, which is signaled by the presence of a setup-root configuration +/// file (even if empty). +fn is_composefs_native(root: &Dir) -> Result { + Ok(root + .symlink_metadata_optional(setup_root_conf_path())? + .is_some()) +} + /// Check for a few files and directories we expect in the base image. fn check_baseimage_root_norecurse(dir: &Dir, _config: &LintExecutionConfig) -> LintResult { // Check /sysroot @@ -604,6 +623,10 @@ fn check_baseimage_root_norecurse(dir: &Dir, _config: &LintExecutionConfig) -> L // Check /ostree -> sysroot/ostree let Some(meta) = dir.symlink_metadata_optional("ostree")? else { + // Composefs-native images don't use ostree, so they don't need it. + if is_composefs_native(dir)? { + return lint_ok(); + } return lint_err("Missing ostree -> sysroot/ostree link"); }; if !meta.is_symlink() { @@ -624,7 +647,9 @@ static LINT_BASEIMAGE_ROOT: Lint = Lint::new_fatal( "baseimage-root", indoc! { r#" Check that expected files are present in the root of the filesystem; such -as /sysroot and a composefs configuration for ostree. More in +as /sysroot and a composefs configuration for ostree. The /ostree symlink +is not required for composefs-native images, i.e. those that ship +/usr/lib/composefs/setup-root-conf.toml. More in . "#}, check_baseimage_root, @@ -1365,6 +1390,21 @@ mod tests { drop(td); let td = passing_fixture()?; check_baseimage_root(&td, config).unwrap().unwrap(); + + // Composefs-native images don't need /ostree... + td.remove_file("ostree")?; + assert!(check_baseimage_root(&td, config).unwrap().is_err()); + let conf = Utf8Path::new(setup_root_conf_path()); + td.create_dir_all(conf.parent().unwrap())?; + td.write(conf, "")?; + check_baseimage_root(&td, config).unwrap().unwrap(); + // ...but if they have it, it must still be correct + td.create_dir("ostree")?; + assert!(check_baseimage_root(&td, config).unwrap().is_err()); + td.remove_dir("ostree")?; + // ...and they still need /sysroot + td.remove_dir("sysroot")?; + assert!(check_baseimage_root(&td, config).unwrap().is_err()); Ok(()) } @@ -1388,6 +1428,13 @@ mod tests { // Now it should fail because composefs is explicitly disabled. assert!(check_composefs(&td, config).unwrap().is_err()); + // ...unless the image is composefs-native, where ostree's + // configuration doesn't matter. + let conf = Utf8Path::new(setup_root_conf_path()); + td.create_dir_all(conf.parent().unwrap())?; + td.write(conf, "")?; + check_composefs(&td, config).unwrap().unwrap(); + Ok(()) } diff --git a/docs/src/bootc-images.md b/docs/src/bootc-images.md index be6c52b7c4..65cadd9616 100644 --- a/docs/src/bootc-images.md +++ b/docs/src/bootc-images.md @@ -27,7 +27,11 @@ For the composefs backend, the UKI must be located at `/boot/EFI/Linux/$kver.efi ### /ostree symlink and `bootc container lint` -This is [a bug](https://github.com/bootc-dev/bootc/issues/2256): currently a `/ostree -> /sysroot/ostree` symlink is required just for `bootc container lint` to pass, even though it's not required for `/sysroot/ostree` to exist. +`bootc container lint` requires a `/ostree -> sysroot/ostree` symlink, +unless the image is composefs-native, which is signaled by the presence of +`/usr/lib/composefs/setup-root-conf.toml` (it may be empty); see +[bootc-setup-root-conf.toml(5)](man/bootc-setup-root-conf.5.md). Such +images also don't need ostree's `prepare-root.conf` to enable composefs. ## composefs backend diff --git a/docs/src/man/bootc-setup-root-conf.5.md b/docs/src/man/bootc-setup-root-conf.5.md index 3e7082f06b..08d6f405c9 100644 --- a/docs/src/man/bootc-setup-root-conf.5.md +++ b/docs/src/man/bootc-setup-root-conf.5.md @@ -15,6 +15,11 @@ mounted. If the file does not exist all options take their documented defaults. +The presence of this file (even if empty) also marks the image as +composefs-native; `bootc container lint` then no longer requires the +`/ostree` symlink or the ostree `prepare-root.conf` composefs configuration +used by the ostree backend. + The `51bootc` dracut module installs this file into the initramfs automatically when it is present on the host image. Image authors can therefore ship the file at this path in their container image and rebuild the initramfs with a