From 47e36a8c132ab8459217f3c9557a9ed3edf06ebb Mon Sep 17 00:00:00 2001 From: David Steele Date: Tue, 12 May 2026 08:58:39 +0100 Subject: [PATCH 1/3] fix: hint to run rpmoci update when build download fails When pinned packages are removed from a rolling repo (e.g. UBI9 only retains the latest package version), rpmoci build fails at download time with "Package could no longer be found in repositories". The error was correct but gave no guidance on how to resolve it. Add context to the lockfile.build() call so failures include a suggestion to run `rpmoci update` to regenerate the lock file. Fixes: DEVX-544 --- src/lib.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 09eff88..3338e20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,13 +161,18 @@ pub fn main(command: Command) -> anyhow::Result<()> { lockfile.write_to_file(lockfile_path)?; } - lockfile.build( - &cfg, - &image, - &tag, - vendor_dir.as_deref(), - label.into_iter().collect(), - )?; + lockfile + .build( + &cfg, + &image, + &tag, + vendor_dir.as_deref(), + label.into_iter().collect(), + ) + .context( + "If packages in the lock file are no longer available in the configured \ + repositories, run `rpmoci update` to regenerate it", + )?; let elapsed_time = now.elapsed(); write::ok( "Success", From 37e04ecb530428c6d42904398aab91d60310d0ef Mon Sep 17 00:00:00 2001 From: David Steele Date: Tue, 12 May 2026 09:24:40 +0100 Subject: [PATCH 2/3] Clippy fix --- src/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 86238ce..056665c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -120,10 +120,10 @@ impl Repository { } // If the repository is a definition, and has an id, return that - if let Repository::Definition(repo) = &self { - if let Some(repoid) = &repo.id { - return repoid.to_string(); - } + if let Repository::Definition(repo) = &self + && let Some(repoid) = &repo.id + { + return repoid.to_string(); } // The repository didn't have an id, so generate one from the url From 25ae744505c0bc1214b965c4ae565218b918bd29 Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 13 May 2026 13:38:34 +0100 Subject: [PATCH 3/3] feat: Add support for refreshing the lockfile when an unlocked build fails. Intended to resolve issues where a compatible lockfile is invalid due to upstream OS packages being removed. --- .github/workflows/ci.yml | 4 ++-- src/lib.rs | 32 ++++++++++++++++++++++++++---- tests/fixtures/ubi9/foo/oci-layout | 1 + tests/fixtures/ubi9/rpmoci.toml | 10 ++++++++++ tests/it.rs | 6 ++++++ 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/ubi9/foo/oci-layout create mode 100644 tests/fixtures/ubi9/rpmoci.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26d5ce4..7c23636 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,13 +46,13 @@ jobs: test-fedora: runs-on: ubuntu-24.04 container: - image: fedora:40 + image: fedora:44 options: --privileged steps: - name: Install dependencies run: | dnf install -y openssl-devel python3-devel sqlite-devel dnf-plugins-core util-linux rust cargo skopeo - dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo + dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo dnf install -y docker-ce-cli - uses: actions/checkout@v4 - name: Run tests diff --git a/src/lib.rs b/src/lib.rs index 3338e20..4b31a98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,21 +158,45 @@ pub fn main(command: Command) -> anyhow::Result<()> { }; if changed { - lockfile.write_to_file(lockfile_path)?; + lockfile.write_to_file(&lockfile_path)?; } - lockfile + match lockfile .build( &cfg, &image, &tag, vendor_dir.as_deref(), - label.into_iter().collect(), + label.clone().into_iter().collect(), ) .context( "If packages in the lock file are no longer available in the configured \ repositories, run `rpmoci update` to regenerate it", - )?; + ) { + Ok(()) => (), + Err(e) => { + // running unlocked with a compatible lockfile: packages may have been + // removed from the rolling repo, so attempt an auto-update and retry. + if lockfile.is_compatible_including_local_rpms(&cfg)? && !locked { + log::debug!( + "Build failed with a compatible lockfile, attempting auto-update and rebuild." + ); + let lockfile = Lockfile::resolve_from_config(&cfg)?; + lockfile.write_to_file(&lockfile_path)?; + lockfile.build( + &cfg, + &image, + &tag, + vendor_dir.as_deref(), + label.into_iter().collect(), + )?; + } else { + // locked or lockfile no longer matches config – bail with the + // hint already included in the error context. + bail!("Failed to build image: {e}."); + } + } + }; let elapsed_time = now.elapsed(); write::ok( "Success", diff --git a/tests/fixtures/ubi9/foo/oci-layout b/tests/fixtures/ubi9/foo/oci-layout new file mode 100644 index 0000000..1343d37 --- /dev/null +++ b/tests/fixtures/ubi9/foo/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion":"1.0.0"} \ No newline at end of file diff --git a/tests/fixtures/ubi9/rpmoci.toml b/tests/fixtures/ubi9/rpmoci.toml new file mode 100644 index 0000000..64b46a8 --- /dev/null +++ b/tests/fixtures/ubi9/rpmoci.toml @@ -0,0 +1,10 @@ +[contents] +packages = ["glibc"] + +[[contents.repositories]] +url = "https://cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/$basearch/baseos/os" +id = "ubi9-test" +options = { gpgcheck = "false" } + +[image] +cmd = ["/bin/bash"] diff --git a/tests/it.rs b/tests/it.rs index ac0d1df..75d2191 100644 --- a/tests/it.rs +++ b/tests/it.rs @@ -385,6 +385,12 @@ fn test_exclude() { build_and_run("exclude", false); } +#[cfg(feature = "test-docker")] +#[test] +fn test_auto_update_missing_package() { + build_and_run("ubi9", true); +} + fn build_and_run(image: &str, should_succeed: bool) -> std::process::Output { let (_tmp_dir, root) = setup_test(image); let status = rpmoci()