Skip to content

Commit 64848fb

Browse files
authored
improve: install UX — root default, auto-restart, optional SLACK_ALLOWED_USERS (#173)
1 parent 6d333a4 commit 64848fb

5 files changed

Lines changed: 86 additions & 19 deletions

File tree

.env.schema

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ SLACK_BOT_TOKEN=
4747
SLACK_APP_TOKEN=
4848

4949
# Comma-separated Slack user IDs allowed to interact with the agent
50-
# Bridge refuses to start without at least one user ID.
51-
# @required @sensitive=false @type=string
50+
# Optional — if unset, all workspace members can interact.
51+
# @sensitive=false @type=string
5252
# @example="U01ABCDEF,U02GHIJKL"
5353
SLACK_ALLOWED_USERS=
5454

bin/baudbot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,11 +474,11 @@ case "$COMMAND_NAME" in
474474
exec "$NODE_BIN" "$BAUDBOT_ROOT/bin/broker-register.mjs" "$@"
475475
;;
476476
--help|-h|"")
477-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [-v|--verbose]"
477+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
478478
;;
479479
*)
480480
echo "Unknown broker subcommand: ${1:-}"
481-
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [-v|--verbose]"
481+
echo "Usage: sudo baudbot broker register [--broker-url URL] [--workspace-id ID] --registration-token TOKEN [--no-restart] [-v|--verbose]"
482482
exit 1
483483
;;
484484
esac

bin/broker-register.mjs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* - agent config: /home/baudbot_agent/.config/.env
1313
*/
1414

