feat: add persistent agent host mounts - #20
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughChangesAgent host mounts
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- RecreateAgent no longer boots a deliberately-stopped box to register mount groups: a stopped box briefly running hb-workload's reconcile loop could start the Hermes gateway and violate the single-writer discipline. Current images register TX9_AGENT_MOUNT_GIDS in their entrypoint at boot, so the exec+restart dance now only runs for old images (detected by grepping the image's shipped entrypoint) on running boxes; old image + stopped box is refused up front, before any destructive step. This also removes the groupadd race between the CLI exec and the new entrypoint. - applyAgentMounts skips PrepareRuntime on a quiesced box: hb up clears the quiesce marker and wires MCP, which cmd_import deliberately avoids on restored boxes (single-writer safety gate). - mount add/remove no-ops (identical mount re-added, unknown target removed) return early instead of destroying and recreating a healthy agent container. - supplementalGroup now models kernel permission-class precedence: owner/group classes govern exclusively, so e.g. an agent-owned 0577 directory no longer passes validation via the other bits, and a directory in the agent's primary GID no longer borrows other bits. - Upgrade runs the mount preflight after the image build, immediately before teardown, so a source that goes offline during a long build fails while the old containers still exist. - RecreateAgent failure guidance points at tx9 upgrade (re-running the mount command cannot recover once the old container is gone). - SaveAgentMounts reuses setOrDelete; docs mention remove-path preflight blocking. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| return preparedAgentMount{bind: bind, group: group}, nil | ||
| } | ||
|
|
||
| func supplementalGroup(info os.FileInfo, readOnly bool) (string, error) { |
There was a problem hiding this comment.
🟡 Medium box/agent_mounts.go:210
supplementalGroup rejects valid mount directories on filesystems that use POSIX ACLs. When access for UID 1001 or a supplemental group is granted via an ACL entry but the plain owner/group/other mode bits are restrictive, the function returns a spurious "does not give agent ... access" error, so tx9 mount add fails for a mount the container could actually use. The check only inspects info.Mode().Perm() and Stat_t.{Uid,Gid}, ignoring ACL entries that Linux applies before falling back to mode bits. Consider reading the directory's ACL (e.g. via system.posix_acl_access xattr) and accounting for it before concluding access is denied, or document that ACL-managed paths are unsupported.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @internal/box/agent_mounts.go around line 210:
`supplementalGroup` rejects valid mount directories on filesystems that use POSIX ACLs. When access for UID `1001` or a supplemental group is granted via an ACL entry but the plain `owner/group/other` mode bits are restrictive, the function returns a spurious "does not give agent ... access" error, so `tx9 mount add` fails for a mount the container could actually use. The check only inspects `info.Mode().Perm()` and `Stat_t.{Uid,Gid}`, ignoring ACL entries that Linux applies before falling back to mode bits. Consider reading the directory's ACL (e.g. via `system.posix_acl_access` xattr) and accounting for it before concluding access is denied, or document that ACL-managed paths are unsupported.
- applyAgentMounts now owns persistence: save the desired mount set only after RecreateAgent succeeds (a failed recreation leaves the old state, so retrying the same command is not short-circuited by the idempotent no-op guard) and before PrepareRuntime (so a runtime prep failure cannot leave a live mount that the next upgrade would silently drop). - imageConfiguresMountGroups distinguishes grep exit 2 (entrypoint missing/unreadable — an inspection failure) from exit 1 (old image). - docs: note the permission check reads classic mode bits only (POSIX ACL grants are rejected) and that mount remove preflight can be blocked by a different offline --require-mountpoint source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
hb is-paused through box.HB collapses "not paused" (exit 1) and a transient exec failure into the same error, so a replacement agent that had not finished booting could be misread as active and PrepareRuntime would unquiesce a deliberately paused box. The new box.AgentQuiesced maps the exit code inside the container: paused and active are explicit results, anything else is an error that skips runtime preparation (mounts are already applied and persisted). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
tx9 mount add|list|removefor persistent per-box agent bind mounts/mntso portable/databackups never traverse NAS content--require-mountpointguard for offline network sharesrunuseragent processesWhy
TX9 only modeled its two named Docker volumes, so the existing Nexus CIFS share at
~/agentscould not be attached through the CLI or reapplied after container recreation. A plain Docker bind was also insufficient because the host share is UID/GID 1000 while the TX9 agent is UID/GID 1001; interactive execs and long-running Hermes processes need the supplemental host group.Impact
Operators can now attach host storage with:
tx9 mount add media-bot "$HOME/agents" /mnt/agents --require-mountpointThe desired configuration is stored in the per-box state file and reused by
tx9 upgrade <box>. Host credentials and the mount itself remain host-managed, and imported portable backups intentionally start without host-local mounts.Validation
/home/davis/agents -> /mnt/agentsinmedia-bottx9 doctor media-botpassedmake syntax lint testgo vet -buildvcs=false ./...go test -buildvcs=false ./...git diff --checkNote
Add persistent host mount support via
tx9 mountCLI commandstx9 mount add/list/removesubcommands in cmd_mount.go to configure host directory bind mounts for agent containers, persisted in per-box env as JSON./mnt; validation enforces absolute paths, no duplicate targets, and optional--require-mountpointto reject plain directories.box.RecreateAgentin create.go to replace only the agent container (preserving executor, network, and volumes) when mounts change, with supplemental GID injection for access control.TX9_AGENT_MOUNT_GIDSat startup to register host-mount groups into theagentuser account.RecreateAgenton older images withoutTX9_AGENT_MOUNT_GIDSsupport falls back to exec-based group setup, requiring the container to be running.Macroscope summarized c1448d1.
Greptile Summary
This PR adds persistent host mounts for TX9 agent containers. The main changes are:
tx9 mount add,list, andremovecommands for per-box bind mounts./mntso portable/databackups stay isolated.--require-mountpointpreflight checks for host/NAS paths.Confidence Score: 5/5
Safe to merge with low risk.
The mount feature is scoped to agent bind mount configuration and preserves existing create, import, upgrade, and runtime behavior. The changed paths validate mount targets, preflight host sources before destructive recreation, and clear host-local state for fresh create/import flows. No blocking correctness or security issues were found.
No files require special attention.
What T-Rex did
Important Files Changed
Reviews (5): Last reviewed commit: "fix: make the mount quiesce check fail c..." | Re-trigger Greptile