gsm_core/
prelude.rs

1use async_trait::async_trait;
2pub use greentic_types::{
3    EnvId, InvocationEnvelope, NodeError, NodeResult, TeamId, TenantCtx, TenantId, UserId,
4};
5pub use secrets_core::DefaultResolver;
6use secrets_core::{embedded::SecretsError, errors::Error as CoreError};
7
8#[derive(Clone, Debug)]
9pub struct SecretPath(pub String);
10
11impl SecretPath {
12    pub fn as_str(&self) -> &str {
13        &self.0
14    }
15
16    pub fn to_uri(&self) -> String {
17        let trimmed = self.0.trim_start_matches('/');
18        format!("secret://{trimmed}")
19    }
20}
21
22#[async_trait]
23pub trait SecretsResolver: Send + Sync {
24    // TODO(greentic-core): keep this aligned with greentic-secrets abstractions
25    // (docs/DESIGN-telemetry-secrets.md) instead of growing bespoke features.
26    async fn get_json<T>(&self, path: &SecretPath, ctx: &TenantCtx) -> NodeResult<Option<T>>
27    where
28        T: serde::de::DeserializeOwned + Send;
29
30    async fn put_json<T>(&self, path: &SecretPath, ctx: &TenantCtx, value: &T) -> NodeResult<()>
31    where
32        T: serde::Serialize + Sync + Send;
33}
34
35#[async_trait]
36impl SecretsResolver for DefaultResolver {
37    async fn get_json<T>(&self, path: &SecretPath, _ctx: &TenantCtx) -> NodeResult<Option<T>>
38    where
39        T: serde::de::DeserializeOwned + Send,
40    {
41        let uri = path.to_uri();
42        match self.core().get_json::<T>(&uri).await {
43            Ok(value) => Ok(Some(value)),
44            Err(SecretsError::Core(CoreError::NotFound { .. })) => Ok(None),
45            Err(err) => Err(NodeError::new(
46                "secrets_read",
47                format!("failed to fetch secret {}", path.as_str()),
48            )
49            .with_source(err)),
50        }
51    }
52
53    async fn put_json<T>(&self, path: &SecretPath, _ctx: &TenantCtx, value: &T) -> NodeResult<()>
54    where
55        T: serde::Serialize + Sync + Send,
56    {
57        let uri = path.to_uri();
58        self.core()
59            .put_json(&uri, value)
60            .await
61            .map(|_| ())
62            .map_err(|err| {
63                NodeError::new(
64                    "secrets_write",
65                    format!("failed to store secret {}", path.as_str()),
66                )
67                .with_source(err)
68            })
69    }
70}