Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion process/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ mod bootc_driver;
mod buildah_driver;
mod cosign_driver;
mod docker_driver;
mod functions;
mod github_driver;
mod gitlab_driver;
mod local_driver;
Expand Down
30 changes: 16 additions & 14 deletions process/drivers/cosign_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ use miette::{Context, IntoDiagnostic, Result, bail};
use semver::VersionReq;
use serde::Deserialize;

use crate::drivers::{DriverVersion, opts::VerifyType};
use crate::drivers::{
DriverVersion,
opts::{PrivateKey, VerifyType},
};

use super::{
SigningDriver,
functions::get_private_key,
opts::{CheckKeyPairOpts, GenerateKeyPairOpts, SignOpts, VerifyOpts},
};

Expand Down Expand Up @@ -86,7 +88,7 @@ impl SigningDriver for CosignDriver {

fn check_signing_files(opts: CheckKeyPairOpts) -> Result<()> {
let path = opts.dir.unwrap_or_else(|| Path::new("."));
let priv_key = get_private_key(path)?;
let priv_key = PrivateKey::new(path)?;

let output = {
let c = cmd!(
Expand Down Expand Up @@ -156,14 +158,14 @@ impl SigningDriver for CosignDriver {
Ok(())
}

fn sign(opts: SignOpts) -> Result<()> {
if opts.image.digest().is_none() {
bail!(
"Image ref {} is not a digest ref",
opts.image.to_string().bold().red(),
);
}

fn sign(
SignOpts {
image,
metadata,
key,
}: SignOpts,
) -> Result<()> {
let image = image.clone_with_digest(metadata.digest().into());
let status = {
let c = cmd!(
env {
Expand All @@ -172,13 +174,13 @@ impl SigningDriver for CosignDriver {
};
"cosign",
"sign",
if let Some(key) = opts.key => format!("--key={key}"),
if let Some(key) = key => format!("--key={key}"),
if Self::is_v3() => [
"--new-bundle-format=false",
"--use-signing-config=false",
],
"--recursive",
opts.image.to_string(),
image.to_string(),
);
trace!("{c:?}");
c
Expand All @@ -187,7 +189,7 @@ impl SigningDriver for CosignDriver {
.into_diagnostic()?;

if !status.success() {
bail!("Failed to sign {}", opts.image.to_string().bold().red());
bail!("Failed to sign {}", image.to_string().bold().red());
}

Ok(())
Expand Down
52 changes: 0 additions & 52 deletions process/drivers/functions.rs

This file was deleted.

49 changes: 38 additions & 11 deletions process/drivers/oci_client_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use blue_build_utils::credentials::Credentials;
use cached::proc_macro::cached;
use log::trace;
use miette::{IntoDiagnostic, Result};
use oci_client::{Reference, client::ClientConfig, secrets::RegistryAuth};
use oci_client::{Reference, client::ClientConfig, manifest::OciManifest, secrets::RegistryAuth};

use crate::{
ASYNC_RUNTIME,
Expand All @@ -29,20 +29,47 @@ impl InspectDriver for OciClientDriver {
let (manifest, digest) = ASYNC_RUNTIME
.block_on(client.pull_manifest(image, &auth))
.into_diagnostic()?;
let (image_manifest, _image_digest) = ASYNC_RUNTIME
.block_on(client.pull_image_manifest(image, &auth))
.into_diagnostic()?;
let config = {
let mut c: Vec<u8> = vec![];
ASYNC_RUNTIME
.block_on(client.pull_blob(image, &image_manifest.config, &mut c))
.into_diagnostic()?;
c

let manifest_digests = match &manifest {
OciManifest::Image(_) => vec![&digest],
OciManifest::ImageIndex(index) => {
index.manifests.iter().map(|entry| &entry.digest).collect()
}
};

trace!("Found digests: {manifest_digests:#?}");

let configs = manifest_digests
.into_iter()
.map(|digest| {
let image = &image.clone_with_digest(digest.clone());
let (image_manifest, _) = ASYNC_RUNTIME
.block_on(client.pull_image_manifest(image, &auth))
.into_diagnostic()?;

let config = {
let mut c: Vec<u8> = vec![];
ASYNC_RUNTIME
.block_on(client.pull_blob(image, &image_manifest.config, &mut c))
.into_diagnostic()?;
c
};
Ok((
image_manifest.config.digest,
serde_json::from_slice(&config).into_diagnostic()?,
))
})
.collect::<Result<Vec<_>>>()?;

trace!(
"Config digests: {:#?}",
configs.iter().map(|(digest, _)| digest)
);

Ok(ImageMetadata::builder()
.manifest(manifest)
.digest(digest)
.config(serde_json::from_slice(&config).into_diagnostic()?)
.configs(configs)
.build())
}
trace!("OciClientDriver::get_metadata({opts:?})");
Expand Down
65 changes: 62 additions & 3 deletions process/drivers/opts/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,77 @@ use std::{
path::{Path, PathBuf},
};

use blue_build_utils::{get_env_var, platform::Platform};
use blue_build_utils::{
constants::{BB_PRIVATE_KEY, COSIGN_PRIV_PATH, COSIGN_PRIVATE_KEY, COSIGN_PUB_PATH},
get_env_var,
platform::Platform,
string,
};
use bon::Builder;
use miette::{IntoDiagnostic, Result};
use miette::{IntoDiagnostic, Result, bail};
use oci_client::Reference;
use zeroize::{Zeroize, Zeroizing};

use crate::drivers::types::ImageMetadata;

#[derive(Debug)]
pub enum PrivateKey {
Env(String),
Path(PathBuf),
}

impl PrivateKey {
/// Create a `PrivateKey` object that tracks where the public key is.
///
/// Contents of the `PrivateKey` are lazy loaded when `PrivateKey::contents` is called.
///
/// # Errors
///
/// Will error if the private key location cannot be found.
pub fn new<P>(path: P) -> Result<Self>
where
P: AsRef<Path>,
{
let path = path.as_ref();

Ok(
match (
path.join(COSIGN_PUB_PATH).exists(),
get_env_var(BB_PRIVATE_KEY).ok(),
get_env_var(COSIGN_PRIVATE_KEY).ok(),
path.join(COSIGN_PRIV_PATH),
) {
(true, Some(private_key), _, _) if !private_key.is_empty() => {
Self::Env(string!(BB_PRIVATE_KEY))
}
(true, _, Some(cosign_priv_key), _) if !cosign_priv_key.is_empty() => {
Self::Env(string!(COSIGN_PRIVATE_KEY))
}
(true, _, _, cosign_priv_key_path) if cosign_priv_key_path.exists() => {
Self::Path(cosign_priv_key_path)
}
_ => {
bail!(
help = format!(
"{}{}{}{}{}{}",
format_args!("Make sure you have a `{COSIGN_PUB_PATH}`\n"),
format_args!(
"in the root of your repo and have either {COSIGN_PRIVATE_KEY}\n"
),
format_args!("set in your env variables or a `{COSIGN_PRIV_PATH}`\n"),
"file in the root of your repo.\n\n",
"See https://blue-build.org/how-to/cosign/ for more information.\n\n",
"If you don't want to sign your image, use the `--no-sign` flag.",
),
"{}",
"Unable to find private/public key pair",
)
}
},
)
}
}

impl std::fmt::Display for PrivateKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
Expand Down Expand Up @@ -70,8 +129,8 @@ pub struct CheckKeyPairOpts<'scope> {
#[builder(derive(Debug, Clone))]
pub struct SignOpts<'scope> {
pub image: &'scope Reference,
pub metadata: &'scope ImageMetadata,
pub key: Option<&'scope PrivateKey>,
pub dir: Option<&'scope Path>,
}

#[derive(Debug, Clone, Copy)]
Expand Down
Loading
Loading