Skip to content

Commit 61de438

Browse files
committed
tests: Fall back to upstream registry when mirror is unavailable
The mirror-fixture-images.yml workflow only runs on pushes to main, so during the PR that adds a new entry to ci/fixture-images.txt the ghcr.io mirror does not yet exist. Without a fallback, the integration test would fail trying to pull from ghcr.io. Add an upstream_ref field to ContainerImage and teach pull_image() to try the mirror first, then warn and retry against the upstream registry if the mirror pull fails. Fill in upstream_ref for existing images (UBI10 and centos-bootc) so the struct is complete. Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 4dd43a1 commit 61de438

1 file changed

Lines changed: 44 additions & 2 deletions

File tree

crates/composefs-integration-tests/src/tests/digest_stability.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,17 @@ use crate::{cfsctl, integration_test};
99
struct ContainerImage {
1010
/// Human-readable label for test output.
1111
label: &'static str,
12-
/// OCI image reference (docker:// prefix).
12+
/// Primary OCI image reference — the ghcr.io mirror (docker:// prefix).
13+
///
14+
/// The mirror is populated by the `mirror-fixture-images.yml` workflow after
15+
/// a PR that adds a new entry to `ci/fixture-images.txt` is merged to main.
16+
/// During the PR itself the mirror does not exist yet, so the test falls back
17+
/// to `upstream_ref` when this pull fails.
1318
image_ref: &'static str,
19+
/// Upstream OCI image reference used as a fallback when `image_ref` is
20+
/// unavailable (e.g. a PR that adds a new mirror entry before it has been
21+
/// pushed). Should be pinned by digest for reproducibility.
22+
upstream_ref: &'static str,
1423
/// Expected composefs image ID without `--bootable`.
1524
expected_id: &'static str,
1625
/// Expected composefs image ID with `--bootable`, or `None` if the
@@ -25,6 +34,7 @@ struct ContainerImage {
2534
const UBI10: ContainerImage = ContainerImage {
2635
label: "ubi10",
2736
image_ref: "docker://ghcr.io/composefs/ci-fixture-ubi10:10.1-1772441712",
37+
upstream_ref: "docker://registry.access.redhat.com/ubi10/ubi:10.1-1772441712",
2838
expected_id: "ff8dad033a3e6015d63d6b00c16918da27bf96cc8ddd824e521549db01013227\
2939
87c30a3f49e5716f8f6052d78b46308dfaaccf0dfc504d26fe58d468810c0b0e",
3040
expected_bootable_id: None,
@@ -37,6 +47,7 @@ const UBI10: ContainerImage = ContainerImage {
3747
const CENTOS_BOOTC: ContainerImage = ContainerImage {
3848
label: "centos-bootc",
3949
image_ref: "docker://ghcr.io/composefs/ci-fixture-centos-bootc:stream10-d1913e3d",
50+
upstream_ref: "docker://quay.io/centos-bootc/centos-bootc@sha256:d1913e3d616b9acb7fc2e3331be8baf844048bca2681a23d34e53e75eb18f3d0",
4051
expected_id: "ad575e0570dfb74cbc837f41715d3fba890dd983d992332eaeee93493ce112ee\
4152
50d3dc5f6f2a3214cc92412fe3ae936e2e9c0eac24ea787e83ef13c0a718a193",
4253
expected_bootable_id: Some(
@@ -54,7 +65,38 @@ fn skip_network() -> bool {
5465
}
5566

5667
/// Pull an OCI image and return the config digest from the pull output.
68+
///
69+
/// Tries `image.image_ref` (the ghcr.io mirror) first. If that fails —
70+
/// which is expected for PRs that add a new mirror entry before it has been
71+
/// pushed — falls back to `image.upstream_ref` with a warning.
5772
fn pull_image(
73+
sh: &Shell,
74+
cfsctl: &std::path::Path,
75+
repo: &std::path::Path,
76+
image: &ContainerImage,
77+
name: &str,
78+
) -> Result<String> {
79+
let candidates = [(image.image_ref, false), (image.upstream_ref, true)];
80+
let mut last_err = None;
81+
for (image_ref, is_fallback) in candidates {
82+
if is_fallback {
83+
eprintln!(
84+
"WARNING: mirror pull failed for {}; falling back to upstream {image_ref}",
85+
image.label,
86+
);
87+
}
88+
match try_pull_image(sh, cfsctl, repo, image_ref, name) {
89+
Ok(config) => return Ok(config),
90+
Err(e) => {
91+
eprintln!("Pull of {image_ref} failed: {e:#}");
92+
last_err = Some(e);
93+
}
94+
}
95+
}
96+
Err(last_err.unwrap())
97+
}
98+
99+
fn try_pull_image(
58100
sh: &Shell,
59101
cfsctl: &std::path::Path,
60102
repo: &std::path::Path,
@@ -126,7 +168,7 @@ fn test_oci_container_digest_stability() -> Result<()> {
126168
cmd!(sh, "{cfsctl} --repo {repo} init --insecure").read()?;
127169

128170
eprintln!("Pulling {} (this may take a while)...", image.label);
129-
let config = pull_image(&sh, &cfsctl, repo, image.image_ref, image.label)?;
171+
let config = pull_image(&sh, &cfsctl, repo, image, image.label)?;
130172

131173
// Plain (non-bootable) image ID
132174
let plain_id = compute_id(&sh, &cfsctl, repo, &config, false)?;

0 commit comments

Comments
 (0)