//! The CI metrics poller agreement: where its forge token and its OIDC client //! secret live in the store, and what each object holds. //! //! swarm-controller mints the forge token; the poller reads it, and its client //! secret, under its own certificate. Its read stanza in `swarm-bao.nix` names //! exactly these two paths. use serde::{Deserialize, Serialize}; use crate::{ Error, path::{Kind, principal_prefix}, }; /// The poller's name segment under [`Kind::Service`]. const SERVICE: &str = "ci-metrics"; /// The path holding the token of the poller's read-only 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 { let prefix = principal_prefix(Kind::Service, SERVICE)?; Ok(format!("{prefix}/forge/token")) } /// The path holding the secret of the poller's OIDC client `client_id`, where /// `swarm-secret-publisher.nix` 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 { let prefix = principal_prefix(Kind::Service, client_id)?; Ok(format!("{prefix}/oidc/client")) } /// What [`client_secret_path`] holds. /// /// No `Debug`: `value` authenticates the poller at the collector. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ClientSecret { /// The secret, under the field name the publisher writes. pub value: String, } #[cfg(test)] mod tests { use super::*; #[test] fn the_paths_are_the_ones_the_store_grants() { // Spelled out: `swarm-bao.nix` grants each literal. assert_eq!( forge_token_path().expect("a constant segment is legal"), "swarm/services/ci-metrics/forge/token" ); assert_eq!( client_secret_path("swarm-ci-metrics").expect("a plain id is legal"), "swarm/services/swarm-ci-metrics/oidc/client" ); } }