Skip to main content

agent_sdk_provider/
auth.rs

1use std::{env, fmt};
2
3use agent_sdk_core::AgentError;
4
5use crate::error::host_configuration_needed;
6
7#[derive(Clone, Eq, PartialEq)]
8/// Runtime API-key material for a provider adapter.
9///
10/// Hosts choose how to resolve and authorize this value. The wrapper only keeps
11/// accidental debug output redacted and reports missing configuration through
12/// the SDK error contract.
13pub struct ProviderApiKey {
14    value: String,
15    source: ProviderSecretSource,
16}
17
18impl ProviderApiKey {
19    /// Creates an API key from an already resolved host secret.
20    pub fn new(value: impl Into<String>) -> Result<Self, AgentError> {
21        let value = value.into();
22        if value.trim().is_empty() {
23            return Err(host_configuration_needed(
24                "provider API key must not be empty",
25            ));
26        }
27        Ok(Self {
28            value,
29            source: ProviderSecretSource::Direct,
30        })
31    }
32
33    /// Resolves an API key from an environment variable.
34    pub fn from_env(env_var: impl Into<String>) -> Result<Self, AgentError> {
35        let env_var = env_var.into();
36        let value = env::var(&env_var).map_err(|_| {
37            host_configuration_needed(format!(
38                "missing provider API key environment variable {env_var}"
39            ))
40        })?;
41        if value.trim().is_empty() {
42            return Err(host_configuration_needed(format!(
43                "provider API key environment variable {env_var} is empty"
44            )));
45        }
46        Ok(Self {
47            value,
48            source: ProviderSecretSource::Env(env_var),
49        })
50    }
51
52    pub(crate) fn expose_secret(&self) -> &str {
53        &self.value
54    }
55
56    /// Returns a non-secret source label suitable for diagnostics.
57    pub fn source_label(&self) -> &str {
58        match &self.source {
59            ProviderSecretSource::Direct => "direct",
60            ProviderSecretSource::Env(env_var) => env_var.as_str(),
61        }
62    }
63}
64
65impl fmt::Debug for ProviderApiKey {
66    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67        formatter
68            .debug_struct("ProviderApiKey")
69            .field("source", &self.source)
70            .field("value", &"<redacted>")
71            .finish()
72    }
73}
74
75#[derive(Clone, Eq, PartialEq)]
76enum ProviderSecretSource {
77    Direct,
78    Env(String),
79}
80
81impl fmt::Debug for ProviderSecretSource {
82    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
83        match self {
84            Self::Direct => formatter.write_str("direct"),
85            Self::Env(env_var) => formatter.debug_tuple("env").field(env_var).finish(),
86        }
87    }
88}