Skip to main content

neuron_secret_aws/
lib.rs

1#![deny(missing_docs)]
2//! Stub secret resolver for AWS Secrets Manager.
3//!
4//! This crate provides the correct trait impl shape for an AWS Secrets Manager resolver.
5//! The actual AWS SDK integration is not implemented — all resolve calls return
6//! `SecretError::BackendError`.
7
8use async_trait::async_trait;
9use layer0::secret::SecretSource;
10use neuron_auth::AuthProvider;
11use neuron_secret::{SecretError, SecretLease, SecretResolver};
12use std::sync::Arc;
13
14/// Stub resolver for AWS Secrets Manager.
15pub struct AwsResolver {
16    _auth: Arc<dyn AuthProvider>,
17}
18
19impl AwsResolver {
20    /// Create a new AWS resolver (stub).
21    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}