eleven / messenger Public

server: add-bot chowns the bot session dir to the service user (#226)

runAddBot runs as root, so MkdirAll/writeEnvFile leave the session dir and env
file root-owned. But lchat-bot@.service runs as the unprivileged serviceUser
(the hardened units), so the sidecar can't write its session files into the
dir — the first boot burns its one-time invites, fails to persist, and
crash-loops on "invite is used or invalid" (also leaving orphan agent members
in the instance roster). Hand the session dir + env to serviceUser after
creating them, before starting the unit.

Existing sidecars escaped this only because their dirs predate the hardening
and were chowned when /data was; a fresh add-bot on a hardened box hit it.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Paul Campbell 8e20692cf88dfa17fc639b6cfaa9068b17e8dd51 parent 1d9d8ae
1 file changed, +6 −0
  • bot.go +6 −0
diff --git a/bot.go b/bot.go
index 1e95551..9ae31cb 100644
--- a/bot.go
+++ b/bot.go
@@ -95,6 +95,12 @@ func runAddBot(args []string) {
if err := writeEnvFile(botEnvPath, botEnv); err != nil {
die("add-bot: write bot env: %v", err)
}
+ // add-bot runs as root, so MkdirAll/writeEnvFile leave these root-owned. But the
+ // bot unit runs as serviceUser (hardened units) and must WRITE its session files
+ // into sessionDir — otherwise the sidecar can't persist, and the first boot
+ // crash-loops after burning its one-time invites. Hand both to the service user.
+ chownToService(sessionDir)
+ chownToService(botEnvPath)
unit := *botUnit + host
if err := systemctl("enable", "--now", unit); err != nil {