Skip to main content

elizaos_plugin_secrets_manager/
lib.rs

1//! elizaOS Secrets Manager Plugin
2//!
3//! Multi-level secrets management with encryption, validation, and dynamic plugin activation.
4//!
5//! # Overview
6//!
7//! This crate provides a comprehensive secrets management solution for elizaOS agents:
8//!
9//! - **Multi-level storage**: Global (agent-wide), World (server/channel), and User (per-user) secrets
10//! - **Strong encryption**: AES-256-GCM encryption with secure key derivation
11//! - **Validation**: Built-in validators for common API keys (OpenAI, Anthropic, etc.)
12//! - **Dynamic activation**: Plugins can be activated once their required secrets are available
13//! - **Access logging**: Track who accessed what secrets and when
14//!
15//! # Example
16//!
17//! ```rust,no_run
18//! use elizaos_plugin_secrets_manager::{
19//!     SecretsService, SecretsServiceConfig, SecretContext
20//! };
21//!
22//! #[tokio::main]
23//! async fn main() {
24//!     // Create the service
25//!     let service = SecretsService::new("agent-123", SecretsServiceConfig::default());
26//!     service.start().await.unwrap();
27//!
28//!     // Set a global secret
29//!     service.set_global("OPENAI_API_KEY", "sk-...", None).await.unwrap();
30//!
31//!     // Get the secret
32//!     let key = service.get_global("OPENAI_API_KEY").await.unwrap();
33//!     println!("API Key: {:?}", key);
34//!
35//!     service.stop().await.unwrap();
36//! }
37//! ```
38
39pub mod crypto;
40pub mod service;
41pub mod storage;
42pub mod types;
43pub mod validation;
44
45// Re-export main types
46pub use crypto::{
47    decrypt, derive_key_from_agent_id, encrypt, generate_key, generate_salt, hash_value,
48    is_encrypted_secret, mask_secret, parse_encrypted_secret, secure_compare, KeyManager,
49    ALGORITHM_AES_GCM, ENCRYPTION_VERSION,
50};
51
52pub use service::{SecretChangeCallback, SecretsService, SecretsServiceConfig};
53
54pub use storage::{
55    CompositeSecretStorage, MemorySecretStorage, SecretStorage, StorageEntry,
56};
57
58pub use types::{
59    EncryptedSecret, PluginRequirementStatus, PluginSecretRequirement, SecretAccessLog,
60    SecretChangeEvent, SecretChangeType, SecretConfig, SecretContext, SecretLevel,
61    SecretMetadata, SecretPermissionType, SecretStatus, SecretType, SecretsError, SecretsResult,
62    StorageBackend,
63};
64
65pub use validation::{
66    get_validator, infer_validation_strategy, register_validator, validate_secret,
67    ValidationResult,
68};
69
70/// Plugin information.
71pub const PLUGIN_NAME: &str = "secrets-manager";
72pub const PLUGIN_VERSION: &str = env!("CARGO_PKG_VERSION");
73pub const PLUGIN_DESCRIPTION: &str =
74    "Multi-level secrets management with encryption and dynamic plugin activation";
75
76/// Service type identifier.
77pub const SECRETS_SERVICE_TYPE: &str = "SECRETS";
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_plugin_info() {
85        assert_eq!(PLUGIN_NAME, "secrets-manager");
86        assert!(!PLUGIN_VERSION.is_empty());
87    }
88
89    #[tokio::test]
90    async fn test_integration() {
91        // Create service
92        let service = SecretsService::new("test-agent", SecretsServiceConfig::default());
93        service.start().await.unwrap();
94
95        // Test global secrets
96        service.set_global("API_KEY", "test-value", None).await.unwrap();
97        let value = service.get_global("API_KEY").await.unwrap();
98        assert_eq!(value, Some("test-value".to_string()));
99
100        // Test world secrets
101        service.set_world("WORLD_SECRET", "world-value", "world-1", None).await.unwrap();
102        let value = service.get_world("WORLD_SECRET", "world-1").await.unwrap();
103        assert_eq!(value, Some("world-value".to_string()));
104
105        // Test user secrets
106        service.set_user("USER_SECRET", "user-value", "user-1", None).await.unwrap();
107        let value = service.get_user("USER_SECRET", "user-1").await.unwrap();
108        assert_eq!(value, Some("user-value".to_string()));
109
110        // Test isolation
111        assert!(service.get_world("WORLD_SECRET", "world-2").await.unwrap().is_none());
112        assert!(service.get_user("USER_SECRET", "user-2").await.unwrap().is_none());
113
114        service.stop().await.unwrap();
115    }
116
117    #[tokio::test]
118    async fn test_encryption_roundtrip() {
119        // Test that encryption/decryption works correctly through the service
120        let service = SecretsService::new("encrypt-test", SecretsServiceConfig::default());
121        service.start().await.unwrap();
122
123        let secret_value = "super-secret-api-key-12345";
124        service.set_global("ENCRYPTED_KEY", secret_value, None).await.unwrap();
125
126        let retrieved = service.get_global("ENCRYPTED_KEY").await.unwrap();
127        assert_eq!(retrieved, Some(secret_value.to_string()));
128
129        service.stop().await.unwrap();
130    }
131}