fix(#962): remove hardcoded "root" string from docstrings and tests

Replace literal "root" with MANAGER_NAME constant in role tests;
update ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS docstring to say "manager"
not "root/manager agent".
This commit is contained in:
atlas 2026-06-01 19:01:49 +02:00 committed by mara
commit aae4be19bd

View file

@ -310,11 +310,11 @@ pub fn reconcile(agent_names: &[String]) -> std::io::Result<bool> {
// ---------------------------------------------------------------------------
/// Agents with this role have the top-level agents (direct children of the
/// root/manager agent) added as virtual children for bind-mount and
/// config-change purposes. Enables recovery: if a top-level agent is down,
/// a role holder can still read its state and update its config.
/// manager) added as virtual children for bind-mount and config-change
/// purposes. Enables recovery: if a top-level agent is down, a role holder
/// can still read its state and update its config.
///
/// The root agent receives this role by default on first `reconcile_roles`
/// The manager receives this role by default on first `reconcile_roles`
/// call; operators can revoke it with `set_role`.
pub const ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS: &str = "can_manage_top_level_agents";
@ -686,48 +686,46 @@ mod tests {
/// `reconcile_roles` does not re-seed it.
#[test]
fn set_role_revoke_keeps_empty_entry_as_tombstone() {
let mgr = crate::lifecycle::MANAGER_NAME;
// Build an in-memory roles map as set_role would see it after granting.
let mut roles: BTreeMap<String, Vec<String>> = BTreeMap::new();
roles.insert(
"root".to_owned(),
vec![ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS.to_owned()],
);
roles.insert(mgr.to_owned(), vec![ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS.to_owned()]);
// Simulate the revoke path of set_role (in-memory, no disk).
let list = roles.entry("root".to_owned()).or_default();
let list = roles.entry(mgr.to_owned()).or_default();
let held = list.iter().any(|r| r == ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS);
assert!(held);
list.retain(|r| r != ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS);
// Key must still be present (tombstone), just with an empty list.
assert!(roles.contains_key("root"), "empty entry must not be removed");
assert!(roles["root"].is_empty());
assert!(roles.contains_key(mgr), "empty entry must not be removed");
assert!(roles[mgr].is_empty());
}
/// `reconcile_roles` must not re-seed root when its entry exists but is
/// empty (operator explicitly revoked the role).
/// `reconcile_roles` must not re-seed the manager when its entry exists
/// but is empty (operator explicitly revoked the role).
#[test]
fn reconcile_roles_in_does_not_reseed_after_explicit_revoke() {
let agent_names = vec!["root".to_owned(), "alice".to_owned()];
let mgr = crate::lifecycle::MANAGER_NAME;
let agent_names = vec![mgr.to_owned(), "alice".to_owned()];
let mut roles: BTreeMap<String, Vec<String>> = BTreeMap::new();
// Tombstone: root was seen before but all roles were revoked.
roles.insert("root".to_owned(), vec![]);
// Tombstone: manager was seen before but all roles were revoked.
roles.insert(mgr.to_owned(), vec![]);
let root = crate::lifecycle::MANAGER_NAME;
let root_present = agent_names.iter().any(|n| n == root);
let should_seed = root_present && !roles.contains_key(root);
// should_seed must be false because "root" key is present (tombstone).
let mgr_present = agent_names.iter().any(|n| n == mgr);
let should_seed = mgr_present && !roles.contains_key(mgr);
// should_seed must be false because manager key is present (tombstone).
assert!(!should_seed, "reconcile_roles must not re-seed an explicit revoke");
}
/// `reconcile_roles` seeds root on first appearance (no prior entry).
/// `reconcile_roles` seeds the manager on first appearance (no prior entry).
#[test]
fn reconcile_roles_in_seeds_root_when_absent() {
let agent_names = vec!["root".to_owned(), "alice".to_owned()];
let mgr = crate::lifecycle::MANAGER_NAME;
let agent_names = vec![mgr.to_owned(), "alice".to_owned()];
let roles: BTreeMap<String, Vec<String>> = BTreeMap::new(); // empty
let root = crate::lifecycle::MANAGER_NAME;
let should_seed = agent_names.iter().any(|n| n == root) && !roles.contains_key(root);
assert!(should_seed, "reconcile_roles must seed root when absent");
let should_seed = agent_names.iter().any(|n| n == mgr) && !roles.contains_key(mgr);
assert!(should_seed, "reconcile_roles must seed manager when absent");
}
}