diff --git a/process/drivers.rs b/process/drivers.rs index 49d6167f..adc187e1 100644 --- a/process/drivers.rs +++ b/process/drivers.rs @@ -200,35 +200,30 @@ impl Driver { let _ = oci_ref; // silence lint if true { - return Ok(40); + return Ok(41); } } info!("Retrieving OS version from {oci_ref}"); - let inspect_opts = GetMetadataOpts::builder() - .image(format!( - "{}/{}", - oci_ref.resolve_registry(), - oci_ref.repository() - )) - .tag(oci_ref.tag().unwrap_or("latest")) - .platform(platform) - .build(); - - let os_version = Self::get_metadata(&inspect_opts) - .and_then(|inspection| { - inspection.get_version().ok_or_else(|| { - miette!( - "Failed to parse version from metadata for {}", - oci_ref.to_string().bold() - ) - }) + let os_version = Self::get_metadata( + &GetMetadataOpts::builder() + .image(oci_ref) + .platform(platform) + .build(), + ) + .and_then(|inspection| { + inspection.get_version().ok_or_else(|| { + miette!( + "Failed to parse version from metadata for {}", + oci_ref.to_string().bold() + ) }) - .or_else(|err| { - warn!("Unable to get version via image inspection due to error:\n{err:?}"); - get_version_run_image(oci_ref) - })?; + }) + .or_else(|err| { + warn!("Unable to get version via image inspection due to error:\n{err:?}"); + get_version_run_image(oci_ref) + })?; trace!("os_version: {os_version}"); Ok(os_version) } diff --git a/process/drivers/buildah_driver.rs b/process/drivers/buildah_driver.rs index d17dd62b..73c4b5dc 100644 --- a/process/drivers/buildah_driver.rs +++ b/process/drivers/buildah_driver.rs @@ -1,6 +1,7 @@ use std::{io::Write, process::Stdio}; use blue_build_utils::{cmd, credentials::Credentials}; +use colored::Colorize; use log::{debug, error, info, trace}; use miette::{bail, miette, IntoDiagnostic, Result}; use semver::Version; @@ -83,13 +84,20 @@ impl BuildDriver for BuildahDriver { fn tag(opts: &TagOpts) -> Result<()> { trace!("BuildahDriver::tag({opts:#?})"); - let mut command = cmd!("buildah", "tag", &*opts.src_image, &*opts.dest_image,); + let dest_image_str = opts.dest_image.to_string(); + + let mut command = cmd!( + "buildah", + "tag", + opts.src_image.to_string(), + &dest_image_str, + ); trace!("{command:?}"); if command.status().into_diagnostic()?.success() { - info!("Successfully tagged {}!", opts.dest_image); + info!("Successfully tagged {}!", dest_image_str.bold().green()); } else { - bail!("Failed to tag image {}", opts.dest_image); + bail!("Failed to tag image {}", dest_image_str.bold().red()); } Ok(()) } @@ -97,6 +105,8 @@ impl BuildDriver for BuildahDriver { fn push(opts: &PushOpts) -> Result<()> { trace!("BuildahDriver::push({opts:#?})"); + let image_str = opts.image.to_string(); + let command = cmd!( "buildah", "push", @@ -104,18 +114,18 @@ impl BuildDriver for BuildahDriver { "--compression-format={}", opts.compression_type.unwrap_or_default() ), - &*opts.image, + &image_str, ); trace!("{command:?}"); let status = command - .build_status(&opts.image, "Pushing Image") + .build_status(&image_str, "Pushing Image") .into_diagnostic()?; if status.success() { - info!("Successfully pushed {}!", opts.image); + info!("Successfully pushed {}!", image_str.bold().green()); } else { - bail!("Failed to push image {}", opts.image); + bail!("Failed to push image {}", image_str.bold().red()); } Ok(()) } diff --git a/process/drivers/cosign_driver.rs b/process/drivers/cosign_driver.rs index 0073a0d8..6b619ad0 100644 --- a/process/drivers/cosign_driver.rs +++ b/process/drivers/cosign_driver.rs @@ -5,6 +5,7 @@ use blue_build_utils::{ constants::{COSIGN_PASSWORD, COSIGN_PUB_PATH, COSIGN_YES}, credentials::Credentials, }; +use colored::Colorize; use log::{debug, trace}; use miette::{bail, miette, Context, IntoDiagnostic, Result}; @@ -121,27 +122,32 @@ impl SigningDriver for CosignDriver { } fn sign(opts: &SignOpts) -> Result<()> { - let image_digest: &str = opts.image.as_ref(); + if opts.image.digest().is_none() { + bail!( + "Image ref {} is not a digest ref", + opts.image.to_string().bold().red(), + ); + } + let mut command = cmd!( "cosign", "sign", if let Some(ref key) = opts.key => format!("--key={key}"), "--recursive", - image_digest, + opts.image.to_string(), COSIGN_PASSWORD => "", COSIGN_YES => "true", ); trace!("{command:?}"); if !command.status().into_diagnostic()?.success() { - bail!("Failed to sign {image_digest}"); + bail!("Failed to sign {}", opts.image.to_string().bold().red()); } Ok(()) } fn verify(opts: &VerifyOpts) -> Result<()> { - let image_name_tag: &str = opts.image.as_ref(); let mut command = cmd!( "cosign", "verify", @@ -157,12 +163,12 @@ impl SigningDriver for CosignDriver { ), }; }, - image_name_tag + opts.image.to_string(), ); trace!("{command:?}"); if !command.status().into_diagnostic()?.success() { - bail!("Failed to verify {image_name_tag}"); + bail!("Failed to verify {}", opts.image.to_string().bold().red()); } Ok(()) diff --git a/process/drivers/docker_driver.rs b/process/drivers/docker_driver.rs index 21d64a67..507baf0a 100644 --- a/process/drivers/docker_driver.rs +++ b/process/drivers/docker_driver.rs @@ -13,6 +13,7 @@ use blue_build_utils::{ string_vec, }; use cached::proc_macro::cached; +use colored::Colorize; use log::{debug, info, trace, warn}; use miette::{bail, miette, IntoDiagnostic, Result}; use once_cell::sync::Lazy; @@ -154,15 +155,17 @@ impl BuildDriver for DockerDriver { fn tag(opts: &TagOpts) -> Result<()> { trace!("DockerDriver::tag({opts:#?})"); + let dest_image_str = opts.dest_image.to_string(); + trace!("docker tag {} {}", opts.src_image, opts.dest_image); - let status = cmd!("docker", "tag", &*opts.src_image, &*opts.dest_image,) + let status = cmd!("docker", "tag", opts.src_image.to_string(), &dest_image_str) .status() .into_diagnostic()?; if status.success() { - info!("Successfully tagged {}!", opts.dest_image); + info!("Successfully tagged {}!", dest_image_str.bold().green()); } else { - bail!("Failed to tag image {}", opts.dest_image); + bail!("Failed to tag image {}", dest_image_str.bold().red()); } Ok(()) } @@ -170,15 +173,17 @@ impl BuildDriver for DockerDriver { fn push(opts: &PushOpts) -> Result<()> { trace!("DockerDriver::push({opts:#?})"); + let image_str = opts.image.to_string(); + trace!("docker push {}", opts.image); - let status = cmd!("docker", "push", &*opts.image) + let status = cmd!("docker", "push", &image_str) .status() .into_diagnostic()?; if status.success() { - info!("Successfully pushed {}!", opts.image); + info!("Successfully pushed {}!", image_str.bold().green()); } else { - bail!("Failed to push image {}", opts.image); + bail!("Failed to push image {}", image_str.bold().red()); } Ok(()) } @@ -315,18 +320,25 @@ impl BuildDriver for DockerDriver { ], ); - let final_images = match (opts.image.as_deref(), opts.archive_path.as_deref()) { + let final_images = match (opts.image, opts.archive_path.as_deref()) { (Some(image), None) => { let images = if opts.tags.is_empty() { - cmd!(command, "-t", image); + let image = image.to_string(); + cmd!(command, "-t", &image); string_vec![image] } else { opts.tags.iter().for_each(|tag| { - cmd!(command, "-t", format!("{image}:{tag}")); + cmd!( + command, + "-t", + format!("{}/{}:{tag}", image.resolve_registry(), image.repository()) + ); }); opts.tags .iter() - .map(|tag| format!("{image}:{tag}")) + .map(|tag| { + format!("{}/{}:{tag}", image.resolve_registry(), image.repository()) + }) .collect() }; let first_image = images.first().unwrap(); @@ -348,8 +360,12 @@ impl BuildDriver for DockerDriver { images } (None, Some(archive_path)) => { - cmd!(command, "--output", format!("type=oci,dest={archive_path}")); - string_vec![archive_path] + cmd!( + command, + "--output", + format!("type=oci,dest={}", archive_path.display()) + ); + string_vec![archive_path.display().to_string()] } (Some(_), Some(_)) => bail!("Cannot use both image and archive path"), (None, None) => bail!("Need either the image or archive path set"), @@ -385,16 +401,12 @@ impl InspectDriver for DockerDriver { #[cached( result = true, key = "String", - convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#, + convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#, sync_writes = true )] fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { trace!("DockerDriver::get_metadata({opts:#?})"); - - let url = opts.tag.as_ref().map_or_else( - || format!("{}", opts.image), - |tag| format!("{}:{tag}", opts.image), - ); + let image_str = opts.image.to_string(); let mut command = cmd!( "docker", @@ -409,16 +421,16 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { "inspect", "--format", "{{json .}}", - &url + &image_str, ); trace!("{command:?}"); let output = command.output().into_diagnostic()?; if output.status.success() { - info!("Successfully inspected image {url}!"); + info!("Successfully inspected image {}!", image_str.bold().green()); } else { - bail!("Failed to inspect image {url}") + bail!("Failed to inspect image {}", image_str.bold().red()) } serde_json::from_slice::(&output.stdout) diff --git a/process/drivers/github_driver.rs b/process/drivers/github_driver.rs index 284f7e18..6bcf8947 100644 --- a/process/drivers/github_driver.rs +++ b/process/drivers/github_driver.rs @@ -230,11 +230,11 @@ mod test { setup_default_branch, None, string_vec![ - format!("{}-40", &*TIMESTAMP), + format!("{}-41", &*TIMESTAMP), "latest", &*TIMESTAMP, - format!("{COMMIT_SHA}-40"), - "40", + format!("{COMMIT_SHA}-41"), + "41", ], )] #[case::default_branch_alt_tags( @@ -242,43 +242,43 @@ mod test { Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ TEST_TAG_1, - format!("{TEST_TAG_1}-40"), - format!("{}-{TEST_TAG_1}-40", &*TIMESTAMP), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), + format!("{TEST_TAG_1}-41"), + format!("{}-{TEST_TAG_1}-41", &*TIMESTAMP), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), TEST_TAG_2, - format!("{TEST_TAG_2}-40"), - format!("{}-{TEST_TAG_2}-40", &*TIMESTAMP), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("{TEST_TAG_2}-41"), + format!("{}-{TEST_TAG_2}-41", &*TIMESTAMP), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] #[case::pr_branch( setup_pr_branch, None, - string_vec!["pr-12-40", format!("{COMMIT_SHA}-40")], + string_vec!["pr-12-41", format!("{COMMIT_SHA}-41")], )] #[case::pr_branch_alt_tags( setup_pr_branch, Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ - format!("pr-12-{TEST_TAG_1}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), - format!("pr-12-{TEST_TAG_2}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("pr-12-{TEST_TAG_1}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), + format!("pr-12-{TEST_TAG_2}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] #[case::branch( setup_branch, None, - string_vec![format!("{COMMIT_SHA}-40"), "br-test-40"], + string_vec![format!("{COMMIT_SHA}-41"), "br-test-41"], )] #[case::branch_alt_tags( setup_branch, Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ - format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), - format!("br-{BR_REF_NAME}-{TEST_TAG_2}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("br-{BR_REF_NAME}-{TEST_TAG_1}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), + format!("br-{BR_REF_NAME}-{TEST_TAG_2}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] fn generate_tags( diff --git a/process/drivers/gitlab_driver.rs b/process/drivers/gitlab_driver.rs index 26a8160a..1891fd5c 100644 --- a/process/drivers/gitlab_driver.rs +++ b/process/drivers/gitlab_driver.rs @@ -238,11 +238,11 @@ mod test { setup_default_branch, None, string_vec![ - format!("{}-40", &*TIMESTAMP), + format!("{}-41", &*TIMESTAMP), "latest", &*TIMESTAMP, - format!("{COMMIT_SHA}-40"), - "40", + format!("{COMMIT_SHA}-41"), + "41", ], )] #[case::default_branch_alt_tags( @@ -250,43 +250,43 @@ mod test { Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ TEST_TAG_1, - format!("{TEST_TAG_1}-40"), - format!("{}-{TEST_TAG_1}-40", &*TIMESTAMP), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), + format!("{TEST_TAG_1}-41"), + format!("{}-{TEST_TAG_1}-41", &*TIMESTAMP), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), TEST_TAG_2, - format!("{TEST_TAG_2}-40"), - format!("{}-{TEST_TAG_2}-40", &*TIMESTAMP), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("{TEST_TAG_2}-41"), + format!("{}-{TEST_TAG_2}-41", &*TIMESTAMP), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] #[case::pr_branch( setup_mr_branch, None, - string_vec!["mr-12-40", format!("{COMMIT_SHA}-40")], + string_vec!["mr-12-41", format!("{COMMIT_SHA}-41")], )] #[case::pr_branch_alt_tags( setup_mr_branch, Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ - format!("mr-12-{TEST_TAG_1}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), - format!("mr-12-{TEST_TAG_2}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("mr-12-{TEST_TAG_1}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), + format!("mr-12-{TEST_TAG_2}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] #[case::branch( setup_branch, None, - string_vec![format!("{COMMIT_SHA}-40"), "br-test-40"], + string_vec![format!("{COMMIT_SHA}-41"), "br-test-41"], )] #[case::branch_alt_tags( setup_branch, Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ - format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), - format!("br-{BR_REF_NAME}-{TEST_TAG_2}-40"), - format!("{COMMIT_SHA}-{TEST_TAG_2}-40"), + format!("br-{BR_REF_NAME}-{TEST_TAG_1}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_1}-41"), + format!("br-{BR_REF_NAME}-{TEST_TAG_2}-41"), + format!("{COMMIT_SHA}-{TEST_TAG_2}-41"), ], )] fn generate_tags( diff --git a/process/drivers/opts/build.rs b/process/drivers/opts/build.rs index c1142eed..04d097c9 100644 --- a/process/drivers/opts/build.rs +++ b/process/drivers/opts/build.rs @@ -1,6 +1,7 @@ use std::{borrow::Cow, path::Path}; use bon::Builder; +use oci_distribution::Reference; use crate::drivers::types::Platform; @@ -26,16 +27,14 @@ pub struct BuildOpts<'scope> { } #[derive(Debug, Clone, Builder)] -#[builder(on(Cow<'_, str>, into))] pub struct TagOpts<'scope> { - pub src_image: Cow<'scope, str>, - pub dest_image: Cow<'scope, str>, + pub src_image: &'scope Reference, + pub dest_image: &'scope Reference, } #[derive(Debug, Clone, Builder)] pub struct PushOpts<'scope> { - #[builder(into)] - pub image: Cow<'scope, str>, + pub image: &'scope Reference, pub compression_type: Option, } @@ -55,14 +54,13 @@ pub struct BuildTagPushOpts<'scope> { /// NOTE: This SHOULD NOT contain the tag of the image. /// /// NOTE: You cannot have this set with `archive_path` set. - #[builder(into)] - pub image: Option>, + pub image: Option<&'scope Reference>, /// The path to the archive file. /// /// NOTE: You cannot have this set with image set. #[builder(into)] - pub archive_path: Option>, + pub archive_path: Option>, /// The path to the Containerfile to build. #[builder(into)] diff --git a/process/drivers/opts/inspect.rs b/process/drivers/opts/inspect.rs index de22b735..dd2f0906 100644 --- a/process/drivers/opts/inspect.rs +++ b/process/drivers/opts/inspect.rs @@ -1,6 +1,5 @@ -use std::borrow::Cow; - use bon::Builder; +use oci_distribution::Reference; use crate::drivers::types::Platform; @@ -8,10 +7,7 @@ use crate::drivers::types::Platform; #[builder(derive(Clone))] pub struct GetMetadataOpts<'scope> { #[builder(into)] - pub image: Cow<'scope, str>, - - #[builder(into)] - pub tag: Option>, + pub image: &'scope Reference, #[builder(default)] pub platform: Platform, diff --git a/process/drivers/opts/signing.rs b/process/drivers/opts/signing.rs index e9e31715..6cfd488f 100644 --- a/process/drivers/opts/signing.rs +++ b/process/drivers/opts/signing.rs @@ -6,6 +6,7 @@ use std::{ use bon::Builder; use miette::{IntoDiagnostic, Result}; +use oci_distribution::Reference; use zeroize::{Zeroize, Zeroizing}; use crate::drivers::types::Platform; @@ -69,7 +70,7 @@ pub struct CheckKeyPairOpts<'scope> { #[derive(Debug, Clone, Builder)] pub struct SignOpts<'scope> { #[builder(into)] - pub image: Cow<'scope, str>, + pub image: &'scope Reference, #[builder(into)] pub key: Option>, @@ -90,17 +91,14 @@ pub enum VerifyType<'scope> { #[derive(Debug, Clone, Builder)] pub struct VerifyOpts<'scope> { #[builder(into)] - pub image: Cow<'scope, str>, + pub image: &'scope Reference, pub verify_type: VerifyType<'scope>, } #[derive(Debug, Clone, Builder)] pub struct SignVerifyOpts<'scope> { #[builder(into)] - pub image: Cow<'scope, str>, - - #[builder(into)] - pub tag: Option>, + pub image: &'scope Reference, #[builder(into)] pub dir: Option>, diff --git a/process/drivers/podman_driver.rs b/process/drivers/podman_driver.rs index ddba6bbb..2debe613 100644 --- a/process/drivers/podman_driver.rs +++ b/process/drivers/podman_driver.rs @@ -167,15 +167,17 @@ impl BuildDriver for PodmanDriver { fn tag(opts: &TagOpts) -> Result<()> { trace!("PodmanDriver::tag({opts:#?})"); - let mut command = cmd!("podman", "tag", &*opts.src_image, &*opts.dest_image,); + let dest_image_str = opts.dest_image.to_string(); + + let mut command = cmd!("podman", "tag", opts.src_image.to_string(), &dest_image_str); trace!("{command:?}"); let status = command.status().into_diagnostic()?; if status.success() { - info!("Successfully tagged {}!", opts.dest_image); + info!("Successfully tagged {}!", dest_image_str.bold().green()); } else { - bail!("Failed to tag image {}", opts.dest_image); + bail!("Failed to tag image {}", dest_image_str.bold().red()); } Ok(()) } @@ -183,6 +185,8 @@ impl BuildDriver for PodmanDriver { fn push(opts: &PushOpts) -> Result<()> { trace!("PodmanDriver::push({opts:#?})"); + let image_str = opts.image.to_string(); + let command = cmd!( "podman", "push", @@ -190,18 +194,18 @@ impl BuildDriver for PodmanDriver { "--compression-format={}", opts.compression_type.unwrap_or_default() ), - &*opts.image, + &image_str, ); trace!("{command:?}"); let status = command - .build_status(&opts.image, "Pushing Image") + .build_status(&image_str, "Pushing Image") .into_diagnostic()?; if status.success() { - info!("Successfully pushed {}!", opts.image); + info!("Successfully pushed {}!", image_str.bold().green()); } else { - bail!("Failed to push image {}", opts.image) + bail!("Failed to push image {}", image_str.bold().red()); } Ok(()) } @@ -283,23 +287,20 @@ impl InspectDriver for PodmanDriver { #[cached( result = true, key = "String", - convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#, + convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#, sync_writes = true )] fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { trace!("PodmanDriver::get_metadata({opts:#?})"); - let url = opts.tag.as_deref().map_or_else( - || format!("{}", opts.image), - |tag| format!("{}:{tag}", opts.image), - ); + let image_str = opts.image.to_string(); let progress = Logger::multi_progress().add( ProgressBar::new_spinner() .with_style(ProgressStyle::default_spinner()) .with_message(format!( "Inspecting metadata for {}, pulling image...", - url.bold() + image_str.bold() )), ); progress.enable_steady_tick(Duration::from_millis(100)); @@ -311,17 +312,17 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { "--platform", opts.platform.to_string(), ], - &url, + &image_str, ); trace!("{command:?}"); let output = command.output().into_diagnostic()?; if !output.status.success() { - bail!("Failed to pull {} for inspection!", url.bold()); + bail!("Failed to pull {} for inspection!", image_str.bold().red()); } - let mut command = cmd!("podman", "image", "inspect", "--format=json", &url); + let mut command = cmd!("podman", "image", "inspect", "--format=json", &image_str); trace!("{command:?}"); let output = command.output().into_diagnostic()?; @@ -330,9 +331,9 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { Logger::multi_progress().remove(&progress); if output.status.success() { - debug!("Successfully inspected image {url}!"); + debug!("Successfully inspected image {}!", image_str.bold().green()); } else { - bail!("Failed to inspect image {url}"); + bail!("Failed to inspect image {}", image_str.bold().red()); } serde_json::from_slice::>(&output.stdout) .into_diagnostic() diff --git a/process/drivers/sigstore_driver.rs b/process/drivers/sigstore_driver.rs index a5415043..dbe5d0f9 100644 --- a/process/drivers/sigstore_driver.rs +++ b/process/drivers/sigstore_driver.rs @@ -15,6 +15,7 @@ use blue_build_utils::{ credentials::Credentials, retry, }; +use colored::Colorize; use log::{debug, trace}; use miette::{bail, miette, Context, IntoDiagnostic}; use sigstore::{ @@ -107,12 +108,16 @@ impl SigningDriver for SigstoreDriver { fn sign(opts: &SignOpts) -> miette::Result<()> { trace!("SigstoreDriver::sign({opts:?})"); + if opts.image.digest().is_none() { + bail!( + "Image ref {} is not a digest ref", + opts.image.to_string().bold().red(), + ); + } + let path = opts.dir.as_ref().map_or_else(|| Path::new("."), |dir| dir); let mut client = ClientBuilder::default().build().into_diagnostic()?; - - let image_digest: &str = opts.image.as_ref(); - let image_digest: OciReference = image_digest.parse().into_diagnostic()?; - trace!("{image_digest:?}"); + let image_digest: OciReference = opts.image.to_string().parse().into_diagnostic()?; let signing_scheme = SigningScheme::default(); let key: Zeroizing> = get_private_key(path)?.contents()?; @@ -174,8 +179,7 @@ impl SigningDriver for SigstoreDriver { fn verify(opts: &VerifyOpts) -> miette::Result<()> { let mut client = ClientBuilder::default().build().into_diagnostic()?; - let image_digest: &str = opts.image.as_ref(); - let image_digest: OciReference = image_digest.parse().into_diagnostic()?; + let image_digest: OciReference = opts.image.to_string().parse().into_diagnostic()?; trace!("{image_digest:?}"); let signing_scheme = SigningScheme::default(); diff --git a/process/drivers/skopeo_driver.rs b/process/drivers/skopeo_driver.rs index 747b2b90..881eae86 100644 --- a/process/drivers/skopeo_driver.rs +++ b/process/drivers/skopeo_driver.rs @@ -23,21 +23,18 @@ impl InspectDriver for SkopeoDriver { #[cached( result = true, key = "String", - convert = r#"{ format!("{}-{:?}-{}", &*opts.image, opts.tag.as_ref(), opts.platform)}"#, + convert = r#"{ format!("{}-{}", opts.image, opts.platform)}"#, sync_writes = true )] fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { trace!("SkopeoDriver::get_metadata({opts:#?})"); - let url = opts.tag.as_ref().map_or_else( - || format!("docker://{}", opts.image), - |tag| format!("docker://{}:{tag}", opts.image), - ); + let image_str = opts.image.to_string(); let progress = Logger::multi_progress().add( ProgressBar::new_spinner() .with_style(ProgressStyle::default_spinner()) - .with_message(format!("Inspecting metadata for {}", url.bold())), + .with_message(format!("Inspecting metadata for {}", image_str.bold())), ); progress.enable_steady_tick(Duration::from_millis(100)); @@ -48,7 +45,7 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { opts.platform.arch(), ], "inspect", - &url, + format!("docker://{image_str}"), stderr = Stdio::inherit(), ); trace!("{command:?}"); @@ -59,9 +56,9 @@ fn get_metadata_cache(opts: &GetMetadataOpts) -> Result { Logger::multi_progress().remove(&progress); if output.status.success() { - debug!("Successfully inspected image {url}!"); + debug!("Successfully inspected image {}!", image_str.bold().green()); } else { - bail!("Failed to inspect image {url}") + bail!("Failed to inspect image {}", image_str.bold().red()); } serde_json::from_slice(&output.stdout).into_diagnostic() } diff --git a/process/drivers/traits.rs b/process/drivers/traits.rs index 4eaaa89c..891b1e63 100644 --- a/process/drivers/traits.rs +++ b/process/drivers/traits.rs @@ -6,7 +6,7 @@ use std::{ use blue_build_utils::{constants::COSIGN_PUB_PATH, retry, string_vec}; use log::{debug, info, trace}; -use miette::{bail, miette, Context, IntoDiagnostic, Result}; +use miette::{bail, Context, IntoDiagnostic, Result}; use oci_distribution::Reference; use semver::{Version, VersionReq}; @@ -127,12 +127,9 @@ pub trait BuildDriver: PrivateDriver { let full_image = match (opts.archive_path.as_ref(), opts.image.as_ref()) { (Some(archive_path), None) => { - format!("oci-archive:{archive_path}") + format!("oci-archive:{}", archive_path.display()) } - (None, Some(image)) => opts - .tags - .first() - .map_or_else(|| image.to_string(), |tag| format!("{image}:{tag}")), + (None, Some(image)) => image.to_string(), (Some(_), Some(_)) => bail!("Cannot use both image and archive path"), (None, None) => bail!("Need either the image or archive path set"), }; @@ -148,25 +145,25 @@ pub trait BuildDriver: PrivateDriver { Self::build(&build_opts)?; let image_list: Vec = if !opts.tags.is_empty() && opts.archive_path.is_none() { - let image = opts - .image - .as_ref() - .ok_or_else(|| miette!("Image is required in order to tag"))?; + let image = opts.image.unwrap(); debug!("Tagging all images"); let mut image_list = Vec::with_capacity(opts.tags.len()); for tag in &opts.tags { debug!("Tagging {} with {tag}", &full_image); - let tagged_image = format!("{image}:{tag}"); + let tagged_image: Reference = + format!("{}/{}:{tag}", image.resolve_registry(), image.repository()) + .parse() + .into_diagnostic()?; let tag_opts = TagOpts::builder() - .src_image(&full_image) + .src_image(image) .dest_image(&tagged_image) .build(); Self::tag(&tag_opts)?; - image_list.push(tagged_image); + image_list.push(tagged_image.to_string()); if opts.push { let retry_count = if opts.retry_push { opts.retry_count } else { 0 }; @@ -174,12 +171,10 @@ pub trait BuildDriver: PrivateDriver { debug!("Pushing all images"); // Push images with retries (1s delay between retries) blue_build_utils::retry(retry_count, 5, || { - let tag_image = format!("{image}:{tag}"); - - debug!("Pushing image {tag_image}"); + debug!("Pushing image {tagged_image}"); let push_opts = PushOpts::builder() - .image(&tag_image) + .image(&tagged_image) .compression_type(opts.compression) .build(); @@ -516,23 +511,20 @@ pub trait SigningDriver: PrivateDriver { .as_ref() .map_or_else(|| PathBuf::from("."), |d| d.to_path_buf()); - let image_name: &str = opts.image.as_ref(); - let inspect_opts = GetMetadataOpts::builder() - .image(image_name) - .platform(opts.platform); - - let inspect_opts = if let Some(ref tag) = opts.tag { - inspect_opts.tag(&**tag).build() - } else { - inspect_opts.build() - }; - - let image_digest = Driver::get_metadata(&inspect_opts)?.digest; - let image_name_tag = opts - .tag - .as_ref() - .map_or_else(|| image_name.to_owned(), |t| format!("{image_name}:{t}")); - let image_digest = format!("{image_name}@{image_digest}"); + let image_digest = Driver::get_metadata( + &GetMetadataOpts::builder() + .image(opts.image) + .platform(opts.platform) + .build(), + )? + .digest; + let image_digest: Reference = format!( + "{}/{}@{image_digest}", + opts.image.resolve_registry(), + opts.image.repository(), + ) + .parse() + .into_diagnostic()?; let (sign_opts, verify_opts) = match (Driver::get_ci_driver(), get_private_key(&path)) { // Cosign public/private key pair @@ -543,7 +535,7 @@ pub trait SigningDriver: PrivateDriver { .key(priv_key.to_string()) .build(), VerifyOpts::builder() - .image(&image_name_tag) + .image(opts.image) .verify_type(VerifyType::File(path.join(COSIGN_PUB_PATH).into())) .build(), ), @@ -551,7 +543,7 @@ pub trait SigningDriver: PrivateDriver { (CiDriverType::Github | CiDriverType::Gitlab, _) => ( SignOpts::builder().dir(&path).image(&image_digest).build(), VerifyOpts::builder() - .image(&image_name_tag) + .image(opts.image) .verify_type(VerifyType::Keyless { issuer: Driver::oidc_provider()?.into(), identity: Driver::keyless_cert_identity()?.into(), diff --git a/src/commands/build.rs b/src/commands/build.rs index e143578c..abaf39e9 100644 --- a/src/commands/build.rs +++ b/src/commands/build.rs @@ -26,6 +26,7 @@ use bon::Builder; use clap::Args; use log::{info, trace, warn}; use miette::{bail, IntoDiagnostic, Result}; +use oci_distribution::Reference; use tempfile::TempDir; use crate::commands::generate::GenerateCommand; @@ -299,12 +300,15 @@ impl BuildCommand { .build(), )?; let image_name = self.image_name(&recipe)?; + let image: Reference = format!("{image_name}:{}", tags.first().map_or("latest", |tag| tag)) + .parse() + .into_diagnostic()?; let build_fn = || -> Result> { Driver::build_tag_push(&self.archive.as_ref().map_or_else( || { BuildTagPushOpts::builder() - .image(&image_name) + .image(&image) .containerfile(containerfile) .platform(self.platform) .tags(tags.collect_cow_vec()) @@ -319,11 +323,11 @@ impl BuildCommand { BuildTagPushOpts::builder() .containerfile(containerfile) .platform(self.platform) - .archive_path(format!( + .archive_path(PathBuf::from(format!( "{}/{}.{ARCHIVE_SUFFIX}", archive_dir.to_string_lossy().trim_end_matches('/'), recipe.name.to_lowercase().replace('/', "_"), - )) + ))) .squash(self.squash) .build() }, @@ -337,6 +341,10 @@ impl BuildCommand { InspectDriver, RechunkDriver, }; + let base_image: Reference = format!("{}:{}", &recipe.base_image, &recipe.image_version) + .parse() + .into_diagnostic()?; + Driver::rechunk( &RechunkOpts::builder() .image(&image_name) @@ -357,8 +365,7 @@ impl BuildCommand { .base_digest( Driver::get_metadata( &GetMetadataOpts::builder() - .image(&*recipe.base_image) - .tag(&*recipe.image_version) + .image(&base_image) .platform(self.platform) .build(), )? @@ -382,10 +389,9 @@ impl BuildCommand { if self.push && !self.no_sign { Driver::sign_and_verify( &SignVerifyOpts::builder() - .image(&image_name) + .image(&image) .retry_push(self.retry_push) .retry_count(self.retry_count) - .maybe_tag(tags.first()) .platform(self.platform) .build(), )?; diff --git a/src/commands/generate.rs b/src/commands/generate.rs index 246cf7b4..6b05d8ac 100644 --- a/src/commands/generate.rs +++ b/src/commands/generate.rs @@ -17,6 +17,7 @@ use cached::proc_macro::cached; use clap::{crate_version, Args}; use log::{debug, info, trace, warn}; use miette::{IntoDiagnostic, Result}; +use oci_distribution::Reference; #[cfg(feature = "validate")] use crate::commands::validate::ValidateCommand; @@ -132,6 +133,10 @@ impl GenerateCommand { info!("Templating for recipe at {}", recipe_path.display()); + let base_image: Reference = format!("{}:{}", &recipe.base_image, &recipe.image_version) + .parse() + .into_diagnostic()?; + let template = ContainerFileTemplate::builder() .os_version( Driver::get_os_version() @@ -144,12 +149,11 @@ impl GenerateCommand { .recipe_path(recipe_path.as_path()) .registry(registry) .repo(Driver::get_repo_url()?) - .build_scripts_image(determine_scripts_tag(self.platform)?) + .build_scripts_image(determine_scripts_tag(self.platform)?.to_string()) .base_digest( Driver::get_metadata( &GetMetadataOpts::builder() - .image(&*recipe.base_image) - .tag(&*recipe.image_version) + .image(&base_image) .platform(self.platform) .build(), )? @@ -178,24 +182,30 @@ impl GenerateCommand { convert = r#"{ platform }"#, sync_writes = true )] -fn determine_scripts_tag(platform: Platform) -> Result { - let version = format!("v{}", crate_version!()); - let opts = GetMetadataOpts::builder() - .image(BUILD_SCRIPTS_IMAGE_REF) - .platform(platform); +fn determine_scripts_tag(platform: Platform) -> Result { + let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::COMMIT_HASH) + .parse() + .into_diagnostic()?; + let opts = GetMetadataOpts::builder().platform(platform); - Driver::get_metadata(&opts.clone().tag(shadow::COMMIT_HASH).build()) + Driver::get_metadata(&opts.clone().image(&image).build()) .inspect_err(|e| trace!("{e:?}")) - .map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::COMMIT_HASH)) + .map(|_| image) .or_else(|_| { - Driver::get_metadata(&opts.clone().tag(shadow::BRANCH).build()) + let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::BRANCH) + .parse() + .into_diagnostic()?; + Driver::get_metadata(&opts.clone().image(&image).build()) .inspect_err(|e| trace!("{e:?}")) - .map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{}", shadow::BRANCH)) + .map(|_| image) }) .or_else(|_| { - Driver::get_metadata(&opts.tag(&version).build()) + let image: Reference = format!("{BUILD_SCRIPTS_IMAGE_REF}:v{}", crate_version!()) + .parse() + .into_diagnostic()?; + Driver::get_metadata(&opts.image(&image).build()) .inspect_err(|e| trace!("{e:?}")) - .map(|_| format!("{BUILD_SCRIPTS_IMAGE_REF}:{version}")) + .map(|_| image) }) .inspect(|image| debug!("Using build scripts image: {image}")) }