From 8b05b06c7adeffc08200175a4f0c87cb3b8ac7b7 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 12:28:40 -0600 Subject: [PATCH 01/12] chore: Use Docker instead of Podman Docker is used everywhere on every platform by default. While Podman is subjectively better, the more accessible our build environment is to others, the better Podman can still be used if linked to Docker somewhere, or by installing podman-docker if available Signed-off-by: RJ Sampson --- Justfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Justfile b/Justfile index 4877d3b..52e30f7 100644 --- a/Justfile +++ b/Justfile @@ -20,7 +20,7 @@ create-cache-dir: mkdir -p ./.cache/workspace keygen *$ARGS: - podman run --rm -it -v "${PWD}:/work:Z" -w /work \ + docker run --rm -it -v "${PWD}:/work:Z" -w /work \ "${MELANGE_IMAGE}" \ keygen $ARGS @@ -57,7 +57,7 @@ renovate: GITHUB_COM_TOKEN=$(cat ~/.ssh/gh_renovate) LOG_LEVEL=${LOG_LEVEL:-debug} renovate --platform=local build-containerfile: - sudo podman build \ + sudo docker build \ -t wolfi-bootc:latest . build-apko $yaml="apko.yaml" $tag="wolfi-bootc:latest": @@ -70,7 +70,7 @@ build-apko $yaml="apko.yaml" $tag="wolfi-bootc:latest": sudo skopeo copy oci:./output/oci/ containers-storage:${tag} bootc *ARGS: - sudo podman run \ + sudo docker run \ --rm --privileged --pid=host \ -it \ -v /sys/fs/selinux:/sys/fs/selinux \ From da3817ebe1982c8179432efb39827e893c5394e9 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 14:44:05 -0600 Subject: [PATCH 02/12] chore(bootc): Update to 1.9.0 As far as I can tell, composefs-backend changes are now present Signed-off-by: RJ Sampson --- manifests/bootc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifests/bootc.yaml b/manifests/bootc.yaml index 338c96f..b41db2f 100644 --- a/manifests/bootc.yaml +++ b/manifests/bootc.yaml @@ -1,6 +1,6 @@ package: name: bootc - version: 1.5.1 + version: 1.9.0 epoch: 0 description: Boot and upgrade via container images copyright: @@ -23,8 +23,8 @@ pipeline: - uses: git-checkout with: repository: https://github.com/bootc-dev/bootc.git - branch: composefs-backend - expected-commit: 54e254cf1dc4925285f717353dc769b345ba149e + tag: v${{package.version}} + expected-commit: 7ad66dbfe3efaf827f4d3b29b4796b38f3d893dc - uses: patch with: From 82eaf25da8d06adfde69b4eea2a7536041e69d48 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 15:30:10 -0600 Subject: [PATCH 03/12] chore(bootupd): Update to v0.2.31, rebase systemd boot patch And track upstream Signed-off-by: RJ Sampson --- manifests/bootupd.yaml | 15 +- manifests/bootupd/systemd-boot.patch | 424 +++++++++++++++++++++++++++ 2 files changed, 433 insertions(+), 6 deletions(-) create mode 100644 manifests/bootupd/systemd-boot.patch diff --git a/manifests/bootupd.yaml b/manifests/bootupd.yaml index 351b26c..7bbf421 100644 --- a/manifests/bootupd.yaml +++ b/manifests/bootupd.yaml @@ -1,7 +1,7 @@ package: name: bootupd - version: 0.2.29 - epoch: 2 + version: 0.2.31 + epoch: 0 description: Bootloader updater copyright: - license: Apache-2.0 @@ -14,10 +14,13 @@ environment: pipeline: - uses: git-checkout with: - repository: https://github.com/p5/coreos-bootupd.git - # tag: v${{package.version}} - branch: sdboot-support - expected-commit: 23d044ce9533823cf0dbf4168122b9c25d918df5 + repository: https://github.com/coreos/bootupd.git + tag: v${{package.version}} + expected-commit: de779db5376f692b314a0b447d700db5b42cc6b1 + + - uses: patch + with: + patches: systemd-boot.patch - uses: cargo/build with: diff --git a/manifests/bootupd/systemd-boot.patch b/manifests/bootupd/systemd-boot.patch new file mode 100644 index 0000000..6c01645 --- /dev/null +++ b/manifests/bootupd/systemd-boot.patch @@ -0,0 +1,424 @@ +From a3fa92bd737b1e96ebba653ca60014446029df1f Mon Sep 17 00:00:00 2001 +From: Robert Sturla +Date: Fri, 29 Aug 2025 22:52:00 +0100 +Subject: [PATCH] feat: add systemd-boot support + +Signed-off-by: Robert Sturla +Signed-off-by: RJ Sampson +--- + Cargo.toml | 19 ++++++--- + README.md | 7 +++- + build.rs | 9 ++++ + src/bios.rs | 1 + + src/bootupd.rs | 87 ++++++++++++++++++++++++++++++++++++--- + src/component.rs | 1 + + src/efi.rs | 43 ++++++++++++++----- + src/main.rs | 3 ++ + src/systemdbootconfigs.rs | 61 +++++++++++++++++++++++++++ + 9 files changed, 208 insertions(+), 23 deletions(-) + create mode 100644 build.rs + create mode 100644 src/systemdbootconfigs.rs + +diff --git a/Cargo.toml b/Cargo.toml +index 4d6fce7..29fb775 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -7,6 +7,7 @@ authors = ["Colin Walters "] + edition = "2021" + rust-version = "1.84.1" + homepage = "https://github.com/coreos/bootupd" ++build = "build.rs" + + include = ["src", "LICENSE", "Makefile", "systemd"] + +@@ -15,6 +16,11 @@ include = ["src", "LICENSE", "Makefile", "systemd"] + platforms = ["*-unknown-linux-gnu"] + tier = "2" + ++[features] ++default = [] ++rpm = ["rpm-rs"] ++systemd-boot = [] ++ + [[bin]] + name = "bootupd" + path = "src/main.rs" +@@ -27,7 +33,14 @@ bootc-internal-utils = "0.0.0" + cap-std-ext = "4.0.6" + camino = "1.2.0" + chrono = { version = "0.4.42", features = ["serde"] } +-clap = { version = "4.5", default-features = false, features = ["cargo", "derive", "std", "help", "usage", "suggestions"] } ++clap = { version = "4.5", default-features = false, features = [ ++ "cargo", ++ "derive", ++ "std", ++ "help", ++ "usage", ++ "suggestions", ++] } + env_logger = "0.11" + fail = { version = "0.5", features = ["failpoints"] } + fn-error-context = "0.2.1" +@@ -63,7 +76,3 @@ pre-release-commit-message = "cargo: bootupd release {{version}}" + sign-commit = true + sign-tag = true + tag-message = "bootupd {{version}}" +- +-[features] +-default = [] +-rpm = ["rpm-rs"] +diff --git a/README.md b/README.md +index 917fc66..29411a3 100644 +--- a/README.md ++++ b/README.md +@@ -34,6 +34,10 @@ that's for tools like `grubby` and `ostree`. + bootupd supports updating GRUB and shim for UEFI firmware on x86_64, aarch64, + and riscv64, and GRUB for BIOS firmware on x86_64 and ppc64le. + ++bootupd only supports installing the systemd-boot shim currently, though may be ++updated to also handle updates in future. systemd-boot support just proxies ++to the relevant `bootctl` commands. ++ + The project is used in Bootable Containers and ostree/rpm-ostree based systems: + - [`bootc install`](https://github.com/containers/bootc/#using-bootc-install) + - [Fedora CoreOS](https://docs.fedoraproject.org/en-US/fedora-coreos/bootloader-updates/) +@@ -78,7 +82,7 @@ care of GRUB and shim. See discussion in [this issue](https://github.com/coreos + ### systemd bootctl + + [systemd bootctl](https://man7.org/linux/man-pages/man1/bootctl.1.html) can update itself; +-this project would probably just proxy that if we detect systemd-boot is in use. ++this project just proxies that if we detect systemd-boot is present. + + ## Other goals + +@@ -151,4 +155,3 @@ bootupd now uses `systemd-run` instead to guarantee the following: + - If we want a non-CLI API (whether that's DBus or Cap'n Proto or varlink or + something else), we will create an independent daemon with a stable API for + this specific need. +- +diff --git a/build.rs b/build.rs +new file mode 100644 +index 0000000..e598d38 +--- /dev/null ++++ b/build.rs +@@ -0,0 +1,9 @@ ++fn main() { ++ if std::env::var("CARGO_FEATURE_SYSTEMD_BOOT").is_ok() { ++ if let Ok(arch) = std::env::var("CARGO_CFG_TARGET_ARCH") { ++ if arch.starts_with("riscv") { ++ panic!("The systemd-boot feature is not supported on RISC-V."); ++ } ++ } ++ } ++} +diff --git a/src/bios.rs b/src/bios.rs +index b4eaca5..66e2f6f 100644 +--- a/src/bios.rs ++++ b/src/bios.rs +@@ -112,6 +112,7 @@ impl Component for Bios { + dest_root: &str, + device: &str, + _update_firmware: bool, ++ _bootloader: &crate::bootupd::Bootloader, + ) -> Result { + let src_dir = openat::Dir::open(src_root) + .with_context(|| format!("opening source directory {src_root}"))?; +diff --git a/src/bootupd.rs b/src/bootupd.rs +index 4dc10c3..2b2d147 100644 +--- a/src/bootupd.rs ++++ b/src/bootupd.rs +@@ -25,6 +25,13 @@ use std::fs::{self, File}; + use std::io::{BufRead, BufReader, BufWriter, Write}; + use std::path::{Path, PathBuf}; + ++#[derive(Debug, Clone, Copy, PartialEq, Eq)] ++pub(crate) enum Bootloader { ++ Grub2, ++ #[cfg(feature = "systemd-boot")] ++ SystemdBoot, ++} ++ + pub(crate) enum ConfigMode { + None, + Static, +@@ -81,6 +88,8 @@ pub(crate) fn install( + anyhow::bail!("No components specified"); + } + ++ let bootloader = select_bootloader(&source_root_dir); ++ + let mut state = SavedState::default(); + let mut installed_efi_vendor = None; + for &component in target_components.iter() { +@@ -93,20 +102,51 @@ pub(crate) fn install( + continue; + } + ++ #[cfg(feature = "systemd-boot")] ++ if bootloader == Bootloader::SystemdBoot && component.name() == "BIOS" { ++ log::warn!("Skip installing BIOS component when using systemd-boot"); ++ continue; ++ } ++ ++ let update_firmware = match bootloader { ++ Bootloader::Grub2 => update_firmware, ++ #[cfg(feature = "systemd-boot")] ++ Bootloader::SystemdBoot => false, ++ }; ++ + let meta = component +- .install(&source_root, dest_root, device, update_firmware) ++ .install( ++ &source_root, ++ dest_root, ++ device, ++ update_firmware, ++ &bootloader, ++ ) + .with_context(|| format!("installing component {}", component.name()))?; + log::info!("Installed {} {}", component.name(), meta.meta.version); + state.installed.insert(component.name().into(), meta); +- // Yes this is a hack...the Component thing just turns out to be too generic. +- if let Some(vendor) = component.get_efi_vendor(&Path::new(source_root))? { +- assert!(installed_efi_vendor.is_none()); +- installed_efi_vendor = Some(vendor); ++ ++ match bootloader { ++ Bootloader::Grub2 => { ++ // Yes this is a hack...the Component thing just turns out to be too generic. ++ if let Some(vendor) = component.get_efi_vendor(&Path::new(source_root))? { ++ assert!(installed_efi_vendor.is_none()); ++ installed_efi_vendor = Some(vendor); ++ } ++ } ++ #[cfg(feature = "systemd-boot")] ++ _ => {} + } + } + let sysroot = &openat::Dir::open(dest_root)?; + +- match configs.enabled_with_uuid() { ++ // If systemd-boot is enabled, do not run grubconfigs::install ++ let configs_with_uuid = match bootloader { ++ Bootloader::Grub2 => configs.enabled_with_uuid(), ++ #[cfg(feature = "systemd-boot")] ++ _ => None, ++ }; ++ match configs_with_uuid { + Some(uuid) => { + let meta = get_static_config_meta()?; + state.static_configs = Some(meta); +@@ -716,6 +756,41 @@ fn strip_grub_config_file( + Ok(()) + } + ++/// Determine whether the necessary bootloader files are present for GRUB. ++fn has_grub(source_root_dir: &openat::Dir) -> bool { ++ source_root_dir.open_file("usr/sbin/grub2-install").is_ok() ++} ++ ++/// Determine whether the necessary bootloader files are present for systemd-boot. ++#[cfg(feature = "systemd-boot")] ++fn has_systemd_boot(source_root_dir: &openat::Dir) -> bool { ++ source_root_dir.open_file(efi::SYSTEMD_BOOT_EFI).is_ok() ++} ++ ++/// Select the bootloader based on available binaries and feature flags. ++fn select_bootloader(source_root_dir: &openat::Dir) -> Bootloader { ++ #[cfg(not(feature = "systemd-boot"))] ++ { ++ if has_grub(source_root_dir) { ++ Bootloader::Grub2 ++ } else { ++ log::warn!("No bootloader binaries found, defaulting to Grub2"); ++ Bootloader::Grub2 ++ } ++ } ++ #[cfg(feature = "systemd-boot")] ++ { ++ if has_grub(source_root_dir) { ++ Bootloader::Grub2 ++ } else if has_systemd_boot(source_root_dir) { ++ Bootloader::SystemdBoot ++ } else { ++ log::warn!("No bootloader binaries found, defaulting to Grub2"); ++ Bootloader::Grub2 ++ } ++ } ++} ++ + #[cfg(test)] + mod tests { + use super::*; +diff --git a/src/component.rs b/src/component.rs +index 8c3ec3c..e3b752d 100644 +--- a/src/component.rs ++++ b/src/component.rs +@@ -55,6 +55,7 @@ pub(crate) trait Component { + dest_root: &str, + device: &str, + update_firmware: bool, ++ bootloader: &crate::bootupd::Bootloader, + ) -> Result; + + /// Implementation of `bootupd generate-update-metadata` for a given component. +diff --git a/src/efi.rs b/src/efi.rs +index 25d6ccd..f523273 100644 +--- a/src/efi.rs ++++ b/src/efi.rs +@@ -22,7 +22,7 @@ use rustix::{fd::AsFd, fd::BorrowedFd, fs::StatVfsMountFlags}; + use walkdir::WalkDir; + use widestring::U16CString; + +-use crate::bootupd::RootContext; ++use crate::bootupd::{Bootloader, RootContext}; + use crate::freezethaw::fsfreeze_thaw_cycle; + use crate::model::*; + use crate::ostreeutil; +@@ -53,6 +53,10 @@ const EFIVARFS: &str = "/sys/firmware/efi/efivars"; + /// Systemd boot loader info EFI variable names + const LOADER_INFO_VAR_STR: &str = "LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"; + const STUB_INFO_VAR_STR: &str = "StubInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"; ++#[cfg(all(feature = "systemd-boot", target_arch = "aarch64"))] ++pub(crate) const SYSTEMD_BOOT_EFI: &str = "usr/lib/systemd/boot/efi/systemd-bootaarch64.efi"; ++#[cfg(all(feature = "systemd-boot", target_arch = "x86_64"))] ++pub(crate) const SYSTEMD_BOOT_EFI: &str = "usr/lib/systemd/boot/efi/systemd-bootx64.efi"; + + /// Return `true` if the system is booted via EFI + pub(crate) fn is_efi_booted() -> Result { +@@ -368,16 +372,8 @@ impl Component for Efi { + dest_root: &str, + device: &str, + update_firmware: bool, ++ bootloader: &Bootloader, + ) -> Result { +- let src_dir = openat::Dir::open(src_root) +- .with_context(|| format!("opening source directory {src_root}"))?; +- let Some(meta) = get_component_update(&src_dir, self)? else { +- anyhow::bail!("No update metadata for component {} found", self.name()); +- }; +- log::debug!("Found metadata {}", meta.version); +- let srcdir_name = component_updatedirname(self); +- let ft = crate::filetree::FileTree::new_from_dir(&src_dir.sub_dir(&srcdir_name)?)?; +- + // Let's attempt to use an already mounted ESP at the target + // dest_root if one is already mounted there in a known ESP location. + let destpath = if let Some(destdir) = self.get_mounted_esp(Path::new(dest_root))? { +@@ -393,6 +389,33 @@ impl Component for Efi { + self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device))? + }; + ++ match bootloader { ++ #[cfg(feature = "systemd-boot")] ++ Bootloader::SystemdBoot => { ++ log::info!("Installing systemd-boot via bootctl"); ++ let esp_dir = openat::Dir::open(&destpath)?; ++ crate::systemdbootconfigs::install(src_root, &esp_dir)?; ++ return Ok(InstalledContent { ++ meta: ContentMetadata { ++ timestamp: Utc::now(), ++ version: "systemd-boot".to_string(), ++ }, ++ filetree: None, ++ adopted_from: None, ++ }); ++ } ++ _ => {} ++ } ++ ++ let src_dir = openat::Dir::open(src_root) ++ .with_context(|| format!("opening source directory {src_root}"))?; ++ let Some(meta) = get_component_update(&src_dir, self)? else { ++ anyhow::bail!("No update metadata for component {} found", self.name()); ++ }; ++ log::debug!("Found metadata {}", meta.version); ++ let srcdir_name = component_updatedirname(self); ++ let ft = crate::filetree::FileTree::new_from_dir(&src_dir.sub_dir(&srcdir_name)?)?; ++ + let destd = &openat::Dir::open(&destpath) + .with_context(|| format!("opening dest dir {}", destpath.display()))?; + validate_esp_fstype(destd)?; +diff --git a/src/main.rs b/src/main.rs +index 5554366..53daad2 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -48,6 +48,9 @@ mod packagesystem; + mod sha512string; + mod util; + ++#[cfg(feature = "systemd-boot")] ++mod systemdbootconfigs; ++ + use clap::crate_name; + + /// Binary entrypoint, for both daemon and client logic. +diff --git a/src/systemdbootconfigs.rs b/src/systemdbootconfigs.rs +new file mode 100644 +index 0000000..9fe063d +--- /dev/null ++++ b/src/systemdbootconfigs.rs +@@ -0,0 +1,61 @@ ++use std::path::Path; ++ ++use anyhow::{Context, Result}; ++use fn_error_context::context; ++ ++const CONFIG_DIR: &str = "usr/lib/bootupd/systemd-boot"; ++ ++/// Install files required for systemd-boot ++/// This mostly proxies the bootctl install command ++#[context("Installing systemd-boot")] ++pub(crate) fn install(src_root: &openat::Dir, esp_path: &openat::Dir) -> Result<()> { ++ let esp_path_buf = esp_path.recover_path().context("ESP path is not valid")?; ++ let esp_path_str = esp_path_buf ++ .to_str() ++ .context("ESP path is not valid UTF-8")?; ++ let status = std::process::Command::new("bootctl") ++ .args(["install", "--esp-path", esp_path_str]) ++ .status() ++ .context("Failed to execute bootctl")?; ++ ++ if !status.success() { ++ anyhow::bail!( ++ "bootctl install failed with status code {}", ++ status.code().unwrap_or(-1) ++ ); ++ } ++ ++ // If loader.conf is present in the bootupd configuration, replace the original config with it ++ let configdir_path = Path::new(CONFIG_DIR); ++ if let Err(e) = try_copy_loader_conf(src_root, configdir_path, esp_path_str) { ++ log::debug!("Optional loader.conf copy skipped: {}", e); ++ } ++ ++ Ok(()) ++} ++ ++/// Try to copy loader.conf from configdir to ESP, returns error if not present or copy fails ++fn try_copy_loader_conf( ++ src_root: &openat::Dir, ++ configdir_path: &Path, ++ esp_path_str: &str, ++) -> Result<()> { ++ let configdir = src_root ++ .sub_dir(configdir_path) ++ .context(format!("Config directory '{}' not found", CONFIG_DIR))?; ++ let dst_loader_conf = Path::new(esp_path_str).join("loader/loader.conf"); ++ match configdir.open_file("loader.conf") { ++ Ok(mut src_file) => { ++ let mut dst_file = std::fs::File::create(&dst_loader_conf) ++ .context("Failed to create loader.conf in ESP")?; ++ std::io::copy(&mut src_file, &mut dst_file) ++ .context("Failed to copy loader.conf to ESP")?; ++ log::info!("loader.conf copied to {}", dst_loader_conf.display()); ++ Ok(()) ++ } ++ Err(e) => { ++ log::debug!("loader.conf not found in configdir, skipping: {}", e); ++ Err(anyhow::anyhow!(e)) ++ } ++ } ++} +-- +2.51.0 + From 905d2955afa880d1c73c54e9e4244f3f4d70b5b2 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 15:49:53 -0600 Subject: [PATCH 04/12] chore: Drop systemd and pefile These are available in Wolfi. Diffing our systemd with upstream, I don't see anything that stands out other than we've split systemd-measure into a separate package. Ideally, we'd try to contribute anything like that upstream Signed-off-by: RJ Sampson --- Justfile | 2 - manifests/kernel-uki.yaml | 5 +- manifests/py3-pefile.yaml | 79 ---- manifests/systemd.yaml | 819 -------------------------------------- 4 files changed, 2 insertions(+), 903 deletions(-) delete mode 100644 manifests/py3-pefile.yaml delete mode 100644 manifests/systemd.yaml diff --git a/Justfile b/Justfile index 52e30f7..349559a 100644 --- a/Justfile +++ b/Justfile @@ -46,8 +46,6 @@ build-tree: just build composefs-rs just build dracut - just build py3-pefile - just build systemd just build kernel just build kernel-initramfs just build kernel-uki diff --git a/manifests/kernel-uki.yaml b/manifests/kernel-uki.yaml index 793dc06..da4f11e 100644 --- a/manifests/kernel-uki.yaml +++ b/manifests/kernel-uki.yaml @@ -3,7 +3,7 @@ package: name: kernel-uki version: 6.15.6 - epoch: 1 + epoch: 2 description: Unified Kernel Image (UKI) for the Linux kernel target-architecture: - x86_64 @@ -23,9 +23,8 @@ environment: - kernel - kernel-modules - kernel-initramfs + - systemd - systemd-ukify - - systemd-uki-tools - - systemd-measure - python3 - dracut - kmod diff --git a/manifests/py3-pefile.yaml b/manifests/py3-pefile.yaml deleted file mode 100644 index 8457394..0000000 --- a/manifests/py3-pefile.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/chainguard-dev/melange/refs/heads/main/pkg/config/schema.json - -package: - name: py3-pefile - version: "2024.8.26" - epoch: 0 - description: Python module to read and work with PE (Portable Executable) files - copyright: - - license: MIT - dependencies: - provider-priority: 0 - -environment: - contents: - packages: - - build-base - - busybox - - py3-supported-flit-core - - py3-supported-pip - - py3-supported-python - - py3-supported-setuptools - - py3-supported-wheel - -vars: - pypi-package: pefile - -data: - - name: py-versions - items: - 3.10: "310" - 3.11: "311" - 3.12: "312" - 3.13: "313" - -pipeline: - - uses: fetch - with: - uri: https://files.pythonhosted.org/packages/source/p/pefile/pefile-${{package.version}}.tar.gz - expected-sha512: 62781f2ab84040a13304ce550dd1e943991df152c5f2951281906e837b1659694051a074ff49cd08d5d508e9b70009b56418a4237511c4464c4eba9bda4bccf7 - -subpackages: - - range: py-versions - name: py${{range.key}}-${{vars.pypi-package}} - description: ${{vars.pypi-package}} installed for python${{range.key}} - dependencies: - runtime: - - py${{range.key}}-future - provides: - - py3-${{vars.pypi-package}} - provider-priority: ${{range.value}} - pipeline: - - uses: py/pip-build-install - with: - python: python${{range.key}} - - runs: | - docdir="/usr/share/doc/${{package.name}}" - mkdir -p "$docdir" - cp -R docs "$docdir"/ || true - install -m 644 -D LICENSE /usr/share/licenses/${{package.name}}/LICENSE - - uses: strip - test: - pipeline: - - uses: python/import - with: - python: python${{range.key}} - import: ${{vars.pypi-package}} - - - name: py3-supported-${{vars.pypi-package}} - description: meta package providing ${{vars.pypi-package}} for supported python versions. - dependencies: - runtime: - - py3.10-${{vars.pypi-package}} - - py3.11-${{vars.pypi-package}} - - py3.12-${{vars.pypi-package}} - - py3.13-${{vars.pypi-package}} -# update: -# enabled: true -# release-monitor: -# identifier: 5933 # Replace with actual pefile release monitor ID if available diff --git a/manifests/systemd.yaml b/manifests/systemd.yaml deleted file mode 100644 index a94cf17..0000000 --- a/manifests/systemd.yaml +++ /dev/null @@ -1,819 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/chainguard-dev/melange/refs/heads/main/pkg/config/schema.json - -package: - name: systemd - version: "257.8" - epoch: 1 - description: The systemd System and Service Manager - copyright: - - license: LGPL-2.1-or-later AND GPL-2.0-or-later - resources: - cpu: 4 - memory: 12Gi - dependencies: - runtime: - - dbus - - kmod - - merged-lib - - merged-sbin - - merged-usrsbin - - quota-tools - - systemd-boot - - wolfi-baselayout - -vars: - llvm-vers: 19 - -data: - - name: standalone-binaries - items: - "systemd-repart": "systemd-repart.standalone" - "systemd-sysusers": "systemd-sysusers.standalone" - "systemd-tmpfiles": "systemd-tmpfiles.standalone" - - - name: filesystems - items: - "ext4": "ext4" - "xfs": "xfs" - -environment: - contents: - packages: - - acl-dev - - audit-dev - - bpftool - - build-base - - ca-certificates-bundle - - clang-${{vars.llvm-vers}} - - cmake - - coreutils - - cryptsetup-dev - - curl-dev - - dbus-dev - - findutils - - gnutar - - gperf - - iptables-dev - - kmod - - kmod-dev - - libarchive-dev - - libbpf - - libbpf-dev - - libcap-dev - - libgcrypt-dev - - libgpg-error-dev - - libidn2-dev - - libmicrohttpd-dev - - libmount - - libseccomp-dev - - libuuid - - libxslt - - linux-headers - - linux-pam-dev - - llvm-${{vars.llvm-vers}} - - meson - - ninja - - openssf-compiler-options - - pcre2-dev - - posix-libc-utils - - py3-jinja2 - - py3-pyelftools - - py3-pefile - - python3 - - quota-tools - - rsync - - tpm2-tss - - util-linux-dev - - valgrind-dev - - xz-dev - -pipeline: - - uses: git-checkout - with: - repository: https://github.com/systemd/systemd - tag: v${{package.version}} - expected-commit: 5e38d199a623563698ab4a69acbbe3afa9135198 - - - uses: meson/configure - with: - opts: | - -Dmode=release \ - -Dvmspawn=enabled \ - -Dinstall-tests=true \ - -Dstandalone-binaries=true \ - -Dsplit-bin=false \ - -Ddefault-dnssec=no \ - -Dukify=enabled \ - -Defi=true - - - uses: meson/compile - - - uses: meson/install - - - runs: | - # We've never used init we don't intend to - rm ${{targets.destdir}}/usr/lib/systemd/system/rc-local.service - -subpackages: - - name: "systemd-test" - description: "Installable systemd-tests" - dependencies: - runtime: - - merged-sbin - - systemd - - systemd-container - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/tests ${{targets.subpkgdir}}/usr/lib/systemd - cd ${{targets.destdir}} - - find . -name '*test*' -print \ - | tar --xattrs '--xattrs-include=*' -pcz '--files-from=-' -f - \ - | tar --xattrs '--xattrs-include=*' -xzf - -C /home/build/melange-out/systemd-test - - find . -name '*test*' -exec rm -f '{}' \; - - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - test: - environment: - contents: - packages: - - bash - - coreutils - - findutils - - python3 - - tzdata - - busybox - - tpm2-tss - - libidn2 # There's a lot of dlopen tests - - libbpf - - libzstd1 - - libarchive - - kmod-libs - pipeline: - - runs: | - mkdir -p /var/tmp/ - # Skipping tests: - # test-execute - won't work in qemu until we have caps, bwrap and docker already skip this - # test-namespace - won't work in qemu until we have caps, bwrap and docker already skip this - # test-bpf-foreign-programs - won't work in qemu, bwrap and docker already skip this - # test-sd-device - but got the following error: No such device - # test-path-util - failed at src/test/test-path-util.c:385, function test_find_executable_full(). Aborting. - # test-label - Error occurred while opening directory =>: Read-only file system - # test-dns-domain - Assertion 'r >= expected' failed at src/test/test-dns-domain.c:782, function test_dns_name_apply_idna_one(). Aborting. - # test-compress-benchmark - failed at src/test/test-compress-benchmark.c:105, function test_compress_decompress(). Aborting. - # test-capability - but got error: Protocol error - # test-bcd - >= 0' failed at src/boot/test-bcd.c:19, function load_bcd(). - # test-tpm2 - none setup in the test env. - # test-fd-util - Failed to fork off '(caf-noproc)': Operation not permitted - # test-fstab-generator - lots of set -x seems to fail messing with mounts? - # 2025/03/28 11:52:30 INFO Assertion 'mkdtemp_malloc("/tmp/test-rm-rf.XXXXXXX", &d) >= 0' failed at src/test/test-rm-rf.c:19, function test_rm_rf_chmod_inner(). Aborting. - # 2025/03/28 11:52:30 INFO (setresuid) terminated by signal ABRT. - # 2025/03/28 11:52:30 INFO Assertion 'r >= 0' failed at src/test/test-rm-rf.c:100, function test_rm_rf_chmod(). Aborting. - /usr/lib/systemd/tests/run-unit-tests.py -u \ - -s test-sd-device \ - -s test-path-util \ - -s test-label \ - -s test-dns-domain \ - -s test-compress-benchmark \ - -s test-capability \ - -s test-bcd \ - -s test-tpm2 \ - -s test-fd-util \ - -s test-fstab-generator.sh \ - -s test-rm-rf \ - -s test-namespace \ - -s test-mount-util \ - -s test-bpf-foreign-programs \ - -s test-execute - - - range: standalone-binaries - name: ${{range.key}}-standalone - description: Standalone version of ${{range.key}} - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin - mv ${{targets.destdir}}/usr/bin/${{range.value}} ${{targets.subpkgdir}}/usr/bin/${{range.key}} - test: - pipeline: - - runs: | - ${{range.key}} --help - ${{range.key}} --version - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: systemd-ukify - description: "Unified Kernel Image (UKI) builder" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin - mv ${{targets.destdir}}/usr/bin/ukify ${{targets.subpkgdir}}/usr/bin/ukify - test: - pipeline: - - runs: | - ukify --help - ukify --version - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - python3 - - py3-pefile - - - name: systemd-uki-tools - description: "Unified Kernel Image (UKI) tools" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/boot/efi - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/linuxx64.efi.stub ${{targets.subpkgdir}}/usr/lib/systemd/boot/efi/linuxx64.efi.stub - - - name: systemd-measure - description: "Pre-calculate and sign expected TPM2 PCR 11 values for booted unified kernel images" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/systemd-measure ${{targets.subpkgdir}}/usr/lib/systemd/systemd-measure - - - name: systemd-shutdown-standalone - description: Standalone version of ${{range.key}} - # Can't test this with --version because the binary checks the pid before anything else - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/systemd-shutdown.standalone ${{targets.subpkgdir}}/usr/lib/systemd/systemd-shutdown - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-dev" - description: "headers for systemd" - dependencies: - runtime: - - libudev - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - uses: split/dev - test: - pipeline: - - uses: test/pkgconf - - - name: "libudev" - description: "udev library" - dependencies: - provider-priority: 10 - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - mv ${{targets.destdir}}/usr/lib/libudev.so.* ${{targets.subpkgdir}}/usr/lib - test: - pipeline: - - uses: test/tw/ldd-check - - - name: "libsystemd" - description: "systemd library" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - mv ${{targets.destdir}}/usr/lib/libsystemd.so.* ${{targets.subpkgdir}}/usr/lib - test: - pipeline: - - uses: test/tw/ldd-check - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "libsystemd-shared" - description: "systemd library" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - cp ${{targets.destdir}}/usr/lib/systemd/libsystemd-shared-*.so ${{targets.subpkgdir}}/usr/lib/ - test: - pipeline: - - uses: test/tw/ldd-check - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-boot-installed" - description: "systemd bootloader (installed for EFI)" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/ - - if: ${{build.arch}} == 'aarch64' - runs: | - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/systemd-bootaa64.efi ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/BOOTAA64.EFI - - if: ${{build.arch}} == 'x86_64' - runs: | - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/BOOTX64.EFI - test: - environment: - contents: - packages: - - file - - grep - pipeline: - - if: ${{build.arch}} == 'aarch64' - runs: | - file /boot/efi/EFI/BOOT/BOOTAA64.EFI | grep "executable for EFI" - - if: ${{build.arch}} == 'x86_64' - runs: | - file /boot/efi/EFI/BOOT/BOOTX64.EFI | grep "executable for EFI" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-boot" - description: "systemd bootloader" - dependencies: - runtime: - - libsystemd-shared - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/etc/ - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/kernel/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system-generators/ - mv ${{targets.destdir}}/etc/kernel ${{targets.subpkgdir}}/etc/ - mv ${{targets.destdir}}/usr/bin/kernel-install ${{targets.subpkgdir}}/usr/bin/ - mv ${{targets.destdir}}/usr/bin/bootctl ${{targets.subpkgdir}}/usr/bin/ - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-boot-update.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/kernel ${{targets.subpkgdir}}/usr/lib/ - mv ${{targets.destdir}}/usr/lib/systemd/boot ${{targets.subpkgdir}}/usr/lib/systemd/ - mv ${{targets.destdir}}/usr/lib/systemd/systemd-bless-boot ${{targets.subpkgdir}}/usr/lib/systemd/ - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-bless-boot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system-generators/systemd-bless-boot-generator ${{targets.subpkgdir}}/usr/lib/systemd/system-generators/ - test: - pipeline: - - uses: test/verify-service - - runs: | - bootctl --version - bootctl --help - kernel-install --version - kernel-install --help - - - name: systemd-container - description: "systemd container tools" - dependencies: - runtime: - - gnutar - - merged-lib - - merged-sbin - - merged-usrsbin - - systemd - - wolfi-baselayout - pipeline: - - runs: | - # Move machine, vm/nspawn, import, export and portable components - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}} - - find . -name '*machine*' \ - -not -name 'systemd-machine-id*' \ - -not -name 'sysinit.target.wants' \ - -not -name 'sysinit.target.wants' \ - -not -name 'systemd-pcr*.service' \ - -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*nspawn*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*vmspawn*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*import*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*export*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*portable*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - - # Remove those files from the main package - find . -name '*machine*' -not -name 'systemd-machine-id*' -exec rm -f '{}' \; - - find . -name '*nspawn*' -exec rm -f '{}' \; - find . -name '*vmspawn*' -exec rm -f '{}' \; - find . -name '*import*' -exec rm -f '{}' \; - find . -name '*export*' -exec rm -f '{}' \; - find . -name '*portable*' -exec rm -f '{}' \; - find . -name '*portable*' -type d -exec rmdir '{}' \; - - # Misc utilties - mv usr/lib/systemd/systemd-pull ${{targets.subpkgdir}}/usr/lib/systemd/ - mv usr/bin/systemd-dissect ${{targets.subpkgdir}}/usr/bin/ - test: - environment: - contents: - # without openssl-provider-legacy import errors referencing CRYPTOGRAPHY_OPENSSL_NO_LEGACY - packages: - - curl - - gnutar - pipeline: - - uses: test/verify-service - - runs: | - machinectl --help - machinectl --version - portablectl --version - portablectl --help - systemd-dissect --help - systemd-dissect --version - systemd-nspawn --help - systemd-nspawn --version - systemd-vmspawn --help - systemd-vmspawn --version - /usr/lib/systemd/systemd-export --help - /usr/lib/systemd/systemd-export --version - /usr/lib/systemd/systemd-import --help - /usr/lib/systemd/systemd-import --version - /usr/lib/systemd/systemd-import-fs --help - /usr/lib/systemd/systemd-import-fs --version - /usr/lib/systemd/systemd-importd --help - /usr/lib/systemd/systemd-importd --version - /usr/lib/systemd/systemd-machined --help - /usr/lib/systemd/systemd-machined --version - /usr/lib/systemd/systemd-portabled --help - /usr/lib/systemd/systemd-portabled --version - /usr/lib/systemd/systemd-pull --help - /usr/lib/systemd/systemd-pull --version - - runs: | - # Run a pull command - SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-pull tar https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.2-x86_64.tar.gz test --verify=checksum --verify=checksum --direct --force - - # ensure it exists - # - # # test if it works - ls -la /var/lib/machines/test - - - name: "udev" - description: "/dev hotplug management daemon" - dependencies: - runtime: - - libsystemd-shared - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}} - find . -name '*udev*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - find . -name '*systemd-hwdb*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*udev*' -exec rm -f {} \; - find . -name '*systemd-hwdb*' -exec rm -f {} \; - test: - pipeline: - - uses: test/verify-service - - runs: | - systemd-hwdb --version - systemd-hwdb --help - udevadm --help - udevadm --version - - name: Systemd-hwdb checks - runs: | - systemd-hwdb update -s - - EXPECTED=$(cat < "${{targets.subpkgdir}}/etc/machine-id" - test: - pipeline: - - runs: | - [ -f /usr/bin/init -a -x /usr/bin/init ] - grep "uninitialized" /etc/machine-id - - - name: "systemd-default-network" - description: "Configure network to DHCP on default interfaces" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/20-eth.network ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/21-enp.network ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/22-end.network ${{targets.subpkgdir}}/etc/systemd/network/ - - - name: "systemd-logind-service" - description: "Logind service" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/multi-user.target.wants - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-logind.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system/dbus-org.freedesktop.login1.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system/multi-user.target.wants/systemd-logind.service ${{targets.subpkgdir}}/usr/lib/systemd/system/multi-user.target.wants/ - mv ${{targets.destdir}}/usr/lib/systemd/systemd-logind ${{targets.subpkgdir}}/usr/lib/systemd/ - test: - pipeline: - - uses: test/verify-service - - - name: "systemd-logind-stub" - description: "Fake login service to boot directly into a shell" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - cp ${{targets.destdir}}/usr/lib/systemd/system/serial-getty@.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - sed -i "s|^ExecStart=.*agetty.*|ExecStart=-/bin/sh -l|" ${{targets.subpkgdir}}/usr/lib/systemd/system/serial-getty@.service - - - name: "systemd-firstboot" - description: "Initialize basic system settings on or before the first boot-up of a system" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - systemd-homed # systemd-homed-firstboot - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/sysinit.target.wants/ - mv ${{targets.destdir}}/usr/bin/systemd-firstboot ${{targets.subpkgdir}}/usr/bin/systemd-firstboot - mv ${{targets.destdir}}/usr/lib/systemd/system/sysinit.target.wants/systemd-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/sysinit.target.wants/systemd-firstboot.service - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/systemd-firstboot.service - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-homed-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/systemd-homed-firstboot.service - test: - pipeline: - - uses: test/verify-service - - name: "Check version" - runs: | - systemd-firstboot --version - systemd-firstboot --help - - - range: filesystems - name: systemd-repart-rootfs-${{range.key}} - description: "Config file to auto grow root ${{range.key}} filesystem" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/repart.d/ - cp files/50-root-${{range.key}}.conf ${{targets.subpkgdir}}/usr/lib/repart.d/50-root.conf - - - name: "systemd-homed" - description: "systemd-homed is a system service designed to manage home directories" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}}/etc/systemd - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - find . -name '*home*' -print | tar -pcz --files-from=- -f - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*home*' -exec rm -f '{}' \; - test: - pipeline: - - uses: test/verify-service - - runs: | - homectl --help - - - name: "systemd-userdb" - description: "dynamic user/group manager" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}}/etc/systemd - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - find . -name '*userdb*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - find . -name '*userdb*' -exec rm -f '{}' \; - test: - pipeline: - - uses: test/verify-service - - runs: | - userdbctl --help - -update: - enabled: true - github: - identifier: systemd/systemd - strip-prefix: v - -test: - environment: - contents: - packages: - - build-base - - systemd-dev - - libsystemd - pipeline: - - uses: test/verify-service - with: - skip-files: syslog.socket # intentionally shipped without a corresponding service - - name: "Check systemctl version" - runs: | - systemctl --version - busctl --version - busctl --help - coredumpctl --version - coredumpctl --help - hostnamectl --version - hostnamectl --help - journalctl --version - journalctl --help - localectl --version - localectl --help - loginctl --version - loginctl --help - networkctl --version - networkctl --help - oomctl --version - oomctl --help - resolvectl --version - resolvectl --help - run0 --version - run0 --help - systemctl --help - systemd-ac-power --version - systemd-ac-power --help - systemd-analyze --help - systemd-ask-password --version - systemd-ask-password --help - systemd-cat --version - systemd-cat --help - systemd-cgls --version - systemd-cgls --help - systemd-cgtop --version - systemd-cgtop --help - systemd-confext --version - systemd-confext --help - systemd-creds --version - systemd-creds --help - systemd-delta --version - systemd-delta --help - systemd-detect-virt --help - systemd-escape --version - systemd-escape --help - systemd-id128 --version - systemd-id128 --help - systemd-inhibit --version - systemd-inhibit --help - systemd-machine-id-setup --version - systemd-machine-id-setup --help - systemd-mount --version - systemd-mount --help - systemd-notify --version - systemd-notify --help - systemd-path --version - systemd-path --help - systemd-repart --version - systemd-repart --help - systemd-resolve --version - systemd-resolve --help - systemd-run --version - systemd-run --help - systemd-socket-activate --version - systemd-socket-activate --help - systemd-stdio-bridge --version - systemd-stdio-bridge --help - systemd-sysext --version - systemd-sysext --help - systemd-sysusers --version - systemd-sysusers --help - systemd-tmpfiles --version - systemd-tmpfiles --help - systemd-tty-ask-password-agent --version - systemd-tty-ask-password-agent --help - systemd-umount --version - systemd-umount --help - systemd-vpick --version - systemd-vpick --help - timedatectl --version - timedatectl --help - varlinkctl --version - varlinkctl --help - halt --help - init --help - poweroff --help - reboot --help - resolvconf --version - resolvconf --help - runlevel --help - shutdown --help - telinit --help - - name: "Check libsystemd" - runs: | - ldconfig -p | grep libsystemd.so - echo '#include - int main() { sd_bus *bus; return sd_bus_default_system(&bus); }' > test.c - cc test.c -lsystemd -o test_systemd - rm test.c test_systemd - - name: "Verify stanalone binaries removed" - runs: | - STANDALONE_BINARIES=$(find /usr -name '*.standalone' ) - test -z "${STANDALONE_BINARIES}" From 3dfd5b9919e7a7032fab75ab56223d758fcbcefc Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 16:42:15 -0600 Subject: [PATCH 05/12] chore(kernel): Update to 6.17.3 Signed-off-by: RJ Sampson --- manifests/kernel-initramfs.yaml | 4 ++-- manifests/kernel-uki.yaml | 4 ++-- manifests/kernel.yaml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/manifests/kernel-initramfs.yaml b/manifests/kernel-initramfs.yaml index 0dc06e5..b488cd3 100644 --- a/manifests/kernel-initramfs.yaml +++ b/manifests/kernel-initramfs.yaml @@ -2,8 +2,8 @@ package: name: kernel-initramfs - version: 6.15.6 - epoch: 1 + version: 6.17.3 + epoch: 0 description: The Linux kernel initramfs copyright: - license: GPL-2.0 diff --git a/manifests/kernel-uki.yaml b/manifests/kernel-uki.yaml index da4f11e..b819064 100644 --- a/manifests/kernel-uki.yaml +++ b/manifests/kernel-uki.yaml @@ -2,8 +2,8 @@ package: name: kernel-uki - version: 6.15.6 - epoch: 2 + version: 6.17.3 + epoch: 0 description: Unified Kernel Image (UKI) for the Linux kernel target-architecture: - x86_64 diff --git a/manifests/kernel.yaml b/manifests/kernel.yaml index 4748856..5b05b78 100644 --- a/manifests/kernel.yaml +++ b/manifests/kernel.yaml @@ -2,8 +2,8 @@ package: name: kernel - version: 6.15.6 - epoch: 2 + version: 6.17.3 + epoch: 0 description: The Linux kernel copyright: - license: GPL-2.0 @@ -40,7 +40,7 @@ pipeline: with: repository: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git tag: v${{package.version}} - expected-commit: 1562d948232546cfad45a1beddc70fe0c7b34950 + expected-commit: f4b756a52c29ce3909c06bba248acf31d1276597 - runs: mv config-${{build.arch}}* .config From 8bc835e52eb6ade44d02bbb5f6b40a054c49bfe4 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 16:43:29 -0600 Subject: [PATCH 06/12] chore: Remove now unused systemd files Signed-off-by: RJ Sampson --- manifests/systemd/files/20-eth.network | 4 ---- manifests/systemd/files/21-enp.network | 4 ---- manifests/systemd/files/22-end.network | 4 ---- manifests/systemd/files/50-root-ext4.conf | 3 --- manifests/systemd/files/50-root-xfs.conf | 3 --- 5 files changed, 18 deletions(-) delete mode 100644 manifests/systemd/files/20-eth.network delete mode 100644 manifests/systemd/files/21-enp.network delete mode 100644 manifests/systemd/files/22-end.network delete mode 100644 manifests/systemd/files/50-root-ext4.conf delete mode 100644 manifests/systemd/files/50-root-xfs.conf diff --git a/manifests/systemd/files/20-eth.network b/manifests/systemd/files/20-eth.network deleted file mode 100644 index 5be26f6..0000000 --- a/manifests/systemd/files/20-eth.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=eth* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/21-enp.network b/manifests/systemd/files/21-enp.network deleted file mode 100644 index 1698a51..0000000 --- a/manifests/systemd/files/21-enp.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=enp* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/22-end.network b/manifests/systemd/files/22-end.network deleted file mode 100644 index f2b0378..0000000 --- a/manifests/systemd/files/22-end.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=end* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/50-root-ext4.conf b/manifests/systemd/files/50-root-ext4.conf deleted file mode 100644 index a4dd0bc..0000000 --- a/manifests/systemd/files/50-root-ext4.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Partition] -Type=root -Format=ext4 diff --git a/manifests/systemd/files/50-root-xfs.conf b/manifests/systemd/files/50-root-xfs.conf deleted file mode 100644 index 8fe16ee..0000000 --- a/manifests/systemd/files/50-root-xfs.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Partition] -Type=root -Format=xfs From c0920bcac3329efcd5d802a312e2073831f614a1 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 17:19:48 -0600 Subject: [PATCH 07/12] fix(bootupd): Fix systemd boot patch Signed-off-by: RJ Sampson --- ...stemd-boot-via-config-and-build-flag.patch | 307 ------------------ .../0002-chore-move-logic-into-efi.rs.patch | 225 ------------- manifests/bootupd/systemd-boot.patch | 20 +- 3 files changed, 11 insertions(+), 541 deletions(-) delete mode 100644 manifests/bootupd/0001-feat-support-systemd-boot-via-config-and-build-flag.patch delete mode 100644 manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch diff --git a/manifests/bootupd/0001-feat-support-systemd-boot-via-config-and-build-flag.patch b/manifests/bootupd/0001-feat-support-systemd-boot-via-config-and-build-flag.patch deleted file mode 100644 index 2ebd7b1..0000000 --- a/manifests/bootupd/0001-feat-support-systemd-boot-via-config-and-build-flag.patch +++ /dev/null @@ -1,307 +0,0 @@ -From 3f8ee3228698592922d4764c25b77b5506492940 Mon Sep 17 00:00:00 2001 -From: Robert Sturla -Date: Wed, 20 Aug 2025 17:09:23 +0100 -Subject: [PATCH] feat: support systemd-boot via config and build flag - ---- - Cargo.toml | 13 +++++++- - src/bootupd.rs | 62 +++++++++++++++++++++++++++++++++++---- - src/cli/bootupd.rs | 21 +++++++++++-- - src/efi.rs | 20 +++++++++++-- - src/main.rs | 2 ++ - src/systemdbootconfigs.rs | 42 ++++++++++++++++++++++++++ - 6 files changed, 149 insertions(+), 11 deletions(-) - create mode 100644 src/systemdbootconfigs.rs - -diff --git a/Cargo.toml b/Cargo.toml -index c3208f8..02b53c2 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -15,6 +15,10 @@ include = ["src", "LICENSE", "Makefile", "systemd"] - platforms = ["*-unknown-linux-gnu"] - tier = "2" - -+[features] -+default = [] -+systemd-boot = [] -+ - [[bin]] - name = "bootupd" - path = "src/main.rs" -@@ -27,7 +31,14 @@ bootc-internal-utils = "0.0.0" - cap-std-ext = "4.0.6" - camino = "1.1.11" - chrono = { version = "0.4.41", features = ["serde"] } --clap = { version = "4.5", default-features = false, features = ["cargo", "derive", "std", "help", "usage", "suggestions"] } -+clap = { version = "4.5", default-features = false, features = [ -+ "cargo", -+ "derive", -+ "std", -+ "help", -+ "usage", -+ "suggestions", -+] } - env_logger = "0.11" - fail = { version = "0.5", features = ["failpoints"] } - fn-error-context = "0.2.1" -diff --git a/src/bootupd.rs b/src/bootupd.rs -index 131548b..9ac7167 100644 ---- a/src/bootupd.rs -+++ b/src/bootupd.rs -@@ -25,6 +25,14 @@ use std::fs::{self, File}; - use std::io::{BufRead, BufReader, BufWriter, Write}; - use std::path::{Path, PathBuf}; - -+#[derive(Debug, Clone, Copy, PartialEq, Eq)] -+// TODO: Implement dynamic bootloader detection -+pub(crate) enum Bootloader { -+ _Auto, -+ Grub, -+ SystemdBoot, -+} -+ - pub(crate) enum ConfigMode { - None, - Static, -@@ -46,9 +54,10 @@ pub(crate) fn install( - dest_root: &str, - device: Option<&str>, - configs: ConfigMode, -- update_firmware: bool, -+ mut update_firmware: bool, - target_components: Option<&[String]>, - auto_components: bool, -+ bootloader: Bootloader, - ) -> Result<()> { - // TODO: Change this to an Option<&str>; though this probably balloons into having - // DeviceComponent and FileBasedComponent -@@ -93,15 +102,34 @@ pub(crate) fn install( - continue; - } - -+ // skip for BIOS if systemd-boot -+ if component.name() == "BIOS" && bootloader == Bootloader::SystemdBoot { -+ println!( -+ "Skip installing component {} for systemd-boot", -+ component.name() -+ ); -+ continue; -+ } -+ -+ if bootloader == Bootloader::SystemdBoot { -+ log::warn!( -+ "Disabling firmware updates for component {}", -+ component.name() -+ ); -+ update_firmware = false; -+ } - let meta = component - .install(&source_root, dest_root, device, update_firmware) - .with_context(|| format!("installing component {}", component.name()))?; - log::info!("Installed {} {}", component.name(), meta.meta.version); - state.installed.insert(component.name().into(), meta); -- // Yes this is a hack...the Component thing just turns out to be too generic. -- if let Some(vendor) = component.get_efi_vendor(&source_root)? { -- assert!(installed_efi_vendor.is_none()); -- installed_efi_vendor = Some(vendor); -+ -+ if bootloader != Bootloader::SystemdBoot { -+ // Yes this is a hack...the Component thing just turns out to be too generic. -+ if let Some(vendor) = component.get_efi_vendor(&source_root)? { -+ assert!(installed_efi_vendor.is_none()); -+ installed_efi_vendor = Some(vendor); -+ } - } - } - let sysroot = &openat::Dir::open(dest_root)?; -@@ -116,10 +144,32 @@ pub(crate) fn install( - target_arch = "powerpc64", - target_arch = "riscv64" - ))] -+ log::warn!("Configuring grub2 with uuid {uuid}"); - crate::grubconfigs::install(sysroot, installed_efi_vendor.as_deref(), uuid)?; - // On other architectures, assume that there's nothing to do. - } -- None => {} -+ None => { -+ log::info!("Skipping static config generation"); -+ } -+ } -+ -+ // Configure systemd-boot -+ // #[cfg(feature = "systemd-boot")] -+ if bootloader == Bootloader::SystemdBoot { -+ let efi = crate::efi::Efi::default(); -+ log::info!("Installing systemd-boot"); -+ // Use dest_root/boot as the root for ESP detection, matching conventions elsewhere -+ let boot_root = Path::new(dest_root).join("boot"); -+ let esp_device = crate::blockdev::get_esp_partition(device)? -+ .ok_or_else(|| anyhow!("No ESP device found"))?; -+ let mnt = efi.ensure_mounted_esp(&boot_root, Path::new(&esp_device))?; -+ let esp_dir = openat::Dir::open(&mnt).context("Opening mounted ESP directory")?; -+ crate::systemdbootconfigs::install(&esp_dir)?; -+ } else { -+ anyhow::bail!( -+ "Failed to find mounted ESP for systemd-boot installation in {:?}.", -+ Path::new(dest_root).join("boot") -+ ); - } - - // Unmount the ESP, etc. -diff --git a/src/cli/bootupd.rs b/src/cli/bootupd.rs -index 4a6b8cf..fe21ba4 100644 ---- a/src/cli/bootupd.rs -+++ b/src/cli/bootupd.rs -@@ -1,4 +1,4 @@ --use crate::bootupd::{self, ConfigMode}; -+use crate::bootupd::{self, Bootloader, ConfigMode}; - use anyhow::{Context, Result}; - use clap::Parser; - use log::LevelFilter; -@@ -73,6 +73,12 @@ pub struct InstallOpts { - /// then only enable installation to the ESP. - #[clap(long)] - auto: bool, -+ -+ /// The bootloader to configure -+ /// -+ /// Defaults to Grub -+ #[clap(long, default_value = "grub")] -+ bootloader: String, - } - - #[derive(Debug, Parser)] -@@ -103,13 +109,23 @@ impl DCommand { - - /// Runner for `install` verb. - pub(crate) fn run_install(opts: InstallOpts) -> Result<()> { -- let configmode = if opts.write_uuid { -+ let bootloader = match opts.bootloader.as_str() { -+ "grub" => Bootloader::Grub, -+ "systemd-boot" => Bootloader::SystemdBoot, -+ _ => anyhow::bail!("Unknown bootloader: {}", opts.bootloader), -+ }; -+ -+ // If systemd-boot, always use ConfigMode::None -+ let configmode = if let Bootloader::SystemdBoot = bootloader { -+ ConfigMode::None -+ } else if opts.write_uuid { - ConfigMode::WithUUID - } else if opts.with_static_configs { - ConfigMode::Static - } else { - ConfigMode::None - }; -+ - bootupd::install( - &opts.src_root, - &opts.dest_root, -@@ -118,6 +134,7 @@ impl DCommand { - opts.update_firmware, - opts.components.as_deref(), - opts.auto, -+ bootloader, - ) - .context("boot data installation failed")?; - Ok(()) -diff --git a/src/efi.rs b/src/efi.rs -index 61de605..41352c5 100644 ---- a/src/efi.rs -+++ b/src/efi.rs -@@ -273,6 +273,7 @@ impl Component for Efi { - .context("Failed to backup GRUB config")?; - } - -+ log::warn!("Replacing grub.cfg in /boot/efi/EFI/{vendor} with static grub.cfg"); - grubconfigs::install(&sysroot, Some(&vendor), true)?; - // Synchronize the filesystem containing /boot/efi/EFI/{vendor} to disk. - fsfreeze_thaw_cycle(efidir.open_file(".")?)?; -@@ -343,8 +344,23 @@ impl Component for Efi { - device: &str, - update_firmware: bool, - ) -> Result { -- let Some(meta) = get_component_update(src_root, self)? else { -- anyhow::bail!("No update metadata for component {} found", self.name()); -+ let meta = match get_component_update(src_root, self)? { -+ Some(meta) => meta, -+ None => { -+ log::debug!( -+ "No update metadata for component {} found, continuing (systemd-boot case)", -+ self.name() -+ ); -+ // You may want to return a default InstalledContent or handle this case differently. -+ return Ok(InstalledContent { -+ meta: ContentMetadata { -+ timestamp: chrono::Utc::now(), -+ version: "systemd-boot".to_string(), -+ }, -+ filetree: None, -+ adopted_from: None, -+ }); -+ } - }; - log::debug!("Found metadata {}", meta.version); - let srcdir_name = component_updatedirname(self); -diff --git a/src/main.rs b/src/main.rs -index 5554366..c769a9e 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -46,6 +46,8 @@ mod model_legacy; - mod ostreeutil; - mod packagesystem; - mod sha512string; -+#[cfg(feature = "systemd-boot")] -+mod systemdbootconfigs; - mod util; - - use clap::crate_name; -diff --git a/src/systemdbootconfigs.rs b/src/systemdbootconfigs.rs -new file mode 100644 -index 0000000..a0bb7e8 ---- /dev/null -+++ b/src/systemdbootconfigs.rs -@@ -0,0 +1,42 @@ -+use std::path::Path; -+ -+use anyhow::{Context, Result}; -+use fn_error_context::context; -+ -+/// Install files required for systemd-boot -+#[context("Installing systemd-boot")] -+pub(crate) fn install(esp_path: &openat::Dir) -> Result<()> { -+ let esp_path = esp_path.recover_path().context("ESP path is not valid")?; -+ let status = std::process::Command::new("bootctl") -+ .args([ -+ "install", -+ "--esp-path", -+ esp_path.to_str().context("ESP path is not valid UTF-8")?, -+ ]) -+ .status() -+ .context("Failed to execute bootctl")?; -+ -+ if !status.success() { -+ anyhow::bail!( -+ "bootctl install failed with status code {}", -+ status.code().unwrap_or(-1) -+ ); -+ } -+ -+ // If loader.conf is present in the bootupd configuration, replace the original config with it -+ let src_loader_conf = "/usr/lib/bootupd/systemd-boot/loader.conf"; -+ let dst_loader_conf = Path::new(&esp_path).join("loader/loader.conf"); -+ if Path::new(src_loader_conf).exists() { -+ std::fs::copy(src_loader_conf, &dst_loader_conf) -+ .context("Failed to copy loader.conf to ESP")?; -+ log::info!( -+ "Copied {} to {}", -+ src_loader_conf, -+ dst_loader_conf.display() -+ ); -+ } else { -+ log::warn!("{} does not exist, skipping copy", src_loader_conf); -+ } -+ -+ Ok(()) -+} --- -2.50.1 diff --git a/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch b/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch deleted file mode 100644 index 385fbab..0000000 --- a/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 51e021993581d52a4ecdd5f531ec497d18da4058 Mon Sep 17 00:00:00 2001 -From: Robert Sturla -Date: Fri, 22 Aug 2025 10:09:04 +0100 -Subject: [PATCH 2/2] chore: move logic into efi.rs - ---- - Cargo.toml | 2 +- - src/bios.rs | 1 + - src/bootupd.rs | 21 +-------- - src/component.rs | 1 + - src/efi.rs | 111 +++++++++++++++++++++++++++-------------------- - 5 files changed, 68 insertions(+), 68 deletions(-) - -diff --git a/Cargo.toml b/Cargo.toml -index 02b53c2..6e1b162 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -16,7 +16,7 @@ platforms = ["*-unknown-linux-gnu"] - tier = "2" - - [features] --default = [] -+default = ["systemd-boot"] - systemd-boot = [] - - [[bin]] -diff --git a/src/bios.rs b/src/bios.rs -index 4b34c20..e84537d 100644 ---- a/src/bios.rs -+++ b/src/bios.rs -@@ -112,6 +112,7 @@ impl Component for Bios { - dest_root: &str, - device: &str, - _update_firmware: bool, -+ _bootloader: crate::bootupd::Bootloader, - ) -> Result { - let Some(meta) = get_component_update(src_root, self)? else { - anyhow::bail!("No update metadata for component {} found", self.name()); -diff --git a/src/bootupd.rs b/src/bootupd.rs -index 9ac7167..703edfd 100644 ---- a/src/bootupd.rs -+++ b/src/bootupd.rs -@@ -119,7 +119,7 @@ pub(crate) fn install( - update_firmware = false; - } - let meta = component -- .install(&source_root, dest_root, device, update_firmware) -+ .install(&source_root, dest_root, device, update_firmware, bootloader) - .with_context(|| format!("installing component {}", component.name()))?; - log::info!("Installed {} {}", component.name(), meta.meta.version); - state.installed.insert(component.name().into(), meta); -@@ -153,24 +153,7 @@ pub(crate) fn install( - } - } - -- // Configure systemd-boot -- // #[cfg(feature = "systemd-boot")] -- if bootloader == Bootloader::SystemdBoot { -- let efi = crate::efi::Efi::default(); -- log::info!("Installing systemd-boot"); -- // Use dest_root/boot as the root for ESP detection, matching conventions elsewhere -- let boot_root = Path::new(dest_root).join("boot"); -- let esp_device = crate::blockdev::get_esp_partition(device)? -- .ok_or_else(|| anyhow!("No ESP device found"))?; -- let mnt = efi.ensure_mounted_esp(&boot_root, Path::new(&esp_device))?; -- let esp_dir = openat::Dir::open(&mnt).context("Opening mounted ESP directory")?; -- crate::systemdbootconfigs::install(&esp_dir)?; -- } else { -- anyhow::bail!( -- "Failed to find mounted ESP for systemd-boot installation in {:?}.", -- Path::new(dest_root).join("boot") -- ); -- } -+ // Systemd-boot installation is now handled by the EFI component's install method. - - // Unmount the ESP, etc. - drop(target_components); -diff --git a/src/component.rs b/src/component.rs -index 5ca32df..37b38c6 100644 ---- a/src/component.rs -+++ b/src/component.rs -@@ -55,6 +55,7 @@ pub(crate) trait Component { - dest_root: &str, - device: &str, - update_firmware: bool, -+ bootloader: crate::bootupd::Bootloader, - ) -> Result; - - /// Implementation of `bootupd generate-update-metadata` for a given component. -diff --git a/src/efi.rs b/src/efi.rs -index 41352c5..f59f8fe 100644 ---- a/src/efi.rs -+++ b/src/efi.rs -@@ -343,66 +343,81 @@ impl Component for Efi { - dest_root: &str, - device: &str, - update_firmware: bool, -+ bootloader: crate::bootupd::Bootloader, - ) -> Result { -- let meta = match get_component_update(src_root, self)? { -- Some(meta) => meta, -- None => { -- log::debug!( -- "No update metadata for component {} found, continuing (systemd-boot case)", -- self.name() -- ); -- // You may want to return a default InstalledContent or handle this case differently. -- return Ok(InstalledContent { -+ let esp_path = self.get_mounted_esp(Path::new(dest_root))?.or_else(|| { -+ if device.is_empty() { -+ None -+ } else { -+ let esp_device = blockdev::get_esp_partition(device).ok().flatten()?; -+ self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device)) -+ .ok() -+ } -+ }); -+ -+ match bootloader { -+ crate::bootupd::Bootloader::SystemdBoot => { -+ log::info!("Installing systemd-boot via bootctl"); -+ let esp_dir = openat::Dir::open(esp_path.as_ref().ok_or_else(|| { -+ anyhow::anyhow!("No ESP mount found for systemd-boot install") -+ })?) -+ .context("Opening mounted ESP directory for systemd-boot")?; -+ crate::systemdbootconfigs::install(&esp_dir)?; -+ Ok(InstalledContent { - meta: ContentMetadata { - timestamp: chrono::Utc::now(), - version: "systemd-boot".to_string(), - }, - filetree: None, - adopted_from: None, -- }); -+ }) - } -- }; -- log::debug!("Found metadata {}", meta.version); -- let srcdir_name = component_updatedirname(self); -- let ft = crate::filetree::FileTree::new_from_dir(&src_root.sub_dir(&srcdir_name)?)?; -+ crate::bootupd::Bootloader::Grub | crate::bootupd::Bootloader::_Auto => { -+ let meta = match get_component_update(src_root, self)? { -+ Some(meta) => meta, -+ None => { -+ log::debug!( -+ "No update metadata for component {} found, continuing (GRUB case)", -+ self.name() -+ ); -+ return Ok(InstalledContent { -+ meta: ContentMetadata { -+ timestamp: chrono::Utc::now(), -+ version: "grub".to_string(), -+ }, -+ filetree: None, -+ adopted_from: None, -+ }); -+ } -+ }; -+ log::debug!("Found metadata {}", meta.version); -+ let srcdir_name = component_updatedirname(self); -+ let ft = crate::filetree::FileTree::new_from_dir(&src_root.sub_dir(&srcdir_name)?)?; - -- // Let's attempt to use an already mounted ESP at the target -- // dest_root if one is already mounted there in a known ESP location. -- let destpath = if let Some(destdir) = self.get_mounted_esp(Path::new(dest_root))? { -- destdir -- } else { -- // Using `blockdev` to find the partition instead of partlabel because -- // we know the target install toplevel device already. -- if device.is_empty() { -- anyhow::bail!("Device value not provided"); -- } -- let esp_device = blockdev::get_esp_partition(device)? -- .ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?; -- self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device))? -- }; -+ let destpath = esp_path -+ .ok_or_else(|| anyhow::anyhow!("No ESP mount found for GRUB install"))?; -+ let destd = &openat::Dir::open(&destpath) -+ .with_context(|| format!("opening dest dir {}", destpath.display()))?; -+ validate_esp_fstype(destd)?; - -- let destd = &openat::Dir::open(&destpath) -- .with_context(|| format!("opening dest dir {}", destpath.display()))?; -- validate_esp_fstype(destd)?; -- -- // TODO - add some sort of API that allows directly setting the working -- // directory to a file descriptor. -- std::process::Command::new("cp") -- .args(["-rp", "--reflink=auto"]) -- .arg(&srcdir_name) -- .arg(destpath) -- .current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd())) -- .run()?; -- if update_firmware { -- if let Some(vendordir) = self.get_efi_vendor(&src_root)? { -- self.update_firmware(device, destd, &vendordir)? -+ std::process::Command::new("cp") -+ .args(["-rp", "--reflink=auto"]) -+ .arg(&srcdir_name) -+ .arg(&destpath) -+ .current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd())) -+ .run()?; -+ if update_firmware { -+ if let Some(vendordir) = self.get_efi_vendor(&src_root)? { -+ self.update_firmware(device, destd, &vendordir)? -+ } -+ } -+ Ok(InstalledContent { -+ meta, -+ filetree: Some(ft), -+ adopted_from: None, -+ }) - } - } -- Ok(InstalledContent { -- meta, -- filetree: Some(ft), -- adopted_from: None, -- }) - } - - fn run_update( --- -2.50.1 diff --git a/manifests/bootupd/systemd-boot.patch b/manifests/bootupd/systemd-boot.patch index 6c01645..c5463f6 100644 --- a/manifests/bootupd/systemd-boot.patch +++ b/manifests/bootupd/systemd-boot.patch @@ -1,7 +1,7 @@ -From a3fa92bd737b1e96ebba653ca60014446029df1f Mon Sep 17 00:00:00 2001 +From b63c79c6fef604884323dd8580a3499649daf00d Mon Sep 17 00:00:00 2001 From: Robert Sturla Date: Fri, 29 Aug 2025 22:52:00 +0100 -Subject: [PATCH] feat: add systemd-boot support +Subject: [PATCH] [PATCH] feat: add systemd-boot support Signed-off-by: Robert Sturla Signed-off-by: RJ Sampson @@ -12,10 +12,10 @@ Signed-off-by: RJ Sampson src/bios.rs | 1 + src/bootupd.rs | 87 ++++++++++++++++++++++++++++++++++++--- src/component.rs | 1 + - src/efi.rs | 43 ++++++++++++++----- + src/efi.rs | 45 +++++++++++++++----- src/main.rs | 3 ++ src/systemdbootconfigs.rs | 61 +++++++++++++++++++++++++++ - 9 files changed, 208 insertions(+), 23 deletions(-) + 9 files changed, 210 insertions(+), 23 deletions(-) create mode 100644 build.rs create mode 100644 src/systemdbootconfigs.rs @@ -263,7 +263,7 @@ index 8c3ec3c..e3b752d 100644 /// Implementation of `bootupd generate-update-metadata` for a given component. diff --git a/src/efi.rs b/src/efi.rs -index 25d6ccd..f523273 100644 +index 25d6ccd..c96cedb 100644 --- a/src/efi.rs +++ b/src/efi.rs @@ -22,7 +22,7 @@ use rustix::{fd::AsFd, fd::BorrowedFd, fs::StatVfsMountFlags}; @@ -304,20 +304,24 @@ index 25d6ccd..f523273 100644 // Let's attempt to use an already mounted ESP at the target // dest_root if one is already mounted there in a known ESP location. let destpath = if let Some(destdir) = self.get_mounted_esp(Path::new(dest_root))? { -@@ -393,6 +389,33 @@ impl Component for Efi { +@@ -393,6 +389,35 @@ impl Component for Efi { self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device))? }; ++ let src_dir = openat::Dir::open(src_root) ++ .with_context(|| format!("opening source directory {src_root}"))?; ++ + match bootloader { + #[cfg(feature = "systemd-boot")] + Bootloader::SystemdBoot => { + log::info!("Installing systemd-boot via bootctl"); + let esp_dir = openat::Dir::open(&destpath)?; -+ crate::systemdbootconfigs::install(src_root, &esp_dir)?; ++ crate::systemdbootconfigs::install(&src_dir, &esp_dir)?; + return Ok(InstalledContent { + meta: ContentMetadata { + timestamp: Utc::now(), + version: "systemd-boot".to_string(), ++ versions: None, + }, + filetree: None, + adopted_from: None, @@ -326,8 +330,6 @@ index 25d6ccd..f523273 100644 + _ => {} + } + -+ let src_dir = openat::Dir::open(src_root) -+ .with_context(|| format!("opening source directory {src_root}"))?; + let Some(meta) = get_component_update(&src_dir, self)? else { + anyhow::bail!("No update metadata for component {} found", self.name()); + }; From a50662ea026bad88252c2caecc753acd4e2ceb54 Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 17:20:55 -0600 Subject: [PATCH 08/12] fix: Docker fixes Correctly set label, explicitly point to Containerfile Signed-off-by: RJ Sampson --- Containerfile | 2 +- Justfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Containerfile b/Containerfile index 6069e31..2d8d57c 100644 --- a/Containerfile +++ b/Containerfile @@ -65,4 +65,4 @@ RUN mkdir -p /boot /sysroot && \ RUN usermod -p '$6$AJv9RHlhEXO6Gpul$5fvVTZXeM0vC03xckTIjY8rdCofnkKSzvF5vEzXDKAby5p3qaOGTHDypVVxKsCE3CbZz7C3NXnbpITrEUvN/Y/' root # Necessary labels -LABEL containers.bootc 1 +LABEL containers.bootc=1 diff --git a/Justfile b/Justfile index 349559a..9dbef76 100644 --- a/Justfile +++ b/Justfile @@ -56,7 +56,7 @@ renovate: build-containerfile: sudo docker build \ - -t wolfi-bootc:latest . + -t wolfi-bootc:latest -f ./Containerfile . build-apko $yaml="apko.yaml" $tag="wolfi-bootc:latest": mkdir -p ./output/oci From 6d6b779ac5e5ed2fcf97525fac84e283e5aae5ea Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 17:27:04 -0600 Subject: [PATCH 09/12] fix: Revert to Podman Now I see why we need it... Signed-off-by: RJ Sampson --- Justfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Justfile b/Justfile index 9dbef76..16fbffe 100644 --- a/Justfile +++ b/Justfile @@ -20,7 +20,7 @@ create-cache-dir: mkdir -p ./.cache/workspace keygen *$ARGS: - docker run --rm -it -v "${PWD}:/work:Z" -w /work \ + podman run --rm -it -v "${PWD}:/work:Z" -w /work \ "${MELANGE_IMAGE}" \ keygen $ARGS @@ -55,8 +55,8 @@ renovate: GITHUB_COM_TOKEN=$(cat ~/.ssh/gh_renovate) LOG_LEVEL=${LOG_LEVEL:-debug} renovate --platform=local build-containerfile: - sudo docker build \ - -t wolfi-bootc:latest -f ./Containerfile . + sudo podman build \ + -t wolfi-bootc:latest . build-apko $yaml="apko.yaml" $tag="wolfi-bootc:latest": mkdir -p ./output/oci @@ -68,7 +68,7 @@ build-apko $yaml="apko.yaml" $tag="wolfi-bootc:latest": sudo skopeo copy oci:./output/oci/ containers-storage:${tag} bootc *ARGS: - sudo docker run \ + sudo podman run \ --rm --privileged --pid=host \ -it \ -v /sys/fs/selinux:/sys/fs/selinux \ From 3c30efda771c3bb8d156f4cac85bf00a2cab232f Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 18:09:29 -0600 Subject: [PATCH 10/12] chore(Containerfile): Use apk.cgr.dev/chainguard Signed-off-by: RJ Sampson --- Containerfile | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Containerfile b/Containerfile index 2d8d57c..3b0722c 100644 --- a/Containerfile +++ b/Containerfile @@ -4,11 +4,11 @@ COPY ./packages /packages FROM cgr.dev/chainguard/wolfi-base AS builder -RUN --mount=type=bind,from=ctx,source=/packages,target=/repo \ - apk add --allow-untrusted \ - -X /repo \ - -X https://packages.wolfi.dev/os \ - -U --initdb -p /mnt \ +RUN --mount=type=bind,from=ctx,source=/packages,target=/repo < Date: Sat, 18 Oct 2025 18:18:50 -0600 Subject: [PATCH 11/12] chore(ostree): Update to 2025.6 Signed-off-by: RJ Sampson --- manifests/ostree.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/ostree.yaml b/manifests/ostree.yaml index 885e3b3..1202e7a 100644 --- a/manifests/ostree.yaml +++ b/manifests/ostree.yaml @@ -1,6 +1,6 @@ package: name: ostree - version: "2025.4" + version: "2025.6" epoch: 0 description: "Operating system and container binary deployment and upgrades" copyright: @@ -28,7 +28,7 @@ pipeline: with: repository: https://github.com/ostreedev/ostree.git tag: v${{package.version}} - expected-commit: 1a9350c94395cf743fc43e715931998fd67c520b + expected-commit: 82185d9aaf0a79b100378f13a54c3d5d3763a971 - runs: env NOCONFIGURE=1 ./autogen.sh From ed6beb3a51050e4dfc2b7599701abea5f170b17f Mon Sep 17 00:00:00 2001 From: RJ Sampson Date: Sat, 18 Oct 2025 18:22:33 -0600 Subject: [PATCH 12/12] chore(composefs-rs): Update to latest commit Signed-off-by: RJ Sampson --- manifests/composefs-rs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/composefs-rs.yaml b/manifests/composefs-rs.yaml index f031053..7ebd2b1 100644 --- a/manifests/composefs-rs.yaml +++ b/manifests/composefs-rs.yaml @@ -1,6 +1,6 @@ package: name: composefs-rs - version: 0_git20250721 + version: 0_git20251018 epoch: 0 description: Boot and upgrade via container images copyright: @@ -16,7 +16,7 @@ pipeline: with: repository: https://github.com/containers/composefs-rs.git branch: main - expected-commit: 50991e3b00babaa867c594a6f0fb193b0684537e + expected-commit: f3cdb75924597ce9ffa1cc48d6e4e011e02f333d - uses: cargo/build with: