lifecycle: bind /applied into manager read-only

set_nspawn_flags now adds --bind-ro=/var/lib/hyperhive/applied
:/applied for the manager container alongside the existing
/agents RW mount. manager can git-fetch deployed/failed/denied
tags out of /applied/<n>/.git to mirror them into its proposed
clones; the read-only bind means git plumbing inside the
container cannot corrupt the authoritative repos. picked up by
the next rebuild of hm1nd (no spawn-time change needed since
set_nspawn_flags runs on every spawn + rebuild).
This commit is contained in:
müde 2026-05-15 23:02:31 +02:00
parent 6cf66e23dc
commit 4a8204f035

View file

@ -607,11 +607,22 @@ async fn systemd_daemon_reload() -> Result<()> {
/// `containers.hm1nd.bindMounts."/agents"`. /// `containers.hm1nd.bindMounts."/agents"`.
pub const CONTAINER_MANAGER_AGENTS_MOUNT: &str = "/agents"; pub const CONTAINER_MANAGER_AGENTS_MOUNT: &str = "/agents";
/// Where the manager sees the applied trees of every agent, read-only.
/// Manager runs `git fetch /applied/<n>/.git refs/tags/*:refs/tags/applied/*`
/// to learn what hive-c0re deployed (or rejected, or failed to
/// build); the RO bind makes accidental writes impossible from
/// inside the container.
pub const CONTAINER_MANAGER_APPLIED_MOUNT: &str = "/applied";
/// The on-host root that gets bind-mounted to `/agents` inside the manager. /// The on-host root that gets bind-mounted to `/agents` inside the manager.
/// Hard-coded to match `AGENT_STATE_ROOT` in coordinator.rs (kept duplicated /// Hard-coded to match `AGENT_STATE_ROOT` in coordinator.rs (kept duplicated
/// here so lifecycle stays usable as a leaf module). /// here so lifecycle stays usable as a leaf module).
const HOST_AGENTS_ROOT: &str = "/var/lib/hyperhive/agents"; const HOST_AGENTS_ROOT: &str = "/var/lib/hyperhive/agents";
/// On-host applied repo root, mirrored RO into the manager. Matches
/// `APPLIED_STATE_ROOT` in coordinator.rs.
const HOST_APPLIED_ROOT: &str = "/var/lib/hyperhive/applied";
fn set_nspawn_flags( fn set_nspawn_flags(
container: &str, container: &str,
runtime_dir: &Path, runtime_dir: &Path,
@ -629,11 +640,22 @@ fn set_nspawn_flags(
if container == MANAGER_NAME { if container == MANAGER_NAME {
// Manager edits sub-agent proposed/ repos and its own. RW so it can // Manager edits sub-agent proposed/ repos and its own. RW so it can
// git-commit. Sub-agents see only their own /run/hive socket and // git-commit. Sub-agents see only their own /run/hive socket and
// /root/.claude (no /agents). // /root/.claude (no /agents or /applied).
//
// /applied is a separate RO mount of the hive-c0re-only applied
// repos so the manager can `git fetch /applied/<n>/.git
// refs/tags/*:refs/tags/applied/*` to mirror deployed/failed/
// denied tags into its proposed clones and diff against
// what's actually deployed. RO bind makes destructive git
// plumbing inside the container unable to corrupt applied.
use std::fmt::Write as _; use std::fmt::Write as _;
let _ = write!( let _ = write!(
binds, binds,
" --bind={HOST_AGENTS_ROOT}:{CONTAINER_MANAGER_AGENTS_MOUNT}" " --bind={HOST_AGENTS_ROOT}:{CONTAINER_MANAGER_AGENTS_MOUNT}",
);
let _ = write!(
binds,
" --bind-ro={HOST_APPLIED_ROOT}:{CONTAINER_MANAGER_APPLIED_MOUNT}",
); );
} }
let bind_flag = format!("EXTRA_NSPAWN_FLAGS=\"{binds}\""); let bind_flag = format!("EXTRA_NSPAWN_FLAGS=\"{binds}\"");