diff --git a/integration-tests/test-repo/recipes/common.yml b/integration-tests/test-repo/recipes/common.yml index d851bcf..783ce67 100644 --- a/integration-tests/test-repo/recipes/common.yml +++ b/integration-tests/test-repo/recipes/common.yml @@ -12,20 +12,16 @@ modules: - example.sh - type: script - # Use this to pass schema check - source: ghcr.io/blue-build/modules/script snippets: - '[ -z "$TEST_ARG" ]' + - type: script - # Use this to pass schema check - source: ghcr.io/blue-build/modules/script env: TEST_ARG: "test" snippets: - '[ "$TEST_ARG" = "test" ]' + - type: script - # Use this to pass schema check - source: ghcr.io/blue-build/modules/script snippets: - '[ -z "$TEST_ARG" ]' @@ -83,33 +79,61 @@ modules: secrets: - type: env name: TEST_SECRET + mount: + type: env + name: TEST_SECRET snippets: - '[ "$TEST_SECRET" == "test123" ]' + + - type: script + secrets: + - type: env + name: TEST_SECRET + mount: + type: file + destination: /tmp/test-secret + snippets: + - '[ "$(cat /tmp/test-secret)" == "test123" ]' + - type: script secrets: - type: file source: ./secrets/test-secret - destination: /tmp/test-secret + mount: + type: file + destination: /tmp/test-secret snippets: - '[ "$(cat /tmp/test-secret)" == "321tset" ]' + + - type: script + secrets: + - type: file + source: ./secrets/test-secret + mount: + type: env + name: TEST_SECRET + snippets: + - '[ "$TEST_SECRET" == "321tset" ]' + - type: script secrets: - type: exec command: cat args: - ./test_secret_file.txt - output: + mount: type: env name: TEST_SECRET snippets: - '[ "$TEST_SECRET" == "TEST_PASS" ]' + - type: script secrets: - type: exec command: cat args: - ./test_secret_file.txt - output: + mount: type: file destination: /tmp/test-secret snippets: diff --git a/justfile b/justfile index 3b78766..fb42aab 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ export RUST_BACKTRACE := "1" export BB_CACHE_LAYERS := "true" export TEST_SECRET := "test123" -# export BB_SKIP_VALIDATION := "true" +export BB_SKIP_VALIDATION := "true" set dotenv-load := true set positional-arguments := true diff --git a/process/drivers/buildah_driver.rs b/process/drivers/buildah_driver.rs index c5b38bb..85a8ef4 100644 --- a/process/drivers/buildah_driver.rs +++ b/process/drivers/buildah_driver.rs @@ -59,6 +59,7 @@ impl BuildDriver for BuildahDriver { "buildah", "build", for opts.secrets.args(&temp_dir)?, + if opts.secrets.ssh() => "--ssh", if !matches!(opts.platform, Platform::Native) => [ "--platform", opts.platform.to_string(), diff --git a/process/drivers/docker_driver.rs b/process/drivers/docker_driver.rs index afa9b50..8f802de 100644 --- a/process/drivers/docker_driver.rs +++ b/process/drivers/docker_driver.rs @@ -215,6 +215,7 @@ impl BuildDriver for DockerDriver { opts.image.to_string(), "-f", for opts.secrets.args(&temp_dir)?, + if opts.secrets.ssh() => "--ssh", if let Some(cache_from) = opts.cache_from.as_ref() => [ "--cache-from", format!( @@ -430,6 +431,7 @@ fn build_tag_push_cmd( "build", ".", for opts.secrets.args(temp_dir)?, + if opts.secrets.ssh() => "--ssh", match &opts.image { ImageRef::Remote(_remote) if opts.push => [ "--output", diff --git a/process/drivers/podman_driver.rs b/process/drivers/podman_driver.rs index a0a6915..c6087b2 100644 --- a/process/drivers/podman_driver.rs +++ b/process/drivers/podman_driver.rs @@ -186,6 +186,7 @@ impl BuildDriver for PodmanDriver { "-t", opts.image.to_string(), for opts.secrets.args(&temp_dir)?, + if opts.secrets.ssh() => "--ssh", ".", ); diff --git a/utils/src/secret.rs b/utils/src/secret.rs index 9946250..7690be7 100644 --- a/utils/src/secret.rs +++ b/utils/src/secret.rs @@ -23,12 +23,9 @@ mod private { #[serde(tag = "type")] pub enum Secret { #[serde(rename = "env")] - Env { name: String }, + Env { name: String, mount: SecretMount }, #[serde(rename = "file")] - File { - source: PathBuf, - destination: PathBuf, - }, + File { source: PathBuf, mount: SecretMount }, #[serde(rename = "exec")] Exec(SecretExec), #[serde(rename = "ssh")] @@ -46,20 +43,32 @@ impl Secret { let hash = self.get_hash(); let prefix = format!("--mount=type=secret,id={hash}"); match self { - Self::Env { name: _ } - | Self::Exec(SecretExec { - command: _, - args: _, - output: SecretExecOutput::Env { name: _ }, - }) => format!("{prefix},dst=/tmp/secrets/{hash}"), - Self::File { - source: _, - destination, + Self::Env { + name: _, + mount: SecretMount::Env { name: _ }, } | Self::Exec(SecretExec { command: _, args: _, - output: SecretExecOutput::File { destination }, + mount: SecretMount::Env { name: _ }, + }) + | Self::File { + source: _, + mount: SecretMount::Env { name: _ }, + } => format!("{prefix},dst=/tmp/secrets/{hash}"), + + Self::Env { + name: _, + mount: SecretMount::File { destination }, + } + | Self::File { + source: _, + mount: SecretMount::File { destination }, + } + | Self::Exec(SecretExec { + command: _, + args: _, + mount: SecretMount::File { destination }, }) => format!("{prefix},dst={}", destination.display()), Self::Ssh => string!("--ssh"), } @@ -69,11 +78,18 @@ impl Secret { pub fn env(&self) -> Option { let hash = self.get_hash(); match self { - Self::Env { name } + Self::Env { + name: _, + mount: SecretMount::Env { name }, + } + | Self::File { + source: _, + mount: SecretMount::Env { name }, + } | Self::Exec(SecretExec { command: _, args: _, - output: SecretExecOutput::Env { name }, + mount: SecretMount::Env { name }, }) => Some(format!(r#"{name}="$(cat /tmp/secrets/{hash})""#)), _ => None, } @@ -117,30 +133,27 @@ pub trait SecretArgs: private::Private { /// # Errors /// Will error if an exec based secret fails to run. fn args(&self, temp_dir: &TempDir) -> Result>; + + /// Checks to see if ssh is a required secret. + fn ssh(&self) -> bool; } impl SecretArgs for HashSet<&Secret, H> { fn args(&self, temp_dir: &TempDir) -> Result> { - self.iter() - .map(|secret| { + Ok(self + .iter() + .map(|&secret| { Ok(match secret { - Secret::Env { name } => { - format!( - "--secret=id={},type=env,src={}", - secret.get_hash(), - name.trim() - ) - } - Secret::File { - source, - destination: _, - } => { - format!( - "--secret=id={},type=file,src={}", - secret.get_hash(), - source.display() - ) - } + Secret::Env { name, mount: _ } => Some(format!( + "--secret=id={},type=env,src={}", + secret.get_hash(), + name.trim() + )), + Secret::File { source, mount: _ } => Some(format!( + "--secret=id={},type=file,src={}", + secret.get_hash(), + source.display() + )), Secret::Exec(exec) => { let result = exec.exec()?; let hash = secret.get_hash(); @@ -148,12 +161,19 @@ impl SecretArgs for HashSet<&Secret, H> { fs::write(&secret_path, result.value()) .into_diagnostic() .wrap_err("Failed to write secret to temp file")?; - format!("--secret=id={hash},src={}", secret_path.display()) + Some(format!("--secret=id={hash},src={}", secret_path.display())) } - Secret::Ssh => string!("--ssh"), + Secret::Ssh => None, }) }) - .collect() + .collect::>>()? + .into_iter() + .flatten() + .collect()) + } + + fn ssh(&self) -> bool { + self.contains(&Secret::Ssh) } } @@ -161,7 +181,7 @@ impl SecretArgs for HashSet<&Secret, H> { pub struct SecretExec { pub command: String, pub args: Vec, - pub output: SecretExecOutput, + pub mount: SecretMount, } impl SecretExec { @@ -188,7 +208,7 @@ impl SecretExec { #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] #[serde(tag = "type")] -pub enum SecretExecOutput { +pub enum SecretMount { #[serde(rename = "env")] Env { name: String }, #[serde(rename = "file")]