Watch
0
0
Fork
You've already forked hyperhive
0

hive-c0re: drop unrecognised tool-group names on read, matching capabilities' prune_unknown

This commit is contained in:
damocles 2026-10-08 00:07:03 +02:00 • committed by mara
commit 06951ddc30

View file

@ -35,9 +35,45 @@ pub fn tool_groups_path() -> PathBuf {
/// Read the per-agent tool-group map. An absent file is the empty map — /// Read the per-agent tool-group map. An absent file is the empty map —
/// callers treat a missing entry as "use role default". A file that /// callers treat a missing entry as "use role default". A file that
/// exists but can't be read or parsed is an error. /// exists but can't be read or parsed is an error. Any entry that isn't a
/// recognised [`hive_sh4re::permissions::ToolGroup`] is dropped (with a
/// `warn!`) from what's returned — a stale or renamed name is never
/// honoured — but `read` itself never writes; unknown names stay on disk
/// until the next `set_groups` rewrites the file.
pub fn read() -> std::io::Result<BTreeMap<String, Vec<String>>> { pub fn read() -> std::io::Result<BTreeMap<String, Vec<String>>> {
super::read_map(&tool_groups_path()) let mut map = super::read_map(&tool_groups_path())?;
prune_unknown(&mut map);
Ok(map)
}
/// True if `name` matches a recognised [`hive_sh4re::permissions::ToolGroup`]
/// exactly (same comparison [`validate_groups`] uses).
fn is_known(name: &str) -> bool {
hive_sh4re::permissions::ToolGroup::ALL
.iter()
.any(|g| <&str>::from(*g) == name)
}
/// Drop any tool-group string in `map` that isn't a recognised
/// [`hive_sh4re::permissions::ToolGroup`], warning per dropped string so a
/// stale or renamed grant doesn't look like it's still in effect. An agent
/// left with no groups is removed entirely, matching [`set_groups`]'s
/// empty-vec behaviour (reverts to the harness role default). Returns
/// whether anything was dropped.
fn prune_unknown(map: &mut BTreeMap<String, Vec<String>>) -> bool {
let mut dropped_any = false;
map.retain(|agent, groups| {
groups.retain(|g| {
let known = is_known(g);
if !known {
dropped_any = true;
tracing::warn!(agent, tool_group = %g, "dropping unrecognised tool group");
}
known
});
!groups.is_empty()
});
dropped_any
} }
/// Look up the configured tool groups for one agent. Returns an empty /// Look up the configured tool groups for one agent. Returns an empty
@ -51,14 +87,10 @@ pub fn groups_for(name: &str) -> std::io::Result<Vec<String>> {
/// Returns `Ok(())` when all names are known, or `Err` listing the /// Returns `Ok(())` when all names are known, or `Err` listing the
/// unrecognised names so callers can surface a useful error message. /// unrecognised names so callers can surface a useful error message.
pub fn validate_groups(groups: &[String]) -> anyhow::Result<()> { pub fn validate_groups(groups: &[String]) -> anyhow::Result<()> {
let valid: std::collections::BTreeSet<&str> = hive_sh4re::permissions::ToolGroup::ALL
.iter()
.map(|g| <&str>::from(*g))
.collect();
let unknown: Vec<&str> = groups let unknown: Vec<&str> = groups
.iter() .iter()
.map(String::as_str) .map(String::as_str)
.filter(|s| !valid.contains(s)) .filter(|s| !is_known(s))
.collect(); .collect();
if unknown.is_empty() { if unknown.is_empty() {
Ok(()) Ok(())