Compare commits

...
Author SHA1 Message Date
damocles
a9ce8a945f fix(#1160): restart agent on failed rebuild if it was running 2026-06-03 18:32:38 +02:00
damocles
452766b35f fix(#1165): validate send recipient before queuing message 2026-06-03 18:32:38 +02:00
2 changed files with 45 additions and 1 deletions

View file

@ -563,6 +563,31 @@ pub(crate) fn handle_send(
// learning the label — runtime reparenting propagates for free. See
// `docs/conventions.md::Recipient sentinels`.
let resolved = crate::topology::resolve_recipient(agent, to);
// Validate that the resolved recipient is a known local agent or the
// special "operator" recipient. Without this check a typo in `to`
// silently queues a message nobody will ever read (issue #1165).
//
// Cross-hive messaging (`name@hive` qualified names) is not routed
// through the broker — use the Matrix MCP tools for that instead.
if resolved.contains('@') {
return AgentResponse::Err {
message: format!(
"send failed: cross-hive recipient `{resolved}` is not supported \
via the broker use Matrix MCP tools for cross-hive messaging"
),
};
}
if resolved != hive_sh4re::OPERATOR_RECIPIENT {
let state_root = crate::coordinator::Coordinator::agent_state_root(&resolved);
if !state_root.exists() {
return AgentResponse::Err {
message: format!(
"send failed: unknown recipient `{resolved}` \
(no agent with that name exists on this hive)"
),
};
}
}
match coord.broker.send(&Message {
from: agent.to_owned(),
to: resolved,

View file

@ -467,7 +467,26 @@ pub async fn rebuild_no_meta(
priv_run("stop", name).await?;
}
on_step("nixos-container update");
priv_run("update", name).await?;
let update_result = priv_run("update", name).await;
if let Err(ref update_err) = update_result {
// The update failed (e.g. nix build error). If the agent was
// running before we stopped it, try to bring it back up on the
// previous successful configuration so it doesn't stay dead.
// The start failure is logged but not promoted to an error —
// we always propagate the original update error (below).
if was_running {
tracing::warn!(
%name,
error = %update_err,
"nixos-container update failed; attempting restart on old config"
);
on_step("nixos-container start (recovery)");
if let Err(e) = priv_run("start", name).await {
tracing::warn!(%name, error = %e, "recovery start after failed update also failed");
}
}
}
update_result?;
if was_running {
// Cold-start fallback on activation errors.
// See `docs/coordinator.md::Cold-start fallback`.