Finishes the sweep of prose that said the publisher unit writes or carries the OIDC client secrets: rust docs, nix comments and option descriptions, test names and docs.
113 lines
3.9 KiB
Rust
113 lines
3.9 KiB
Rust
//! The review classifier agreement: where its inference keys, its queue
|
|
//! client secret and its forge token live in the store, and what each object
|
|
//! holds.
|
|
//!
|
|
//! The operator writes the keys by hand in the store's UI; the classifier
|
|
//! reads them and the client secret under its own certificate, a key once per
|
|
//! run. Its read stanza in `swarm-bao.nix` names exactly these three paths. The forge token is `swarm-controller`'s alone: it mints it, and
|
|
//! posts the classifier's reviews with it.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{
|
|
Error,
|
|
path::{Kind, principal_prefix},
|
|
};
|
|
|
|
/// The classifier's name segment under [`Kind::Service`].
|
|
const SERVICE: &str = "review-classifier";
|
|
|
|
/// The path holding the Anthropic API key the classifier runs `claude` with.
|
|
///
|
|
/// # Errors
|
|
/// Never in practice: the name segment is a constant. The `Result` is
|
|
/// [`principal_prefix`]'s.
|
|
pub fn api_key_path() -> Result<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, SERVICE)?;
|
|
Ok(format!("{prefix}/anthropic-api-key"))
|
|
}
|
|
|
|
/// The path holding the provider key the classifier runs an ACP agent with,
|
|
/// as a [`crate::acp::ProviderKey`].
|
|
///
|
|
/// # Errors
|
|
/// Never in practice: the name segment is a constant. The `Result` is
|
|
/// [`principal_prefix`]'s.
|
|
pub fn acp_provider_key_path() -> Result<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, SERVICE)?;
|
|
Ok(format!("{prefix}/acp-provider"))
|
|
}
|
|
|
|
/// What [`api_key_path`] holds.
|
|
///
|
|
/// No `Debug`: `api_key` is a live provider credential.
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct ApiKey {
|
|
/// The key itself, under the field name [`crate::acp::ProviderKey`] uses.
|
|
/// The operator enters this field name in the store's UI.
|
|
pub api_key: String,
|
|
}
|
|
|
|
/// The path holding the token of the classifier's forge account, as a
|
|
/// [`crate::forge::Credential`].
|
|
///
|
|
/// # Errors
|
|
/// Never in practice: the name segment is a constant. The `Result` is
|
|
/// [`principal_prefix`]'s.
|
|
pub fn forge_token_path() -> Result<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, SERVICE)?;
|
|
Ok(format!("{prefix}/forge/token"))
|
|
}
|
|
|
|
/// The path holding the queue client secret of the classifier's OIDC client
|
|
/// `client_id`, where authelia's mint puts every swarm service's.
|
|
///
|
|
/// # Errors
|
|
/// [`Error::PathSegment`] when `client_id` is not a single path segment.
|
|
pub fn client_secret_path(client_id: &str) -> Result<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, client_id)?;
|
|
Ok(format!("{prefix}/oidc/client"))
|
|
}
|
|
|
|
/// What [`client_secret_path`] holds.
|
|
///
|
|
/// No `Debug`: `value` authenticates the classifier at the queue.
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct ClientSecret {
|
|
/// The secret, under the field name authelia's mint writes.
|
|
pub value: String,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn the_paths_are_the_ones_the_store_grants() {
|
|
// Spelled out: the operator types the first into the store's UI, and
|
|
// `swarm-bao.nix` grants each literal.
|
|
assert_eq!(
|
|
api_key_path().expect("a constant segment is legal"),
|
|
"swarm/services/review-classifier/anthropic-api-key"
|
|
);
|
|
assert_eq!(
|
|
acp_provider_key_path().expect("a constant segment is legal"),
|
|
"swarm/services/review-classifier/acp-provider"
|
|
);
|
|
assert_eq!(
|
|
forge_token_path().expect("a constant segment is legal"),
|
|
"swarm/services/review-classifier/forge/token"
|
|
);
|
|
assert_eq!(
|
|
client_secret_path("swarm-review-classifier").expect("a plain id is legal"),
|
|
"swarm/services/swarm-review-classifier/oidc/client"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn the_stored_key_field_is_api_key() {
|
|
let stored: ApiKey =
|
|
serde_json::from_str(r#"{"api_key":"k"}"#).expect("the documented shape decodes");
|
|
assert_eq!(stored.api_key, "k");
|
|
}
|
|
}
|