Watch
0
0
Fork
You've already forked hyperhive
0

add one shared templated agent policy and name each agent's bao entity after it

This commit is contained in:
atlas 2026-10-25 20:39:59 +01:00 • committed by mara
commit 4cdf807afc

View file

@ -200,10 +200,83 @@ pub fn render_agent(agent: &str) -> Result<String, Error> {
Ok(format!("{read}{list}"))
}
/// The one policy every agent's cert-auth role attaches next to its own.
///
/// Inside [`HIVE_PREFIX`] so that the controller may write it, and without an
/// agent's suffix so that it is never an agent's object name:
/// [`agents_from_role_names`] needs `hive-agent-` with a segment after it. The
/// hive name that would spell it is `agent`, which `nix/reserved-hive-fragments.nix`
/// forbids.
pub const SHARED_AGENT_POLICY: &str = "hive-agent";
/// The template that stands for the agent's name in [`render_shared_agent`]:
/// the name of the login's identity entity, which swarm-controller sets to the
/// agent's name.
const ENTITY_NAME_TEMPLATE: &str = "{{identity.entity.name}}";
/// Render the policy [`SHARED_AGENT_POLICY`] holds: the stanzas of
/// [`render_agent`], with the agent's name taken from the identity entity of
/// whoever presents the token instead of written into the text.
///
/// The text is the same for every agent, so a change to the rule is one write.
/// An entity whose name is not an agent's grants nothing: the controller names
/// each agent's entity after the agent, and a login that no entity of that
/// name owns reads `swarm/agents/<generated name>/`, where nothing is stored.
#[must_use]
pub fn render_shared_agent() -> String {
let kind = <&str>::from(Kind::Agent);
let read = read_stanza(&format!(
"{MOUNT}/data/{ROOT}/{kind}/{ENTITY_NAME_TEMPLATE}/*"
));
let list = list_stanza(&format!(
"{MOUNT}/metadata/{ROOT}/{kind}/{ENTITY_NAME_TEMPLATE}/*"
));
format!("{read}{list}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_shared_document_is_the_per_agent_one_with_the_entity_name_for_the_agent() {
let shared = render_shared_agent();
assert_eq!(
shared,
"path \"secret/data/swarm/agents/{{identity.entity.name}}/*\" {\n capabilities = [\"read\"]\n}\n\
path \"secret/metadata/swarm/agents/{{identity.entity.name}}/*\" {\n capabilities = [\"list\"]\n}\n"
);
// Same shape as the per-agent document, so the rule is one rule.
assert_eq!(
shared.replace("{{identity.entity.name}}", "atlas"),
render_agent("atlas").expect("legal")
);
}
#[test]
fn the_shared_document_names_no_agent_and_grants_no_wider_than_one() {
let shared = render_shared_agent();
assert!(!shared.contains("atlas"));
assert!(!shared.contains("agents/*"), "{shared}");
assert!(!shared.contains("create"));
assert!(!shared.contains("update"));
assert!(!shared.contains("delete"));
}
#[test]
fn the_shared_policy_name_is_writable_and_no_agents_or_hives() {
assert!(SHARED_AGENT_POLICY.starts_with(HIVE_PREFIX));
assert!(
agents_from_role_names(&[SHARED_AGENT_POLICY.to_owned()]).is_empty(),
"it must not be read back as an agent"
);
// The only hive name that would render it carries `agent`.
assert_eq!(
hive_object_name("agent").expect("legal as a segment"),
SHARED_AGENT_POLICY
);
}
#[test]
fn the_document_grants_every_agent_and_this_hive_alone() {
assert_eq!(