Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/module-eval/agent-user.nix
atlas 89a5d65119 agents: persistent /agents/<n>/work dir outside state/
Agents keep git worktrees and cargo target dirs under /home/<agent>,
which lives in the container rootfs and is deleted on destroy. They
can't move them under state/, because a claude started there walks up
into state/CLAUDE.md and takes on the agent's identity.

Add a per-agent work/ dir next to state/ on the host
(/var/lib/hyperhive/agents/<n>/work), bind-mounted RW at
/agents/<n>/work. hive-c0re creates it in ensure_state_dir and in
set_nspawn_flags (the rebuild path reaches only the latter), the
agent's activation chowns it to the agent user like state/ and
harness/, and measure_agent_disk counts it. destroy never touches the
agent root, so work/ survives it; purge removes the whole root, so
work/ goes with it.

Closes #4977
2026-10-05 12:56:02 +02:00

55 lines
1.9 KiB
Nix

# `checks.module-eval-agent-user` — see ./lib.nix for the shared
# rationale (why this suite exists, naming convention, "evaluates
# not executes").
{
pkgs,
lib,
self,
nixosSystem,
}:
let
inherit
(import ./lib.nix {
inherit
pkgs
lib
self
nixosSystem
;
})
agentWith
runGroup
;
# A named agent, so the rendered script carries a name no default supplies.
migrate =
(agentWith { services.hyperhive.agent.user.name = "iris"; })
.system.activationScripts.hive-agent-user-migrate.text;
cases = [
{
# hive-c0re creates the host work dir as hive-core; this activation is
# the only thing that lets the agent write to it.
name = "the agent's activation hands its own work dir to the agent user";
ok = lib.hasInfix ''chown -hR "$userName:$userName" "/agents/$userName/work"'' migrate;
}
{
# hive-priv creates the host socket dir `0751 root` and never chowns it,
# so this activation is the only thing that lets the harness bind there.
name = "the agent's activation hands its socket dir to the agent user at 0751";
ok =
lib.hasInfix "userName=${lib.escapeShellArg "iris"}" migrate
&& lib.hasInfix ''socketDir="/run/hive-agent/$userName"'' migrate
&& lib.hasInfix ''chown -h "$userName:$userName" "$socketDir"'' migrate
&& lib.hasInfix ''chmod 0751 "$socketDir"'' migrate;
}
{
# `test -d` and `chmod` follow symlinks, so without this refusal ahead
# of the chown branch a link at the socket dir is chmodded at its target.
name = "the agent's activation refuses a symlinked or non-directory socket dir";
ok =
lib.hasInfix ''if [ -L "$socketDir" ] || { [ -e "$socketDir" ] && [ ! -d "$socketDir" ]; }; then'' migrate
&& lib.hasInfix ''elif [ -d "$socketDir" ]; then'' migrate;
}
];
in
runGroup "agent-user" cases