//! The CI runner agreement: where the forge's runner registration token lives, //! and what the object at that path holds. //! //! `swarm-controller` fetches the token with the forge's admin API and writes //! it here; `nix/host-modules/swarm-ci-runner.nix` reads it under the runner's //! own certificate. That runner's read stanza is the only one in the store that //! covers this path. use serde::{Deserialize, Serialize}; use crate::{ Error, path::{Kind, principal_prefix}, }; /// The runner's name segment under [`Kind::Service`]. const SERVICE: &str = "ci-runner"; /// The path holding the forge's runner registration token. /// /// # Errors /// Never in practice: the name segment is a constant. The `Result` is /// [`principal_prefix`]'s. pub fn registration_token_path() -> Result { let prefix = principal_prefix(Kind::Service, SERVICE)?; Ok(format!("{prefix}/registration-token")) } /// What the registration-token path holds. /// /// No `Debug` derive: `value` registers a runner that receives jobs from every /// repo on the forge, and a derived `Debug` is one `{:?}` away from a log line. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Credential { /// The token itself. `swarm-ci-runner.nix` reads the store with /// `bao kv get -field=value`, so this name is load-bearing for a reader /// this crate does not control, the same as [`crate::matrix::Credential`]'s. pub value: String, } #[cfg(test)] mod tests { use super::*; #[test] fn the_registration_token_is_under_the_runners_service_prefix() { // The literal is what `swarm-bao.nix` grants the runner's role, and // what the controller's write stanza names. assert_eq!( registration_token_path().expect("a constant segment is legal"), "swarm/services/ci-runner/registration-token" ); } }