mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
Introduce a Database trait abstraction (~60 async methods) enabling compile-time backend selection between PostgreSQL and libSQL/Turso. Convert all modules from concrete Store to Arc<dyn Database>, add LibSqlSecretsStore and LibSqlWasmToolStore implementations, wire libsql stores throughout CLI and main entry points, and make the setup wizard backend-agnostic. Key changes: - src/db/: Database trait, PostgresDatabase adapter, LibSqlBackend with native SQLite-dialect SQL, and idempotent migration system - src/secrets/store.rs: LibSqlSecretsStore (all 8 trait methods) - src/tools/wasm/storage.rs: LibSqlWasmToolStore (all 7 trait methods) - src/main.rs, cli/tool.rs, cli/mcp.rs: backend-conditional wiring - src/setup/channels.rs: SecretsContext uses Arc<dyn SecretsStore> - Feature-gate postgres-only tests and examples Co-Authored-By: Claude Opus 4.6 <[email protected]>
79 lines
3.6 KiB
Rust
79 lines
3.6 KiB
Rust
//! Secrets management for secure credential storage and injection.
|
|
//!
|
|
//! This module provides:
|
|
//! - AES-256-GCM encrypted secret storage
|
|
//! - Per-secret key derivation (HKDF-SHA256)
|
|
//! - PostgreSQL persistence
|
|
//! - OS keychain integration for master key
|
|
//! - Access control for WASM tools
|
|
//!
|
|
//! # Security Model
|
|
//!
|
|
//! ```text
|
|
//! ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
//! │ Secret Lifecycle │
|
|
//! │ │
|
|
//! │ User stores secret ──► Encrypt with AES-256-GCM ──► Store in PostgreSQL │
|
|
//! │ (per-secret key via HKDF) │
|
|
//! │ │
|
|
//! │ WASM requests HTTP ──► Host checks allowlist ──► Decrypt secret ──► │
|
|
//! │ & allowed_secrets (in memory only) │
|
|
//! │ │ │
|
|
//! │ ▼ │
|
|
//! │ Inject into request ──► Execute HTTP call │
|
|
//! │ (WASM never sees value) │
|
|
//! │ │ │
|
|
//! │ ▼ │
|
|
//! │ Leak detector scans ──► Return response to WASM │
|
|
//! │ response for secrets │
|
|
//! └─────────────────────────────────────────────────────────────────────────────┘
|
|
//! ```
|
|
//!
|
|
//! # Master Key Storage
|
|
//!
|
|
//! The master key for encrypting secrets can come from:
|
|
//! - **OS Keychain** (recommended for local installs): Auto-generated and stored securely
|
|
//! - **Environment variable** (for CI/Docker): Set `SECRETS_MASTER_KEY`
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```ignore
|
|
//! use ironclaw::secrets::{SecretsStore, PostgresSecretsStore, SecretsCrypto, CreateSecretParams};
|
|
//! use secrecy::SecretString;
|
|
//!
|
|
//! // Initialize crypto with master key from environment
|
|
//! let master_key = SecretString::from(std::env::var("SECRETS_MASTER_KEY")?);
|
|
//! let crypto = Arc::new(SecretsCrypto::new(master_key)?);
|
|
//!
|
|
//! // Create store
|
|
//! let store = PostgresSecretsStore::new(pool, crypto);
|
|
//!
|
|
//! // Store a secret
|
|
//! store.create("user_123", CreateSecretParams::new("openai_key", "sk-...")).await?;
|
|
//!
|
|
//! // Check if secret exists (WASM can call this)
|
|
//! let exists = store.exists("user_123", "openai_key").await?;
|
|
//!
|
|
//! // Decrypt for injection (host boundary only)
|
|
//! let decrypted = store.get_decrypted("user_123", "openai_key").await?;
|
|
//! ```
|
|
|
|
mod crypto;
|
|
pub mod keychain;
|
|
mod store;
|
|
mod types;
|
|
|
|
pub use crypto::SecretsCrypto;
|
|
#[cfg(feature = "libsql")]
|
|
pub use store::LibSqlSecretsStore;
|
|
#[cfg(feature = "postgres")]
|
|
pub use store::PostgresSecretsStore;
|
|
pub use store::SecretsStore;
|
|
pub use types::{
|
|
CreateSecretParams, CredentialLocation, CredentialMapping, DecryptedSecret, Secret,
|
|
SecretError, SecretRef,
|
|
};
|
|
|
|
#[cfg(test)]
|
|
pub use store::testing::InMemorySecretsStore;
|