1#![deny(missing_docs)]
2use async_trait::async_trait;
9use layer0::secret::SecretSource;
10use neuron_auth::AuthProvider;
11use neuron_secret::{SecretError, SecretLease, SecretResolver};
12use std::sync::Arc;
13
14pub struct AwsResolver {
16 _auth: Arc<dyn AuthProvider>,
17}
18
19impl AwsResolver {
20 pub fn new(auth: Arc<dyn AuthProvider>) -> Self {
22 Self { _auth: auth }
23 }
24}
25
26#[async_trait]
27impl SecretResolver for AwsResolver {
28 async fn resolve(&self, source: &SecretSource) -> Result<SecretLease, SecretError> {
29 match source {
30 SecretSource::AwsSecretsManager { secret_id, region } => {
31 Err(SecretError::BackendError(format!(
32 "AwsResolver is a stub — would resolve {secret_id} in region {region:?}"
33 )))
34 }
35 _ => Err(SecretError::NoResolver("aws".into())),
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use neuron_auth::{AuthError, AuthRequest, AuthToken};
44
45 struct StubAuth;
46 #[async_trait]
47 impl AuthProvider for StubAuth {
48 async fn provide(&self, _request: &AuthRequest) -> Result<AuthToken, AuthError> {
49 Ok(AuthToken::permanent(b"stub".to_vec()))
50 }
51 }
52
53 fn _assert_send_sync<T: Send + Sync>() {}
54
55 #[test]
56 fn object_safety() {
57 _assert_send_sync::<Box<dyn SecretResolver>>();
58 _assert_send_sync::<Arc<dyn SecretResolver>>();
59 let auth: Arc<dyn AuthProvider> = Arc::new(StubAuth);
60 let _: Arc<dyn SecretResolver> = Arc::new(AwsResolver::new(auth));
61 }
62
63 #[tokio::test]
64 async fn matches_aws_source() {
65 let auth: Arc<dyn AuthProvider> = Arc::new(StubAuth);
66 let resolver = AwsResolver::new(auth);
67 let source = SecretSource::AwsSecretsManager {
68 secret_id: "my-secret".into(),
69 region: Some("us-east-1".into()),
70 };
71 let err = resolver.resolve(&source).await.unwrap_err();
72 assert!(matches!(err, SecretError::BackendError(_)));
73 assert!(err.to_string().contains("stub"));
74 }
75
76 #[tokio::test]
77 async fn rejects_wrong_source() {
78 let auth: Arc<dyn AuthProvider> = Arc::new(StubAuth);
79 let resolver = AwsResolver::new(auth);
80 let source = SecretSource::Vault {
81 mount: "secret".into(),
82 path: "data/key".into(),
83 };
84 let err = resolver.resolve(&source).await.unwrap_err();
85 assert!(matches!(err, SecretError::NoResolver(_)));
86 }
87}