cuenv_core/secrets/
mod.rs1use crate::{Error, Result};
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::collections::HashMap;
13
14pub use cuenv_secrets::{
16 BatchResolver, ResolvedSecrets, SaltConfig, SecretError, SecretResolver, SecretSpec,
17 compute_secret_fingerprint,
18};
19
20pub use cuenv_secrets::resolvers::{EnvSecretResolver, ExecSecretResolver};
22
23pub use cuenv_1password::secrets::{OnePasswordConfig, OnePasswordResolver};
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct ExecResolver {
29 pub command: String,
31
32 pub args: Vec<String>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
46pub struct Secret {
47 pub resolver: String,
49
50 #[serde(default, skip_serializing_if = "String::is_empty")]
52 pub command: String,
53
54 #[serde(default, skip_serializing_if = "Vec::is_empty")]
56 pub args: Vec<String>,
57
58 #[serde(rename = "ref", default, skip_serializing_if = "Option::is_none")]
60 pub op_ref: Option<String>,
61
62 #[serde(flatten)]
64 pub extra: HashMap<String, Value>,
65}
66
67impl Secret {
68 #[must_use]
70 pub fn new(command: String, args: Vec<String>) -> Self {
71 Secret {
72 resolver: "exec".to_string(),
73 command,
74 args,
75 op_ref: None,
76 extra: HashMap::new(),
77 }
78 }
79
80 #[must_use]
82 pub fn onepassword(reference: impl Into<String>) -> Self {
83 Secret {
84 resolver: "onepassword".to_string(),
85 command: String::new(),
86 args: Vec::new(),
87 op_ref: Some(reference.into()),
88 extra: HashMap::new(),
89 }
90 }
91
92 #[must_use]
94 pub fn with_extra(command: String, args: Vec<String>, extra: HashMap<String, Value>) -> Self {
95 Secret {
96 resolver: "exec".to_string(),
97 command,
98 args,
99 op_ref: None,
100 extra,
101 }
102 }
103
104 #[must_use]
106 pub fn provider(&self) -> &str {
107 &self.resolver
108 }
109
110 #[must_use]
112 pub fn to_spec(&self) -> SecretSpec {
113 let source = match self.resolver.as_str() {
114 "onepassword" => self.op_ref.clone().unwrap_or_default(),
115 "exec" => serde_json::json!({
116 "command": self.command,
117 "args": self.args
118 })
119 .to_string(),
120 _ => serde_json::to_string(self).unwrap_or_default(),
122 };
123 SecretSpec::new(source)
124 }
125
126 pub async fn resolve(&self) -> Result<String> {
131 let spec = self.to_spec();
132
133 match self.resolver.as_str() {
134 "onepassword" => {
135 let resolver = OnePasswordResolver::new().map_err(|e| {
136 Error::configuration(format!("Failed to initialize 1Password resolver: {e}"))
137 })?;
138 resolver
139 .resolve("secret", &spec)
140 .await
141 .map_err(|e| Error::configuration(format!("{e}")))
142 }
143 "exec" => {
144 let resolver = ExecSecretResolver::new();
145 resolver
146 .resolve("secret", &spec)
147 .await
148 .map_err(|e| Error::configuration(format!("{e}")))
149 }
150 other => Err(Error::configuration(format!(
151 "Unsupported secret resolver: {other}"
152 ))),
153 }
154 }
155}