bitwarden_access_connector/resolver/
mod.rs1pub(crate) mod config;
5pub(crate) mod env;
6
7use std::collections::HashMap;
8
9use async_trait::async_trait;
10use bitwarden_pam_sealed::SealedTargetSystemKind;
11use bitwarden_sensitive_value::Sensitive;
12use uuid::Uuid;
13
14#[derive(Debug)]
17pub(crate) struct ResolvedCredentials {
18 inner: HashMap<String, Sensitive<String>>,
19}
20
21impl ResolvedCredentials {
22 pub(crate) fn new() -> Self {
23 Self {
24 inner: HashMap::new(),
25 }
26 }
27
28 pub(crate) fn insert(&mut self, key: String, value: String) {
29 self.inner.insert(key, Sensitive::from(value));
30 }
31
32 pub(crate) fn get(&self, key: &str) -> Option<&Sensitive<String>> {
33 self.inner.get(key)
34 }
35
36 pub(crate) fn iter(&self) -> impl Iterator<Item = (&String, &Sensitive<String>)> {
37 self.inner.iter()
38 }
39}
40
41impl Default for ResolvedCredentials {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47#[derive(Debug, thiserror::Error)]
49pub(crate) enum ResolveError {
50 #[error("missing required credential variables: {}", .0.join(", "))]
53 Missing(Vec<String>),
54}
55
56#[async_trait]
59pub(crate) trait CredentialResolver: Send + Sync {
60 async fn resolve(
62 &self,
63 target_system_id: Uuid,
64 kind: SealedTargetSystemKind,
65 ) -> Result<ResolvedCredentials, ResolveError>;
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn resolved_credentials_get_and_insert() {
74 let mut creds = ResolvedCredentials::new();
75 assert!(creds.get("FOO").is_none());
76 creds.insert("FOO".to_string(), "bar".to_string());
77 assert!(creds.get("FOO").is_some());
78 }
79
80 #[test]
81 fn resolve_error_missing_contains_names() {
82 let names = vec!["TENANT_ID".to_string(), "CLIENT_SECRET".to_string()];
83 let err = ResolveError::Missing(names.clone());
84 let msg = err.to_string();
85 assert!(msg.contains("TENANT_ID"));
86 assert!(msg.contains("CLIENT_SECRET"));
87 }
88}