93 lines
3.1 KiB
Rust
93 lines
3.1 KiB
Rust
//! The swarm builder agreement: where its forge token and its queue client
|
|
//! secret live in the store, and what each object holds.
|
|
//!
|
|
//! swarm-controller mints the forge token; the builder reads it, and its queue
|
|
//! client secret, under its own certificate. It also reads the cache push
|
|
//! token, which the operator writes. Its read stanza in `swarm-bao.nix` names
|
|
//! exactly these three paths.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{
|
|
Error,
|
|
path::{Kind, principal_prefix},
|
|
};
|
|
|
|
/// The builder's name segment under [`Kind::Service`].
|
|
const SERVICE: &str = "builder";
|
|
|
|
/// The path holding the token of the builder'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<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, SERVICE)?;
|
|
Ok(format!("{prefix}/forge/token"))
|
|
}
|
|
|
|
/// The path holding the token the builder pushes closures to the binary cache
|
|
/// with, as an [`AtticPushToken`]. The operator writes it by hand: the cache is
|
|
/// an instance outside the swarm, and no swarm unit mints the token.
|
|
///
|
|
/// Under the cache's own name segment rather than the builder's, since the
|
|
/// token belongs to the cache's tenant.
|
|
///
|
|
/// # Errors
|
|
/// Never in practice: the name segment is a constant. The `Result` is
|
|
/// [`principal_prefix`]'s.
|
|
pub fn attic_push_token_path() -> Result<String, Error> {
|
|
let prefix = principal_prefix(Kind::Service, "attic")?;
|
|
Ok(format!("{prefix}/push-token"))
|
|
}
|
|
|
|
/// What [`attic_push_token_path`] holds.
|
|
///
|
|
/// No `Debug`: `value` writes to the binary cache.
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct AtticPushToken {
|
|
/// The token, under the field name the operator writes.
|
|
pub value: String,
|
|
}
|
|
|
|
/// The path holding the queue client secret of the builder'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<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 builder at the queue.
|
|
#[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/builder/forge/token"
|
|
);
|
|
assert_eq!(
|
|
client_secret_path("swarm-builder").expect("a plain id is legal"),
|
|
"swarm/services/swarm-builder/oidc/client"
|
|
);
|
|
assert_eq!(
|
|
attic_push_token_path().expect("a constant segment is legal"),
|
|
"swarm/services/attic/push-token"
|
|
);
|
|
}
|
|
}
|