zeph_vault/env.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Environment-variable vault backend.
5//!
6//! [`EnvVaultProvider`] reads secrets directly from process environment variables.
7//! Designed for quick local development and CI environments.
8
9use std::future::Future;
10use std::pin::Pin;
11
12use zeph_common::secret::VaultError;
13
14use crate::VaultProvider;
15
16/// Vault backend that reads secrets from environment variables.
17///
18/// This backend is designed for quick local development and CI environments where injecting
19/// environment variables is convenient. In production, prefer [`crate::AgeVaultProvider`].
20///
21/// [`get_secret`][VaultProvider::get_secret] reads any environment variable by name.
22/// [`list_keys`][VaultProvider::list_keys] returns only variables whose names start with
23/// `ZEPH_SECRET_`, preventing accidental exposure of unrelated process environment.
24///
25/// # Examples
26///
27/// ```no_run
28/// use zeph_vault::{EnvVaultProvider, VaultProvider as _};
29///
30/// # async fn example() {
31/// let vault = EnvVaultProvider;
32/// // Returns None for variables that are not set.
33/// let result = vault.get_secret("ZEPH_TEST_NONEXISTENT_99999").await.unwrap();
34/// assert!(result.is_none());
35/// # }
36/// ```
37pub struct EnvVaultProvider;
38
39impl VaultProvider for EnvVaultProvider {
40 fn get_secret(
41 &self,
42 key: &str,
43 ) -> Pin<Box<dyn Future<Output = Result<Option<String>, VaultError>> + Send + '_>> {
44 let key = key.to_owned();
45 Box::pin(async move { Ok(std::env::var(&key).ok()) })
46 }
47
48 fn list_keys(&self) -> Vec<String> {
49 let mut keys: Vec<String> = std::env::vars()
50 .filter(|(k, _)| k.starts_with("ZEPH_SECRET_"))
51 .map(|(k, _)| k)
52 .collect();
53 keys.sort_unstable();
54 keys
55 }
56}