claude_agent/auth/providers/
environment.rs

1//! Environment variable credential provider.
2
3use async_trait::async_trait;
4
5use crate::auth::{Credential, CredentialProvider};
6use crate::{Error, Result};
7
8const DEFAULT_ENV_VAR: &str = "ANTHROPIC_API_KEY";
9
10/// Provider that reads API key from environment variable.
11pub struct EnvironmentProvider {
12    env_var: String,
13}
14
15impl EnvironmentProvider {
16    /// Create provider using default ANTHROPIC_API_KEY.
17    pub fn new() -> Self {
18        Self {
19            env_var: DEFAULT_ENV_VAR.to_string(),
20        }
21    }
22
23    /// Create provider with custom environment variable.
24    pub fn with_var(env_var: impl Into<String>) -> Self {
25        Self {
26            env_var: env_var.into(),
27        }
28    }
29}
30
31impl Default for EnvironmentProvider {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37#[async_trait]
38impl CredentialProvider for EnvironmentProvider {
39    fn name(&self) -> &str {
40        "environment"
41    }
42
43    async fn resolve(&self) -> Result<Credential> {
44        std::env::var(&self.env_var)
45            .map(Credential::api_key)
46            .map_err(|_| Error::auth(format!("{} not set", self.env_var)))
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[tokio::test]
55    async fn test_environment_provider_missing() {
56        unsafe { std::env::remove_var("TEST_API_KEY_NOT_SET") };
57        let provider = EnvironmentProvider::with_var("TEST_API_KEY_NOT_SET");
58        assert!(provider.resolve().await.is_err());
59    }
60
61    #[tokio::test]
62    async fn test_environment_provider_set() {
63        unsafe { std::env::set_var("TEST_API_KEY_SET", "test-key") };
64        let provider = EnvironmentProvider::with_var("TEST_API_KEY_SET");
65        let cred = provider.resolve().await.unwrap();
66        assert!(matches!(cred, Credential::ApiKey(k) if k == "test-key"));
67        unsafe { std::env::remove_var("TEST_API_KEY_SET") };
68    }
69}