//! Wire types for the `hive-priv` privileged-helper socket. //! //! Both `hive-priv` (server) and `hive-c0re` (client via `priv_client`) //! import these so the shapes stay in sync. use serde::{Deserialize, Serialize}; /// Default socket path for the privileged helper. pub const PRIV_SOCK: &str = "/run/hive/priv.sock"; /// Manager logical agent name. The manager's system container name is /// `h-ruth` (same `h-` prefix convention as every other agent). pub const MANAGER_NAME: &str = "ruth"; /// Sub-agent container prefix. System container name = `h-`. pub const AGENT_PREFIX: &str = "h-"; /// Sibling service containers managed by hive-c0re. pub const SIBLING_CONTAINERS: &[&str] = &["hive-forge", "hive-matrix", "hive-gateway"]; /// Host path of the meta flake. The flake ref for agent `` is /// `{META_DIR}#{name}`, derived by `hive-priv` — never passed over the wire. pub const META_DIR: &str = "/var/lib/hyperhive/meta"; /// Output format for `ReadContainerJournal`. Maps to journalctl /// `--output=<...>`. Restricted to the two formats hive callers use so /// the wire type can't smuggle an arbitrary `--output` value. #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum JournalOutput { /// `short` — the journalctl default (syslog-style timestamps). #[default] Short, /// `short-iso` — ISO 8601 timestamps. ShortIso, } impl JournalOutput { /// The string journalctl expects after `--output=`. pub fn as_journalctl(self) -> &'static str { match self { JournalOutput::Short => "short", JournalOutput::ShortIso => "short-iso", } } } /// One bind-mount entry for `WriteNspawnFlags`. /// hive-priv constructs `--bind=:` (or `--bind-ro=`) /// and validates both paths before writing the conf file. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BindMount { pub host_path: String, pub container_path: String, pub read_only: bool, } /// A request to the privileged helper. /// /// Wire format: one JSON object per line over `/run/hive/priv.sock`. /// Every variant is a specific known operation — no pass-through /// shell commands or arbitrary paths. New privileged ops get new /// variants. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "op", rename_all = "snake_case")] pub enum PrivRequest { // --- Container lifecycle --- /// `nixos-container start ` StartContainer { name: String }, /// `nixos-container stop ` StopContainer { name: String }, /// `nixos-container kill ` KillContainer { name: String }, /// `nixos-container update --flake ` /// The flake ref is derived from `name` by hive-priv. UpdateContainer { name: String }, /// `nixos-container create --flake ` /// The flake ref is derived from `name` by hive-priv. CreateContainer { name: String }, /// `nixos-container destroy ` DestroyContainer { name: String }, /// `nixos-container list` ListContainers, // --- Container journal reads --- /// Read a container's journal via `journalctl -M `. /// Requires root: the machine-bus transport enters the container's /// namespace, so this can't run from the unprivileged hive-c0re /// process. hive-priv validates `container` against the managed- /// container allowlist, then runs journalctl and returns its output. /// /// The filters (`unit` / `priority` / `grep` / `since` / `until`) /// are applied within the already-authorized machine and passed to /// journalctl as plain argument values; they can't widen access /// beyond the validated `container`. ReadContainerJournal { /// System container name (`h-` or a sibling service). container: String, /// `-n `. lines: u32, /// `-b` — restrict to the current boot. #[serde(default)] boot: bool, /// `--output=<...>`. #[serde(default)] output: JournalOutput, /// `-u `. #[serde(default)] unit: Option, /// `-p `. #[serde(default)] priority: Option, /// `--grep=`. #[serde(default)] grep: Option, /// `--since=`. #[serde(default)] since: Option, /// `--until=`. #[serde(default)] until: Option, }, // --- Config file writes --- /// Update `/etc/nixos-containers/.conf`: strip network-isolation /// vars, force `PRIVATE_NETWORK=0`, and set `EXTRA_NSPAWN_FLAGS` from the /// provided bind-mount list. Written by `lifecycle::set_nspawn_flags`. WriteNspawnFlags { container: String, binds: Vec, }, /// Write `/run/systemd/system/container@.service.d/hyperhive-limits.conf` /// with `[Service]\nMemoryMax=\nCPUQuota=\n`. /// Written by `lifecycle::set_resource_limits`. WriteResourceLimits { container: String, memory_max: String, cpu_quota: String, }, /// Remove `/run/systemd/system/container@.service.d/` if present. /// Called by `lifecycle::destroy` to clean up the resource-limits drop-in. RemoveServiceDropin { container: String }, // --- System --- /// Run `systemctl daemon-reload`. DaemonReload, /// Reload nginx inside the `hive-gateway` container via /// `systemd-run --machine=hive-gateway nginx -s reload`. ReloadGatewayNginx, // --- Socket dir ownership --- /// Set ownership of `/run/hive-agent//` to `uid:gid`. /// Called by `lifecycle::set_nspawn_flags` after `create_dir_all`. ChownSocketDir { agent_name: String, uid: u32, gid: u32, }, /// Set mode of `/run/hive-agent//`. /// Fallback when uid lookup returns `None` on first spawn. ChmodSocketDir { agent_name: String, mode: u32 }, } /// Response from the privileged helper. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PrivResponse { pub ok: bool, #[serde(default)] pub stdout: String, #[serde(default)] pub stderr: String, #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, }