rtb_credentials/bearing.rs
1//! [`CredentialBearing`] — the introspection seam used by
2//! `rtb-cli`'s `credentials` subtree to enumerate the
3//! [`CredentialRef`]s a downstream tool's config knows about.
4//!
5//! # Design rationale
6//!
7//! `credentials list / test / doctor` need to walk every credential
8//! a tool's typed config carries. Three options were considered in
9//! the v0.4 scope addendum (§4.1 / O1):
10//!
11//! - A `serde`-trait visitor that walks the deserialised `Config<C>`.
12//! Heavyweight; needs custom plumbing.
13//! - A `schemars`-driven walk over `Config::schema()`. Brittle once
14//! `$ref` resolution, `oneOf`/`anyOf` for `Option`, and JSON-pointer
15//! ↔ Rust path mismatches enter the picture.
16//! - **An explicit trait downstream tools implement.** Five lines per
17//! tool, no schema-walking, no edge cases. **Chosen.**
18//!
19//! A `#[derive(CredentialBearing)]` proc-macro is deferred to v0.5.
20
21use crate::reference::CredentialRef;
22
23/// Exposes the [`CredentialRef`]s in a downstream tool's config to
24/// `rtb-cli`'s `credentials` subtree.
25///
26/// Tools implement this on their typed `Config` struct (or any other
27/// type the `App` carries that owns its credentials):
28///
29/// ```rust
30/// use rtb_credentials::{CredentialBearing, CredentialRef};
31///
32/// struct MyConfig {
33/// anthropic: AnthropicSection,
34/// github: GithubSection,
35/// }
36/// struct AnthropicSection { api: CredentialRef }
37/// struct GithubSection { token: CredentialRef }
38///
39/// impl CredentialBearing for MyConfig {
40/// fn credentials(&self) -> Vec<(&'static str, &CredentialRef)> {
41/// vec![
42/// ("anthropic", &self.anthropic.api),
43/// ("github", &self.github.token),
44/// ]
45/// }
46/// }
47/// ```
48///
49/// The `&'static str` name is the human-friendly identifier surfaced
50/// by `credentials list` and accepted as the argument to
51/// `credentials add / remove / test`.
52pub trait CredentialBearing {
53 /// Yield `(name, &CredentialRef)` pairs for every credential
54 /// this value owns.
55 fn credentials(&self) -> Vec<(&'static str, &CredentialRef)>;
56}
57
58/// Blanket impl for `()` — tools that haven't typed their config
59/// yet still build. `credentials list` reports an empty set.
60impl CredentialBearing for () {
61 fn credentials(&self) -> Vec<(&'static str, &CredentialRef)> {
62 Vec::new()
63 }
64}