hive-sh4re: split tool-group + capability enums into their own topic module

This commit is contained in:
damocles 2026-08-10 22:54:32 +02:00 committed by mara
commit d3ac4de8fb
11 changed files with 313 additions and 296 deletions

View file

@ -3,7 +3,7 @@
//! and `tool-groups.json`.
//!
//! Format: a JSON object mapping agent name to an array of
//! `hive_sh4re::Capability` `snake_case` strings:
//! `hive_sh4re::permissions::Capability` `snake_case` strings:
//!
//! ```json
//! {
@ -52,7 +52,7 @@ pub fn caps_for(name: &str) -> Vec<String> {
/// Check whether an agent holds a specific capability.
#[must_use]
pub fn has_cap(name: &str, cap: hive_sh4re::Capability) -> bool {
pub fn has_cap(name: &str, cap: hive_sh4re::permissions::Capability) -> bool {
caps_for(name)
.iter()
.any(|s| s.eq_ignore_ascii_case(cap.as_str()))

View file

@ -3,7 +3,7 @@
//! and the meta `flake.nix`.
//!
//! Format: a JSON object mapping agent name to an array of
//! `hive_sh4re::ToolGroup` `snake_case` strings:
//! `hive_sh4re::permissions::ToolGroup` `snake_case` strings:
//!
//! ```json
//! {
@ -70,7 +70,7 @@ fn write(map: &BTreeMap<String, Vec<String>>) -> std::io::Result<()> {
/// Returns `Ok(())` when all names are known, or `Err` listing the
/// unrecognised names so callers can surface a useful error message.
pub fn validate_groups(groups: &[String]) -> anyhow::Result<()> {
let valid: std::collections::BTreeSet<&str> = hive_sh4re::ToolGroup::ALL
let valid: std::collections::BTreeSet<&str> = hive_sh4re::permissions::ToolGroup::ALL
.iter()
.map(|g| g.as_str())
.collect();
@ -85,7 +85,7 @@ pub fn validate_groups(groups: &[String]) -> anyhow::Result<()> {
anyhow::bail!(
"unknown tool group(s): {}; valid names are: {}",
unknown.join(", "),
hive_sh4re::ToolGroup::ALL
hive_sh4re::permissions::ToolGroup::ALL
.iter()
.map(|g| g.as_str())
.collect::<Vec<_>>()

View file

@ -696,7 +696,7 @@ impl Coordinator {
/// rebuild-queue worker after a `PermChange` / Capabilities entry
/// commits the JSON file, so the P3RM1SS10NS tab updates live.
pub fn emit_capabilities_snapshot(self: &Arc<Self>) {
use hive_sh4re::Capability;
use hive_sh4re::permissions::Capability;
let caps = Capability::ALL.iter().map(|c| c.as_str()).collect();
let descriptions = Capability::ALL
.iter()
@ -723,7 +723,7 @@ impl Coordinator {
/// rebuild-queue worker after a `PermChange` / `ToolGroups` entry
/// commits the JSON file, so the P3RM1SS10NS tab updates live.
pub fn emit_tool_groups_snapshot(self: &Arc<Self>) {
use hive_sh4re::ToolGroup;
use hive_sh4re::permissions::ToolGroup;
let groups = ToolGroup::ALL.iter().map(|g| g.as_str()).collect();
let descriptions = ToolGroup::ALL
.iter()

View file

@ -48,11 +48,11 @@ pub(super) struct ToolGroupsSnapshot {
pub(super) async fn get_tool_groups(
State(state): State<AppState>,
) -> axum::Json<ToolGroupsSnapshot> {
let groups = hive_sh4re::ToolGroup::ALL
let groups = hive_sh4re::permissions::ToolGroup::ALL
.iter()
.map(|g| g.as_str())
.collect();
let descriptions = hive_sh4re::ToolGroup::ALL
let descriptions = hive_sh4re::permissions::ToolGroup::ALL
.iter()
.map(|g| (g.as_str(), g.description()))
.collect();
@ -80,7 +80,7 @@ pub(super) async fn get_tool_groups(
/// the container actually runs with.
#[must_use]
pub(crate) fn tool_group_default_names() -> Vec<&'static str> {
hive_sh4re::ToolGroup::AGENT_DEFAULT
hive_sh4re::permissions::ToolGroup::AGENT_DEFAULT
.iter()
.map(|g| g.as_str())
.collect()
@ -204,7 +204,7 @@ pub(super) struct CapabilitiesSnapshot {
pub(super) async fn get_capabilities(
State(state): State<AppState>,
) -> axum::Json<CapabilitiesSnapshot> {
use hive_sh4re::Capability;
use hive_sh4re::permissions::Capability;
let caps = Capability::ALL.iter().map(|c| c.as_str()).collect();
let descriptions = Capability::ALL
.iter()
@ -256,7 +256,7 @@ pub(super) async fn post_capabilities(
if let Some(reject) = guard_agent_name(&state, &logical).await {
return Ok(reject);
}
let known: Vec<&str> = hive_sh4re::Capability::ALL
let known: Vec<&str> = hive_sh4re::permissions::Capability::ALL
.iter()
.map(|c| c.as_str())
.collect();
@ -334,7 +334,7 @@ pub(super) async fn post_permissions(
State(state): State<AppState>,
axum::Json(body): axum::Json<BatchPermsBody>,
) -> Result<Response, ProblemDetails> {
let known_caps: Vec<&str> = hive_sh4re::Capability::ALL
let known_caps: Vec<&str> = hive_sh4re::permissions::Capability::ALL
.iter()
.map(|c| c.as_str())
.collect();

View file

@ -75,7 +75,7 @@ async fn handle_restart_infra(
coord.emit_audit_entry(entry);
}
};
if !crate::capabilities::has_cap(agent, hive_sh4re::Capability::InfraAdmin) {
if !crate::capabilities::has_cap(agent, hive_sh4re::permissions::Capability::InfraAdmin) {
tracing::warn!(%agent, %name, "agent: infra restart denied (no infra_admin capability)");
audit(
crate::audit_log::AuditOutcome::Err,

View file

@ -757,7 +757,10 @@ fn require_new_child(agent: &str, target: &str, action: &str) -> Option<Response
/// gated on `QueryAgentState`.
fn handle_get_loose_ends(coord: &Arc<Coordinator>, agent: &str, target: Option<&str>) -> Response {
let result = if target == Some("*") {
if !crate::capabilities::has_cap(agent, hive_sh4re::Capability::QueryAgentState) {
if !crate::capabilities::has_cap(
agent,
hive_sh4re::permissions::Capability::QueryAgentState,
) {
return Response::Err {
message: "query_agent_state capability required for hive-wide loose ends"
.to_owned(),
@ -801,7 +804,10 @@ fn resolve_agent_state_target<'a>(
if crate::topology::is_descendant_of(name, caller) {
return Ok(name);
}
if crate::capabilities::has_cap(caller, hive_sh4re::Capability::QueryAgentState) {
if crate::capabilities::has_cap(
caller,
hive_sh4re::permissions::Capability::QueryAgentState,
) {
Ok(name)
} else {
Err(format!(
@ -842,7 +848,7 @@ pub async fn dispatch_host_journal(agent: &str, args: HostJournalArgs<'_>) -> Re
since,
until,
} = args;
if !crate::capabilities::has_cap(agent, hive_sh4re::Capability::ReadHostJournal) {
if !crate::capabilities::has_cap(agent, hive_sh4re::permissions::Capability::ReadHostJournal) {
return Response::Err {
message: "agent does not have the read_host_journal capability".to_owned(),
};

View file

@ -171,7 +171,7 @@ fn seed_manager_tool_groups() {
tracing::debug!("manager tool groups already set — leaving as-is");
return;
}
let all_groups: Vec<String> = hive_sh4re::ToolGroup::MANAGER_DEFAULT
let all_groups: Vec<String> = hive_sh4re::permissions::ToolGroup::MANAGER_DEFAULT
.iter()
.map(|g| g.as_str().to_owned())
.collect();