feat(#1636): infra_admin capability — restart hive-ci/gateway/forge via restart tool

This commit is contained in:
damocles 2026-06-13 11:41:15 +02:00 committed by mara
commit f05031ebe3
6 changed files with 144 additions and 4 deletions

View file

@ -391,7 +391,7 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) ->
agent: target,
} => handle_reminder_rollup(coord, agent, target.as_deref(), *since_secs),
AgentRequest::Start { name } => handle_start_child(coord, agent, name).await,
AgentRequest::Restart { name } => handle_restart_child(coord, agent, name),
AgentRequest::Restart { name } => handle_restart_child(coord, agent, name).await,
AgentRequest::Kill { name } => handle_kill_child(coord, agent, name).await,
AgentRequest::Update { name } => handle_update_child(coord, agent, name),
AgentRequest::ListDescendants => handle_list_descendants(agent).await,
@ -515,7 +515,15 @@ async fn handle_start_child(coord: &Arc<Coordinator>, agent: &str, name: &str) -
/// `Restart` — enqueue a restart for a direct-child container.
/// Topology parenthood is the only authorisation criterion — no
/// capability flag needed.
fn handle_restart_child(coord: &Arc<Coordinator>, agent: &str, name: &str) -> AgentResponse {
async fn handle_restart_child(coord: &Arc<Coordinator>, agent: &str, name: &str) -> AgentResponse {
// Infra-container restart: an agent holding the `infra_admin`
// capability can restart a hive infrastructure container (hive-ci /
// hive-gateway / hive-forge) by passing its name to the same restart
// tool. These names are never agent children, so this branch is
// disjoint from the child-restart path below.
if hive_sh4re::priv_proto::RESTARTABLE_INFRA_CONTAINERS.contains(&name) {
return handle_restart_infra(agent, name).await;
}
if let Some(err) = require_child(agent, name, "restart") {
return err;
}
@ -531,6 +539,29 @@ fn handle_restart_child(coord: &Arc<Coordinator>, agent: &str, name: &str) -> Ag
AgentResponse::Ok
}
/// Restart a hive infrastructure container on behalf of an agent that
/// holds the `infra_admin` capability. The container name is already
/// known to be in `RESTARTABLE_INFRA_CONTAINERS`; this gates on the
/// capability and routes the systemctl restart through hive-priv (which
/// re-validates the name root-side). Direct, not approval-gated.
async fn handle_restart_infra(agent: &str, container: &str) -> AgentResponse {
if !crate::capabilities::has_cap(agent, hive_sh4re::Capability::InfraAdmin) {
tracing::warn!(%agent, %container, "agent: infra restart denied (no infra_admin capability)");
return AgentResponse::Err {
message: format!(
"restarting infra container `{container}` requires the `infra_admin` capability"
),
};
}
tracing::info!(%agent, %container, "agent: restart infra container");
match crate::priv_client::restart_infra_container(container).await {
Ok(()) => AgentResponse::Ok,
Err(e) => AgentResponse::Err {
message: format!("{e:#}"),
},
}
}
/// `Kill` — kill a direct-child container, unregister it, notify the
/// manager.
async fn handle_kill_child(coord: &Arc<Coordinator>, agent: &str, name: &str) -> AgentResponse {

View file

@ -276,6 +276,18 @@ pub async fn restart_matrix_daemon(agent_name: &str) -> Result<()> {
.await?)
}
/// Restart a hive infrastructure container (hive-ci / hive-gateway /
/// hive-forge) on the host via `systemctl restart
/// container@<container>.service`. hive-priv re-validates `container`
/// against its root-side allowlist; callers must already have checked
/// the requesting agent holds the `infra_admin` capability.
pub async fn restart_infra_container(container: &str) -> Result<()> {
ok(call(&PrivRequest::RestartInfraContainer {
container: container.to_owned(),
})
.await?)
}
fn check(resp: PrivResponse) -> Result<(String, String)> {
if resp.ok {
Ok((resp.stdout, resp.stderr))