Watch
0
0
Fork
You've already forked hyperhive
0

agent permissions: drop hive-c0re's swarm-agent-permissions.json fallback, fail closed before the first read

Removes the HiveCopy hand-off: hive-c0re no longer writes each agent's
entry from swarm-agent-permissions.json into its runtime dir as
swarm-permissions.json, and the harness and subagent daemon no longer
read it. hive-c0re keeps the file as its own last read of the swarm for
the manage_root_agent mounts. Also removes permissions_import::pending(),
its only caller being the hand-off. No nix provisioned the copy, so no
nix option is removed and no tombstone is needed.

Rule after this change: until an agent's first successful read of its
key it holds no permissions (no execution, so no bash), and a subagent it
starts holds the same. After a read a set key wins, [] holds none and an
unset key is the default. A failed read keeps the last value, so an
unreachable queue at start keeps the agent closed until a read succeeds.
The harness logs once at warn that it starts closed.

Fixes #5315
This commit is contained in:
atlas 2026-10-21 01:56:37 +02:00 • committed by mara
commit 2f00f9041f
11 changed files with 121 additions and 283 deletions

View file

@ -1,6 +1,6 @@
//! Per-container host-side config: the nspawn conf rewrite (bind mounts,
//! network isolation, forwarded credentials), the systemd resource-limits
//! drop-in, the agent's copies of its memory cap and stored permissions, and
//! drop-in, the agent's copy of its memory cap, and
//! the `write_dropins` verb that re-applies them.
use std::path::{Path, PathBuf};
@ -17,8 +17,8 @@ use super::{
};
/// Re-apply the per-container host-side config: nspawn flags (bind
/// mounts etc.), the systemd resource-limits drop-in, the agent's copies of
/// its memory cap and stored permissions, and a daemon reload so all of it
/// mounts etc.), the systemd resource-limits drop-in, the agent's copy of
/// its memory cap, and a daemon reload so all of it
/// takes effect on the next unit (re)start. Idempotent — the job queue's
/// `WriteDropin` node, also folded into every `Swap` (rebuild is the
/// reconcile verb).
@ -26,7 +26,6 @@ pub async fn write_dropins(name: &str, hive: &HiveEnv, paths: &AgentPaths) -> Re
validate(name)?;
let container = container_name(name);
set_nspawn_flags(&container, hive, &paths.agent, &paths.claude, &paths.notes).await?;
hand_permissions(name, &paths.agent);
if let Some((cpu_quota, memory_max)) = stage_limits(
name,
&crate::resource_limits::swarm_limits_path(),
@ -401,22 +400,6 @@ fn holds_manage_root_agent(agent_name: &str, path: &Path) -> bool {
})
}
/// Copy `agent`'s stored permissions into its runtime dir, which it holds
/// until its own first read of the swarm's key succeeds. A failure is logged
/// and the agent still starts, on the default.
pub fn hand_permissions(agent: &str, runtime_dir: &Path) {
let pending = crate::workers::permissions_import::pending();
if let Err(e) =
crate::permissions::hand_at(&crate::permissions::path(), pending, agent, runtime_dir)
{
tracing::error!(
agent = %agent,
error = ?e,
"could not hand the agent its stored permissions; it holds the default until it reads its key"
);
}
}
/// Idempotently rewrite the lines in `/etc/nixos-containers/<container>.conf`
/// that hive-c0re owns: `PRIVATE_NETWORK` (always 1), `HOST_ADDRESS` (the
/// bridge gateway IP) and `EXTRA_NSPAWN_FLAGS` (the runtime-dir bind). What

View file

@ -12,7 +12,7 @@ pub use git::{
git_is_ancestor, git_read_tree_reset, git_rev_parse, git_show_file, git_tag, git_update_ref,
git_update_ref_cas, run_with_deadline,
};
pub use host_config::{hand_permissions, write_dropins};
pub use host_config::write_dropins;
pub use setup::{
ensure_agent_state_subvolume, ensure_claude_dir, ensure_state_dir, initial_flake_nix,
setup_applied, setup_proposed,