cuenv_core/secrets/
mod.rs1use crate::{Error, Result};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10use tokio::process::Command;
11
12#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
14pub struct ExecResolver {
15 pub command: String,
17
18 pub args: Vec<String>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
25pub struct Secret {
26 pub resolver: String,
28
29 pub command: String,
31
32 #[serde(default)]
34 pub args: Vec<String>,
35
36 #[serde(flatten)]
38 pub extra: HashMap<String, Value>,
39}
40
41impl Secret {
42 pub fn new(command: String, args: Vec<String>) -> Self {
44 Secret {
45 resolver: "exec".to_string(),
46 command,
47 args,
48 extra: HashMap::new(),
49 }
50 }
51
52 pub fn with_extra(command: String, args: Vec<String>, extra: HashMap<String, Value>) -> Self {
54 Secret {
55 resolver: "exec".to_string(),
56 command,
57 args,
58 extra,
59 }
60 }
61
62 pub async fn resolve(&self) -> Result<String> {
64 match self.resolver.as_str() {
65 "exec" => {
66 let output = Command::new(&self.command)
67 .args(&self.args)
68 .output()
69 .await
70 .map_err(|e| {
71 Error::configuration(format!(
72 "Failed to execute secret resolver command '{}': {}",
73 self.command, e
74 ))
75 })?;
76
77 if !output.status.success() {
78 let stderr = String::from_utf8_lossy(&output.stderr);
79 return Err(Error::configuration(format!(
80 "Secret resolver command '{}' failed: {}",
81 self.command, stderr
82 )));
83 }
84
85 let stdout = String::from_utf8_lossy(&output.stdout);
86 Ok(stdout.trim().to_string())
87 }
88 other => Err(Error::configuration(format!(
89 "Unsupported secret resolver: {}",
90 other
91 ))),
92 }
93 }
94}