15+
import { execFileSync } from "node:child_process";
1516
import fs from "node:fs";
1617
import os from "node:os";
1718
import path from "node:path";
@@ -48,6 +49,7 @@ export function usageText() {
4849
" --broker-url URL Broker base URL (e.g. https://broker.example.com)",
4950
" --workspace-id ID Slack workspace ID (e.g. T0123ABCD)",
5051
" --registration-token TOKEN Registration token from dashboard callback (required)",
52+
" --no-restart Skip automatic agent restart after registration",
5153
" -v, --verbose Show detailed registration progress",
5254
" -h, --help Show this help",
5355
"",
@@ -62,6 +64,7 @@ export function parseArgs(argv) {
6264
registrationToken: "",
6365
verbose: false,
6466
help: false,
67+
noRestart: false,
6568
};
6669

6770
for (let i = 0; i < argv.length; i++) {
@@ -77,6 +80,11 @@ export function parseArgs(argv) {
7780
continue;
7881
}
7982

83+
if (arg === "--no-restart") {
84+
out.noRestart = true;
85+
continue;
86+
}
87+
8088
if (arg.startsWith("--broker-url=")) {
8189
out.brokerUrl = arg.slice("--broker-url=".length);
8290
continue;
@@ -558,6 +566,32 @@ export function isMainModule(moduleUrl = import.meta.url, argv1 = process.argv[1
558566
return moduleUrl === argvUrl || (argvRealUrl !== "" && moduleUrl === argvRealUrl);
559567
}
560568

569+
export function hasSystemd() {
570+
try {
571+
fs.accessSync("/run/systemd/system", fs.constants.F_OK);
572+
return true;
573+
} catch {
574+
return false;
575+
}
576+
}
577+
578+
export function restartAgent({ logger = () => {}, execFileSyncImpl = execFileSync } = {}) {
579+
if (!hasSystemd()) {
580+
console.log("⚠️ systemd not available — restart the agent manually.");
581+
return false;
582+
}
583+
584+
logger("Restarting agent via systemctl...");
585+
try {
586+
execFileSyncImpl("systemctl", ["restart", "baudbot"], { stdio: "inherit" });
587+
console.log("✅ Agent restarted.");
588+
return true;
589+
} catch {
590+
console.error("⚠️ Agent restart failed — run: sudo baudbot restart");
591+
return false;
592+
}
593+
}
594+
561595
export async function main(argv = process.argv.slice(2)) {
562596
const parsed = parseArgs(argv);
563597

@@ -597,7 +631,11 @@ export async function main(argv = process.argv.slice(2)) {
597631
console.log(` - ${target.path}`);
598632
}
599633

600-
console.log("Next step: sudo baudbot restart");
634+
if (parsed.noRestart) {
635+
console.log("Next step: sudo baudbot restart");
636+
} else {
637+
restartAgent({ logger });
638+
}
601639

602640
return 0;
603641
}

bin/broker-register.test.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
isMainModule,
1717
lookupUser,
1818
resolveConfigTargets,
19+
restartAgent,
20+
hasSystemd,
1921
} from "./broker-register.mjs";
2022

2123
const FIXTURE_SERVER_KEYS = {
@@ -48,6 +50,7 @@ test("parseArgs parses long-form options", () => {
4850
registrationToken: "token-xyz",
4951
verbose: false,
5052
help: false,
53+
noRestart: false,
5154
});
5255
});
5356

@@ -341,3 +344,33 @@ test("resolveConfigTargets throws for unknown BAUDBOT_CONFIG_USER", () => {
341344
/admin user not found/,
342345
);
343346
});
347+
348+
test("parseArgs accepts --no-restart flag", () => {
349+
const parsed = parseArgs(["--no-restart", "--registration-token", "tok"]);
350+
assert.equal(parsed.noRestart, true);
351+
assert.equal(parsed.registrationToken, "tok");
352+
});
353+
354+
test("parseArgs defaults noRestart to false", () => {
355+
const parsed = parseArgs([]);
356+
assert.equal(parsed.noRestart, false);
357+
});
358+
359+
test("restartAgent returns false and warns when execFileSync fails", { skip: !hasSystemd() && "no systemd" }, () => {
360+
const logs = [];
361+
const logger = (msg) => logs.push(msg);
362+
const failingExec = () => { throw new Error("simulated failure"); };
363+
364+
const result = restartAgent({ logger, execFileSyncImpl: failingExec });
365+
assert.equal(result, false);
366+
});
367+
368+
test("restartAgent calls systemctl restart baudbot on success", { skip: !hasSystemd() && "no systemd" }, () => {
369+
const calls = [];
370+
const mockExec = (cmd, args) => { calls.push({ cmd, args }); };
371+
372+
restartAgent({ execFileSyncImpl: mockExec });
373+
assert.equal(calls.length, 1);
374+
assert.equal(calls[0].cmd, "systemctl");
375+
assert.deepEqual(calls[0].args, ["restart", "baudbot"]);
376+
});

install.sh

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,28 +107,24 @@ info "Detected: ${BOLD}$PRETTY_NAME${RESET} ($DISTRO)"
107107

108108
# ── Detect admin user ────────────────────────────────────────────────────────
109109

110-
# If run via sudo, SUDO_USER is the real user. Otherwise ask.
110+
# If run via sudo, SUDO_USER is the real user. Otherwise detect or ask.
111111
ADMIN_USER="${SUDO_USER:-}"
112112
if [ -z "$ADMIN_USER" ] || [ "$ADMIN_USER" = "root" ]; then
113-
# Try to find a non-root user with a home directory
114-
ADMIN_USER=""
113+
# Try to find a non-root user with a home directory as the default candidate
114+
CANDIDATE=""
115115
while IFS=: read -r username _ uid _ _ home _; do
116116
if [ "$uid" -ge 1000 ] && [ "$uid" -lt 60000 ] && [ -d "$home" ] && [ "$username" != "baudbot_agent" ]; then
117-
ADMIN_USER="$username"
117+
CANDIDATE="$username"
118118
break
119119
fi
120120
done < /etc/passwd
121121

122-
if [ -z "$ADMIN_USER" ]; then
123-
ask "Admin username (your account, not root): "
124-
read -r ADMIN_USER
125-
else
126-
ask "Admin username [${ADMIN_USER}]: "
127-
read -r input
128-
if [ -n "$input" ]; then
129-
ADMIN_USER="$input"
130-
fi
131-
fi
122+
# Fall back to current user (typically root when running directly as root)
123+
CANDIDATE="${CANDIDATE:-$(whoami)}"
124+
125+
ask "Admin username [${CANDIDATE}]: "
126+
read -r input
127+
ADMIN_USER="${input:-$CANDIDATE}"
132128
fi
133129

134130
if ! id "$ADMIN_USER" &>/dev/null; then

0 commit comments

Comments
 (0)