diff --git a/cincinnati/src/plugins/internal/graph_builder/release_scrape_dockerv2/registry/mod.rs b/cincinnati/src/plugins/internal/graph_builder/release_scrape_dockerv2/registry/mod.rs index 4e151ec75..ab4c0df24 100644 --- a/cincinnati/src/plugins/internal/graph_builder/release_scrape_dockerv2/registry/mod.rs +++ b/cincinnati/src/plugins/internal/graph_builder/release_scrape_dockerv2/registry/mod.rs @@ -254,11 +254,14 @@ async fn get_manifest_layers( tag: String, repo: &str, registry_client: &Client, -) -> Result<(Option, String, Vec), Error> { +) -> Result<(Option, String, Vec, bool), Error> { trace!("[{}] Fetching release", tag); let (tag, manifest, manifestref) = get_manifest_and_ref(tag, repo.to_owned(), ®istry_client).await?; + // Check if manifest is a manifest list with a single arch + let is_manifest_list = matches!(&manifest, dkregistry::v2::manifest::Manifest::ML(_)); + // Try to read the architecture from the manifest let arch = match manifest.architectures() { Ok(archs) => { @@ -289,7 +292,7 @@ async fn get_manifest_layers( .rev() .collect(); - Ok((arch, manifestref, layers_digests)) + Ok((arch, manifestref, layers_digests, is_manifest_list)) } /// Fetches a vector of all release metadata from the given repository, hosted on the given @@ -333,7 +336,7 @@ pub async fn fetch_releases( let misses = cache_misses.clone(); async move { - let (arch, manifestref, mut layers_digests) = + let (arch, manifestref, mut layers_digests, is_manifest_list) = match get_manifest_layers(tag.to_owned(), &repo, ®istry_client).await { Ok(result) => result, Err(e) => { @@ -357,19 +360,41 @@ pub async fn fetch_releases( // if the image is multi arch, we will have to get one image from the manifest list and // use its metadata, because manifest lists are just collections of manifests and don't // have their own layers with metadata files. - if arch.as_ref().unwrap() == "multi" { - let digest = layers_digests - .first() - .map(std::string::ToString::to_string) - .expect( - format!("no images referenced in ManifestList ref:{}", manifestref) - .as_str(), - ); + if is_manifest_list { + let digest = match layers_digests.first() { + Some(d) => d.to_string(), + None => { + error!( + "no images referenced in ManifestList for {}:{} ref:{}", + &repo, &tag, &manifestref + ); + skip_releases.fetch_add(1, Ordering::SeqCst); + return Ok(()); + } + }; // TODO: destructured assignments are unstable in current rust, after updating rust // change this to (_,_,layers_digests) and remove separate assignment from below. - let (_ml_arch, _ml_manifestref, ml_layers_digests) = - get_manifest_layers(digest, &repo, ®istry_client).await?; - layers_digests = ml_layers_digests; + match get_manifest_layers(digest, &repo, ®istry_client).await { + Ok((_ml_arch, _ml_manifestref, ml_layers_digests, _ml_is_manifest_list)) => { + layers_digests = ml_layers_digests; + } + Err(e) => { + if tag.contains(".sig") { + debug!( + "encountered a signature for child manifest {}:{}: {}, ignoring this image", + &repo, &tag, e + ); + sig_releases.fetch_add(1, Ordering::SeqCst); + } else { + error!( + "fetching child manifest from ManifestList for {}:{}: {}", + &repo, &tag, e + ); + skip_releases.fetch_add(1, Ordering::SeqCst); + } + return Ok(()); + } + }; } let release = match lookup_or_fetch(