feat: Add ability to mount secrets

This commit is contained in:
Gerald Pinder 2025-07-13 11:41:42 -04:00
parent 22ef8392b7
commit 4fabd3e5db
27 changed files with 463 additions and 69 deletions

View file

@ -20,7 +20,6 @@ os_pipe = { version = "1", features = ["io_safety"] }
rand = "0.9"
signal-hook = { version = "0.3", features = ["extended-siginfo"] }
sigstore = { version = "0.11", features = ["full-rustls-tls", "cached-client", "sigstore-trust-root", "sign"], default-features = false }
zeroize = { version = "1", features = ["aarch64", "derive", "serde"] }
cached.workspace = true
chrono.workspace = true
@ -42,6 +41,7 @@ tokio.workspace = true
bon.workspace = true
users.workspace = true
uuid.workspace = true
zeroize.workspace = true
[dev-dependencies]
rstest.workspace = true

View file

@ -14,7 +14,7 @@ use std::{
time::Duration,
};
use blue_build_utils::semver::Version;
use blue_build_utils::{BUILD_ID, semver::Version};
use bon::{Builder, bon};
use cached::proc_macro::cached;
use clap::Args;
@ -69,9 +69,6 @@ static SELECTED_SIGNING_DRIVER: std::sync::LazyLock<RwLock<Option<SigningDriverT
static SELECTED_CI_DRIVER: std::sync::LazyLock<RwLock<Option<CiDriverType>>> =
std::sync::LazyLock::new(|| RwLock::new(None));
/// UUID used to mark the current builds
static BUILD_ID: std::sync::LazyLock<Uuid> = std::sync::LazyLock::new(Uuid::new_v4);
/// Args for selecting the various drivers to use for runtime.
///
/// If the args are left uninitialized, the program will determine

View file

