Skip to main content

rtb_credentials/
reference.rs

1//! Config-serialisable reference to a credential.
2
3use secrecy::SecretString;
4use serde::Deserialize;
5
6/// Declarative reference to a credential that the [`Resolver`] walks
7/// through the documented precedence chain:
8/// `env` > `keychain` > `literal` > `fallback_env`.
9///
10/// Downstream tools carry this in their config structs, e.g.
11///
12/// ```
13/// use rtb_credentials::CredentialRef;
14///
15/// #[derive(serde::Deserialize)]
16/// struct AnthropicCfg {
17///     api: CredentialRef,
18/// }
19/// ```
20///
21/// [`Resolver`]: crate::resolver::Resolver
22/// `Serialize` is deliberately **not** derived: `SecretString` does
23/// not implement `Serialize` (secrecy crate removed it to prevent
24/// blind round-trip leaks). Tools writing credentials to config
25/// should go through a dedicated "write secret" path that redacts
26/// or skips the literal.
27#[derive(Debug, Clone, Default, Deserialize)]
28#[serde(deny_unknown_fields)]
29pub struct CredentialRef {
30    /// Name of an environment variable carrying the secret.
31    /// Checked first.
32    #[serde(default)]
33    pub env: Option<String>,
34
35    /// OS-keychain lookup descriptor. Checked second.
36    #[serde(default)]
37    pub keychain: Option<KeychainRef>,
38
39    /// Literal secret embedded in config. Checked third. Refused
40    /// when the process is running under `CI=true` (see
41    /// [`CredentialError::LiteralRefusedInCi`]).
42    ///
43    /// Note: `SecretString` round-trips through serde with the
44    /// secrecy crate's `serde` feature. The raw value is zeroed on
45    /// drop and redacted in `Debug`.
46    ///
47    /// [`CredentialError::LiteralRefusedInCi`]: crate::error::CredentialError::LiteralRefusedInCi
48    #[serde(default)]
49    pub literal: Option<SecretString>,
50
51    /// Name of an ecosystem-default env var used as a last-chance
52    /// fallback (e.g. `ANTHROPIC_API_KEY`). Checked last.
53    #[serde(default)]
54    pub fallback_env: Option<String>,
55}
56
57/// Reference to an entry in an OS keychain.
58#[derive(Debug, Clone, Deserialize, serde::Serialize)]
59#[serde(deny_unknown_fields)]
60pub struct KeychainRef {
61    /// Keychain "service" / collection name — typically the tool's
62    /// name (`mytool`) or a provider identifier (`anthropic`).
63    pub service: String,
64    /// Account / username component — typically the user's login or
65    /// an API-provider identifier (`default`).
66    pub account: String,
67}