From 3d14ddeb7d4c479045afa200485791246be05234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Sat, 16 May 2026 00:24:39 +0200 Subject: [PATCH] lifecycle: bind /meta RO into manager set_nspawn_flags now adds a third manager-only bind alongside /agents (RW) and /applied (RO): --bind-ro=/var/lib/hyperhive/meta :/meta. manager can git log /meta to see every deploy across the swarm and cat /meta/flake.lock to introspect which sha each agent is currently pinned at. defensive create_dir_all on the host side so a cold start with no agents (meta repo not yet seeded) doesn't trip systemd-nspawn's missing-bind-source check before the migration plants the dir. --- hive-c0re/src/lifecycle.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/hive-c0re/src/lifecycle.rs b/hive-c0re/src/lifecycle.rs index 31a3304..3debb67 100644 --- a/hive-c0re/src/lifecycle.rs +++ b/hive-c0re/src/lifecycle.rs @@ -592,6 +592,10 @@ const HOST_AGENTS_ROOT: &str = "/var/lib/hyperhive/agents"; /// `APPLIED_STATE_ROOT` in coordinator.rs. const HOST_APPLIED_ROOT: &str = "/var/lib/hyperhive/applied"; +/// On-host meta repo root, mirrored RO into the manager. Matches +/// `meta::meta_dir()` but duplicated here so lifecycle stays a leaf. +const HOST_META_ROOT: &str = "/var/lib/hyperhive/meta"; + fn set_nspawn_flags( container: &str, runtime_dir: &Path, @@ -607,6 +611,14 @@ fn set_nspawn_flags( notes = notes_dir.display(), ); if container == MANAGER_NAME { + use std::fmt::Write as _; + // systemd-nspawn refuses to start a container whose bind + // source doesn't exist. The meta repo is created by the + // startup migration, but make sure the directory is there + // before the manager comes up in case set_nspawn_flags fires + // first (e.g. cold start with no agents). + std::fs::create_dir_all(HOST_META_ROOT) + .with_context(|| format!("create {HOST_META_ROOT}"))?; // 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 // /root/.claude (no /agents or /applied). @@ -617,7 +629,11 @@ fn set_nspawn_flags( // 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 _; + // + // /meta is a third RO mount exposing the system-wide deploy + // flake (`git log /meta --oneline` shows every deploy across + // every agent; `cat /meta/flake.lock` resolves which sha each + // agent is pinned at right now). let _ = write!( binds, " --bind={HOST_AGENTS_ROOT}:{CONTAINER_MANAGER_AGENTS_MOUNT}", @@ -626,6 +642,11 @@ fn set_nspawn_flags( binds, " --bind-ro={HOST_APPLIED_ROOT}:{CONTAINER_MANAGER_APPLIED_MOUNT}", ); + let _ = write!( + binds, + " --bind-ro={HOST_META_ROOT}:{mount}", + mount = crate::meta::CONTAINER_MANAGER_META_MOUNT, + ); } let bind_flag = format!("EXTRA_NSPAWN_FLAGS=\"{binds}\""); let mut lines: Vec = original