fix: declare the agent socket dir's owner in tmpfiles, not by chown after
/run/hive-agent/<name> was 0777 root root in steady state, not just during first spawn. A directory without the sticky bit lets any user unlink files in it, and the gateway container has all of /run/hive-agent bind-mounted in, so anything that could reach the path could delete an agent's agent.sock, bind its own, and receive that agent's todos from hive-c0re. Two mechanisms were writing the dir and undoing each other: the tmpfiles.d entry wrote 0777 root root, then hive-c0re round-tripped through hive-priv's ChownSocketDir to narrow it. `d` re-asserts mode and owner on every apply and the file is regenerated on any agent's spawn or destroy, so every such event reset every agent's dir back to world-writable. SyncAgentTmpfiles now carries each agent's container uid/gid and the entry declares the answer: 0751 <uid> <gid>. Three principals need the dir and no two share a group -- the harness binds its sockets (owner rwx), hive-c0re dials agent.sock and the gateway's nginx dials web.sock (both only need traverse, and both sockets are already 0666). Deletes ChownSocketDir and ChmodSocketDir, both priv_client wrappers, the either/or in host_config with its two swallowed warn!s, and the now-dead socket_dir_path -- two verbs off the privileged helper's surface and one round-trip off every agent spawn. Also makes the two tmpfiles rules for /run/hive-agent itself agree: the gateway module said hive-core, the generated file said root, and which won depended on the order systemd read them in.
This commit is contained in:
parent
642377c5e0
commit
3fc1588e83
8 changed files with 110 additions and 103 deletions
|
|
@ -95,6 +95,21 @@ now set unconditionally for every agent. The mechanism:
|
|||
bind, not file bind — file bind-mounts don't survive the
|
||||
harness's `unlink + bind(2)` cycle on socket replace. Per-agent
|
||||
subdir keeps each agent's container blind to siblings' sockets.
|
||||
|
||||
**Ownership of that dir is declared, not repaired.** The tmpfiles.d
|
||||
entry written by `SyncAgentTmpfiles` names the agent's container
|
||||
uid/gid directly — `d /run/hive-agent/<name> 0751 <uid> <gid> -`.
|
||||
Three principals need the dir and no two share a group: the harness
|
||||
(owner, `rwx`, binds + unlinks its sockets), `hive-c0re` (dials
|
||||
`agent.sock`) and the gateway's nginx (dials `web.sock`, and has all
|
||||
of `/run/hive-agent` bind-mounted in). The latter two only need
|
||||
traverse, which is what `o=--x` grants; both sockets are `0666`.
|
||||
Do **not** reintroduce a chown here: tmpfiles re-applies this entry
|
||||
on every boot *and* every agent spawn/destroy, so any ownership set
|
||||
afterwards is reverted the next time any agent changes. The mode is
|
||||
also load-bearing — a directory without the sticky bit lets any user
|
||||
unlink files in it, so a world-writable socket dir would let anything
|
||||
that can reach the path replace an agent's socket with its own.
|
||||
3. **Marker gate**. After successful `bind_unix`, the harness drops
|
||||
`<dir>/hyperhive-socket-bound` next to the socket. c0re's
|
||||
`agent_sockets::write` filters its JSON map by marker presence —
|
||||
|
|
|
|||
|
|
@ -212,7 +212,6 @@ known operations; there is no arbitrary command pass-through:
|
|||
| `WriteResourceLimits` | write `CPUQuota=`/`MemoryMax=`/`CPUWeight=`/`IOWeight=` systemd drop-in for agent container |
|
||||
| `RemoveServiceDropin` | remove `container@<name>.service.d/` drop-in on destroy |
|
||||
| `DaemonReload` | `systemctl daemon-reload` |
|
||||
| `ChownSocketDir` / `ChmodSocketDir` | chown/chmod `/run/hive-agent/<name>/` socket directory |
|
||||
| `RunForgeAdmin` | `nixos-container run hive-forge -- runuser -u forgejo -- forgejo admin <args>` |
|
||||
| `WriteAgentForgeToken` / `WriteAgentMatrixToken` | write `0600` credential file into agent state dir |
|
||||
| `RestartMatrixDaemon` | `systemctl --machine=h-<name> restart hive-matrix-daemon.service` |
|
||||
|
|
|
|||
Loading…
Reference in a new issue