@ -1,11 +1,12 @@
use std::{io::Write, process::Stdio};
use blue_build_utils::{credentials::Credentials, semver::Version};
use blue_build_utils::{credentials::Credentials, secret::SecretArgs, semver::Version};
use colored::Colorize;
use comlexr::cmd;
use log::{debug, error, info, trace};
use miette::{IntoDiagnostic, Result, bail, miette};
use miette::{Context, IntoDiagnostic, Result, bail, miette};
use serde::Deserialize;
use tempfile::TempDir;
use crate::{drivers::types::Platform, logging::CommandLogging};
@ -50,9 +51,14 @@ impl BuildDriver for BuildahDriver {
fn build(opts: &BuildOpts) -> Result<()> {
trace!("BuildahDriver::build({opts:#?})");
let temp_dir = TempDir::new()
.into_diagnostic()
.wrap_err("Failed to create temporary directory for secrets")?;
let command = cmd!(
"buildah",
"build",
for opts.secrets.args(&temp_dir)?,
if !matches!(opts.platform, Platform::Native) => [
"--platform",
opts.platform.to_string(),

View file

@ -8,6 +8,7 @@ use blue_build_utils::{
constants::{BLUE_BUILD, DOCKER_HOST, GITHUB_ACTIONS},
credentials::Credentials,
get_env_var,
secret::SecretArgs,
semver::Version,
string_vec,
};
@ -194,6 +195,10 @@ impl BuildDriver for DockerDriver {
fn build(opts: &BuildOpts) -> Result<()> {
trace!("DockerDriver::build({opts:#?})");
let temp_dir = TempDir::new()
.into_diagnostic()
.wrap_err("Failed to create temporary directory for secrets")?;
if opts.squash {
warn!("Squash is deprecated for docker so this build will not squash");
}
@ -209,6 +214,7 @@ impl BuildDriver for DockerDriver {
"-t",
opts.image.to_string(),
"-f",
for opts.secrets.args(&temp_dir)?,
if let Some(cache_from) = opts.cache_from.as_ref() => [
"--cache-from",
format!(
@ -381,6 +387,10 @@ impl BuildDriver for DockerDriver {
fn build_tag_push(opts: &BuildTagPushOpts) -> Result<Vec<String>> {
trace!("DockerDriver::build_tag_push({opts:#?})");
let temp_dir = TempDir::new()
.into_diagnostic()
.wrap_err("Failed to create temporary directory for secrets")?;
if opts.squash {
warn!("Squash is deprecated for docker so this build will not squash");
}
@ -391,7 +401,7 @@ impl BuildDriver for DockerDriver {
let first_image = final_images.first().unwrap();
let status = build_tag_push_cmd(opts, first_image)
let status = build_tag_push_cmd(opts, first_image, &temp_dir)?
.build_status(first_image, "Building Image")
.into_diagnostic()?;
@ -408,13 +418,18 @@ impl BuildDriver for DockerDriver {
}
}
fn build_tag_push_cmd(opts: &BuildTagPushOpts<'_>, first_image: &str) -> Command {
fn build_tag_push_cmd(
opts: &BuildTagPushOpts<'_>,
first_image: &str,
temp_dir: &TempDir,
) -> Result<Command> {
let c = cmd!(
"docker",
"buildx",
format!("--builder={BLUE_BUILD}"),
"build",
".",
for opts.secrets.args(temp_dir)?,
match &opts.image {
ImageRef::Remote(_remote) if opts.push => [
"--output",
@ -459,7 +474,7 @@ fn build_tag_push_cmd(opts: &BuildTagPushOpts<'_>, first_image: &str) -> Command
],
);
trace!("{c:?}");
c
Ok(c)
}
fn get_final_images(opts: &BuildTagPushOpts<'_>) -> Vec<String> {

View file

@ -1,5 +1,6 @@
use std::{borrow::Cow, path::Path};
use std::{borrow::Cow, collections::HashSet, path::Path};
use blue_build_utils::secret::Secret;
use bon::Builder;
use oci_distribution::Reference;
@ -33,6 +34,9 @@ pub struct BuildOpts<'scope> {
#[builder(into)]
pub cache_to: Option<&'scope Reference>,
#[builder(default)]
pub secrets: HashSet<&'scope Secret>,
}
#[derive(Debug, Clone, Builder)]
@ -110,4 +114,8 @@ pub struct BuildTagPushOpts<'scope> {
/// Cache layers to the registry.
pub cache_to: Option<&'scope Reference>,
/// Secrets to mount
#[builder(default)]
pub secrets: HashSet<&'scope Secret>,
}

View file

@ -1,5 +1,6 @@
use std::{borrow::Cow, path::Path};
use std::{borrow::Cow, collections::HashSet, path::Path};
use blue_build_utils::secret::Secret;
use bon::Builder;
use oci_distribution::Reference;
@ -55,6 +56,9 @@ pub struct RechunkOpts<'scope> {
/// Cache layers to the registry.
pub cache_to: Option<&'scope Reference>,
#[builder(default)]
pub secrets: HashSet<&'scope Secret>,
}
#[derive(Debug, Clone, Builder)]

View file

@ -7,14 +7,14 @@ use std::{
use blue_build_utils::{
constants::SUDO_ASKPASS, credentials::Credentials, has_env_var, running_as_root,
semver::Version,
secret::SecretArgs, semver::Version,
};
use cached::proc_macro::cached;
use colored::Colorize;
use comlexr::{cmd, pipe};
use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, error, info, trace};
use miette::{IntoDiagnostic, Report, Result, bail, miette};
use miette::{Context, IntoDiagnostic, Report, Result, bail, miette};
use oci_distribution::Reference;
use serde::Deserialize;
use tempfile::TempDir;
@ -137,6 +137,10 @@ impl BuildDriver for PodmanDriver {
fn build(opts: &BuildOpts) -> Result<()> {
trace!("PodmanDriver::build({opts:#?})");
let temp_dir = TempDir::new()
.into_diagnostic()
.wrap_err("Failed to create temporary directory for secrets")?;
let use_sudo = opts.privileged && !running_as_root();
let command = cmd!(
if use_sudo {
@ -149,7 +153,10 @@ impl BuildDriver for PodmanDriver {
"-p",
SUDO_PROMPT,
],
if use_sudo => "podman",
if use_sudo => [
"--preserve-env",
"podman",
],
"build",
if !matches!(opts.platform, Platform::Native) => [
"--platform",
@ -178,6 +185,7 @@ impl BuildDriver for PodmanDriver {
&*opts.containerfile,
"-t",
opts.image.to_string(),
for opts.secrets.args(&temp_dir)?,
".",
);
@ -409,11 +417,11 @@ impl ContainerMountDriver for PodmanDriver {
} else {
"podman"
},
if use_sudo && has_env_var(SUDO_ASKPASS) => [
"-A",
"-p",
SUDO_PROMPT,
],
if use_sudo && has_env_var(SUDO_ASKPASS) => [
"-A",
"-p",
SUDO_PROMPT,
],
if use_sudo => "podman",
"mount",
opts.container_id,

View file

@ -128,6 +128,7 @@ pub trait BuildDriver: PrivateDriver {
.squash(opts.squash)
.maybe_cache_from(opts.cache_from)
.maybe_cache_to(opts.cache_to)
.secrets(opts.secrets.clone())
.build();
info!("Building image {}", opts.image);
@ -289,6 +290,7 @@ pub trait RechunkDriver: RunDriver + BuildDriver + ContainerMountDriver {
.privileged(true)
.squash(true)
.host_network(true)
.secrets(opts.secrets.clone())
.build(),
)?;