1pub mod agent;
5pub mod auth;
6pub mod memory;
7pub mod platform;
8pub mod policy;
9pub mod session;
10
11use std::fmt;
12
13pub use agent::AgentSecretAccess;
14pub use auth::AgentVerifier;
15pub use memory::SecretBytes;
16pub use policy::SecretPolicy;
17pub use session::SessionContext;
18
19#[cfg(feature = "onepassword")]
20pub use platform::onepassword::OnePasswordStore;
21
22#[derive(Debug)]
23pub enum SecretError {
24 NotSupported,
25 NotAuthorized,
26 InvalidInput,
27 StorageFailure,
28}
29
30impl fmt::Display for SecretError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 let msg = match self {
33 SecretError::NotSupported => "operation not supported",
34 SecretError::NotAuthorized => "not authorized",
35 SecretError::InvalidInput => "invalid input",
36 SecretError::StorageFailure => "storage failure",
37 };
38 f.write_str(msg)
39 }
40}
41
42impl std::error::Error for SecretError {}
43
44pub type SecretResult<T> = Result<T, SecretError>;
45
46pub trait SecretStore: Send + Sync {
47 fn put(&self, key: &str, secret: &[u8], policy: SecretPolicy) -> SecretResult<()>;
48 fn get(&self, key: &str) -> SecretResult<SecretBytes>;
49 fn delete(&self, key: &str) -> SecretResult<()>;
50 fn list_keys(&self) -> SecretResult<Vec<String>>;
51}
52
53pub fn default_store() -> Box<dyn SecretStore> {
54 platform::default_store()
55}
56
57#[cfg(test)]
58mod tests {
59 use std::collections::HashMap;
60 use std::sync::Mutex;
61
62 use super::*;
63 use crate::agent::AgentSecretAccess;
64 use crate::auth::AgentVerifier;
65
66 struct AllowVerifier;
67
68 impl AgentVerifier for AllowVerifier {
69 fn verify(&self, _session: &SessionContext) -> SecretResult<()> {
70 Ok(())
71 }
72 }
73
74 struct DenyVerifier;
75
76 impl AgentVerifier for DenyVerifier {
77 fn verify(&self, _session: &SessionContext) -> SecretResult<()> {
78 Err(SecretError::NotAuthorized)
79 }
80 }
81
82 struct MemoryStore {
83 entries: Mutex<HashMap<String, Vec<u8>>>,
84 }
85
86 impl MemoryStore {
87 fn new() -> Self {
88 Self {
89 entries: Mutex::new(HashMap::new()),
90 }
91 }
92 }
93
94 impl SecretStore for MemoryStore {
95 fn put(&self, key: &str, secret: &[u8], _policy: SecretPolicy) -> SecretResult<()> {
96 let mut guard = self.entries.lock().map_err(|_| SecretError::StorageFailure)?;
97 guard.insert(key.to_string(), secret.to_vec());
98 Ok(())
99 }
100
101 fn get(&self, key: &str) -> SecretResult<SecretBytes> {
102 let guard = self.entries.lock().map_err(|_| SecretError::StorageFailure)?;
103 let value = guard
104 .get(key)
105 .ok_or(SecretError::InvalidInput)?
106 .clone();
107 Ok(SecretBytes::new(value))
108 }
109
110 fn delete(&self, key: &str) -> SecretResult<()> {
111 let mut guard = self.entries.lock().map_err(|_| SecretError::StorageFailure)?;
112 guard.remove(key);
113 Ok(())
114 }
115
116 fn list_keys(&self) -> SecretResult<Vec<String>> {
117 let guard = self.entries.lock().map_err(|_| SecretError::StorageFailure)?;
118 Ok(guard.keys().cloned().collect())
119 }
120 }
121
122 #[test]
123 fn agent_access_allows_put_get_delete_when_verified() {
124 let store = MemoryStore::new();
125 let verifier = AllowVerifier;
126 let access = AgentSecretAccess::new(&store, &verifier);
127 let session = SessionContext::new("agent", "session");
128
129 access
130 .put_for_session(&session, "key", b"value", SecretPolicy::default())
131 .unwrap();
132
133 let secret = access.get_for_session(&session, "key").unwrap();
134 let got = secret.expose(|bytes| bytes.to_vec());
135 assert_eq!(got, b"value");
136
137 access.delete_for_session(&session, "key").unwrap();
138 }
139
140 #[test]
141 fn agent_access_denies_when_verifier_rejects() {
142 let store = MemoryStore::new();
143 let verifier = DenyVerifier;
144 let access = AgentSecretAccess::new(&store, &verifier);
145 let session = SessionContext::new("agent", "session");
146
147 let err = access
148 .put_for_session(&session, "key", b"value", SecretPolicy::default())
149 .unwrap_err();
150 assert!(matches!(err, SecretError::NotAuthorized));
151 }
152
153 #[test]
154 fn secret_error_display_formats_messages() {
155 assert_eq!(SecretError::NotSupported.to_string(), "operation not supported");
156 assert_eq!(SecretError::NotAuthorized.to_string(), "not authorized");
157 assert_eq!(SecretError::InvalidInput.to_string(), "invalid input");
158 assert_eq!(SecretError::StorageFailure.to_string(), "storage failure");
159 }
160
161 #[test]
162 fn default_store_constructs_a_backend() {
163 let _store = default_store();
164 }
165
166 #[test]
167 fn memory_store_lists_inserted_keys() {
168 let store = MemoryStore::new();
169 store
170 .put("alpha", b"one", SecretPolicy::default())
171 .expect("put alpha");
172 store
173 .put("beta", b"two", SecretPolicy::default())
174 .expect("put beta");
175
176 let mut keys = store.list_keys().expect("list keys");
177 keys.sort();
178
179 assert_eq!(keys, vec!["alpha".to_string(), "beta".to_string()]);
180 }
181}