-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·357 lines (315 loc) · 12.9 KB
/
setup.sh
File metadata and controls
executable file
·357 lines (315 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/bin/bash
# Baudbot Agent Setup Script
# Run as root or with sudo from the admin user account
#
# Prerequisites:
# - Linux (tested on Arch and Ubuntu)
# - Docker installed
#
# This script:
# 1. Creates the baudbot_agent user
# 2. Installs Node.js and pi
# 3. Sets up SSH key for GitHub
# 4. Installs the Docker wrapper
# 5. Installs the safe bash wrapper (tool deny list)
# 6. Configures sudoers
# 7. Creates runtime directories and deploys from source
# 8. Installs extension and bridge dependencies
# 9. Sets up firewall and makes it persistent
# 10. Enables /proc hidepid isolation (process visibility)
# 11. Makes ~/baudbot/ read-only to the agent
#
# ⚠️ If you add a step here, add the reverse to bin/uninstall.sh!
#
# After running, you still need to:
# - Set the baudbot_agent password: sudo passwd baudbot_agent
# - Add secrets to ~/.config/.env (see CONFIGURATION.md)
# - Add the SSH public key to your GitHub account
# - Add the admin user to baudbot_agent group (for file access): sudo usermod -aG baudbot_agent <admin_user>
set -euo pipefail
EXPERIMENTAL=0
ADMIN_USER=""
while [ "$#" -gt 0 ]; do
case "$1" in
--experimental)
EXPERIMENTAL=1
shift
;;
-h|--help)
echo "Usage: $0 [--experimental] <admin_user>"
exit 0
;;
*)
if [ -n "$ADMIN_USER" ]; then
echo "Usage: $0 [--experimental] <admin_user>"
exit 1
fi
ADMIN_USER="$1"
shift
;;
esac
done
if [ -z "$ADMIN_USER" ]; then
echo "Usage: $0 [--experimental] <admin_user>"
exit 1
fi
BAUDBOT_HOME="/home/baudbot_agent"
# Source repo auto-detected from this script's location (can live anywhere)
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=bin/lib/runtime-node.sh
source "$REPO_DIR/bin/lib/runtime-node.sh"
NODE_VERSION="$(bb_runtime_node_version)"
PI_VERSION="${BAUDBOT_PI_VERSION:-0.52.12}"
NODE_VERSIONED_DIR="$BAUDBOT_HOME/opt/node-v$NODE_VERSION-linux-x64"
NODE_BIN_DIR="$(bb_runtime_node_bin_dir "$BAUDBOT_HOME")"
# Work from a neutral directory — sudo -u baudbot_agent inherits CWD, and
# git/find fail if CWD is a directory the agent can't access (e.g. /root).
cd /tmp
if [ "$EXPERIMENTAL" -eq 1 ]; then
echo "=== Experimental mode enabled (includes risky/unstable integrations) ==="
fi
echo "=== Creating baudbot_agent user ==="
if id baudbot_agent &>/dev/null; then
echo "User already exists, skipping"
else
useradd -m -s /bin/bash baudbot_agent
echo "User created. Run 'sudo passwd baudbot_agent' after setup."
fi
chmod 750 "$BAUDBOT_HOME"
echo "=== Ensuring .bashrc exists ==="
sudo -u baudbot_agent touch "$BAUDBOT_HOME/.bashrc"
echo "=== Adding $ADMIN_USER to baudbot_agent group ==="
usermod -aG baudbot_agent "$ADMIN_USER"
echo "=== Generating SSH key ==="
if [ ! -f "$BAUDBOT_HOME/.ssh/id_ed25519" ]; then
sudo -u baudbot_agent bash -c '
mkdir -p ~/.ssh
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
ssh-keygen -t ed25519 -C "baudbot-agent" -f ~/.ssh/id_ed25519 -N ""
cat > ~/.ssh/config << SSHEOF
Host github.com
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
SSHEOF
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub ~/.ssh/known_hosts
'
echo "SSH public key:"
cat "$BAUDBOT_HOME/.ssh/id_ed25519.pub"
echo "Add this to https://github.com/settings/keys for your agent's GitHub account"
else
echo "SSH key already exists, skipping"
fi
echo "=== Installing Node.js $NODE_VERSION ==="
if [ ! -d "$NODE_VERSIONED_DIR" ]; then
sudo -u baudbot_agent bash -c "
mkdir -p ~/opt
curl -fsSL https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz -o /tmp/node.tar.xz
tar xJf /tmp/node.tar.xz -C ~/opt/
rm /tmp/node.tar.xz
"
else
echo "Node.js already installed, skipping"
fi
sudo -u baudbot_agent bash -c "ln -sfn \"node-v$NODE_VERSION-linux-x64\" ~/opt/node"
echo "=== Installing pi $PI_VERSION ==="
sudo -u baudbot_agent env PATH="$NODE_BIN_DIR:$PATH" \
npm install -g "@mariozechner/pi-coding-agent@$PI_VERSION"
echo "=== Configuring git identity ==="
GIT_USER_NAME="${GIT_USER_NAME:-baudbot-agent}"
GIT_USER_EMAIL="${GIT_USER_EMAIL:-baudbot-agent@users.noreply.github.com}"
sudo -u baudbot_agent bash -c "
git config --global user.name '$GIT_USER_NAME'
git config --global user.email '$GIT_USER_EMAIL'
git config --global init.defaultBranch main
"
echo "=== Configuring shared repo permissions ==="
# Set core.sharedRepository=group on all repos so git creates objects
# with group-write perms. Without this, umask 077 in start.sh causes
# new .git/objects to be owner-only, breaking group access (admin user).
# Source repo — set as admin user (agent can't access admin home, and root
# needs safe.directory due to different ownership)
if [ -d "$REPO_DIR/.git" ]; then
sudo -u "$ADMIN_USER" git -C "$REPO_DIR" config core.sharedRepository group
echo " ✓ $REPO_DIR"
fi
# Agent workspace repos — set as agent
for repo in "$BAUDBOT_HOME"/workspace/*/; do
if [ -d "$repo/.git" ]; then
sudo -u baudbot_agent git -C "$repo" config core.sharedRepository group
echo " ✓ $repo"
fi
done
echo "=== Adding PATH to bashrc ==="
if ! grep -q "\$HOME/opt/node/bin" "$BAUDBOT_HOME/.bashrc"; then
sudo -u baudbot_agent bash -c "echo 'export PATH=\$HOME/opt/node/bin:\$PATH' >> ~/.bashrc"
fi
echo "=== Setting up secrets directory ==="
sudo -u baudbot_agent bash -c '
mkdir -p ~/.config
touch ~/.config/.env
chmod 600 ~/.config/.env
'
echo "=== Installing pre-commit hook (root-owned, tamper-proof) ==="
cp "$REPO_DIR/hooks/pre-commit" "$REPO_DIR/.git/hooks/pre-commit"
chown root:root "$REPO_DIR/.git/hooks/pre-commit"
chmod 755 "$REPO_DIR/.git/hooks/pre-commit"
echo "Installed root-owned pre-commit hook — agent cannot modify protected security files"
echo "=== Installing Docker wrapper ==="
cp "$REPO_DIR/bin/baudbot-docker" /usr/local/bin/baudbot-docker
chown root:root /usr/local/bin/baudbot-docker
chmod 755 /usr/local/bin/baudbot-docker
echo "=== Installing safe bash wrapper ==="
cp "$REPO_DIR/bin/baudbot-safe-bash" /usr/local/bin/baudbot-safe-bash
chown root:root /usr/local/bin/baudbot-safe-bash
chmod 755 /usr/local/bin/baudbot-safe-bash
echo "Installed /usr/local/bin/baudbot-safe-bash (root-owned, not agent-writable)"
echo "=== Adding docker alias ==="
if ! grep -q "baudbot-docker" "$BAUDBOT_HOME/.bashrc"; then
sudo -u baudbot_agent bash -c 'echo "alias docker=\"sudo /usr/local/bin/baudbot-docker\"" >> ~/.bashrc'
fi
echo "=== Configuring sudoers ==="
cat > /etc/sudoers.d/baudbot-agent << EOF
# Allow admin to manage baudbot
$ADMIN_USER ALL=(baudbot_agent) NOPASSWD: ALL
# Allow baudbot to use docker wrapper
baudbot_agent ALL=(root) NOPASSWD: /usr/local/bin/baudbot-docker
EOF
chmod 440 /etc/sudoers.d/baudbot-agent
if [ "$EXPERIMENTAL" -eq 1 ]; then
echo "=== Persisting experimental feature flag ==="
ADMIN_HOME=$(getent passwd "$ADMIN_USER" | cut -d: -f6)
ADMIN_CONFIG_DIR="$ADMIN_HOME/.baudbot"
ADMIN_CONFIG_FILE="$ADMIN_CONFIG_DIR/.env"
mkdir -p "$ADMIN_CONFIG_DIR"
touch "$ADMIN_CONFIG_FILE"
if grep -q '^BAUDBOT_EXPERIMENTAL=' "$ADMIN_CONFIG_FILE"; then
sed -i 's/^BAUDBOT_EXPERIMENTAL=.*/BAUDBOT_EXPERIMENTAL=1/' "$ADMIN_CONFIG_FILE"
else
echo "BAUDBOT_EXPERIMENTAL=1" >> "$ADMIN_CONFIG_FILE"
fi
chmod 700 "$ADMIN_CONFIG_DIR"
chmod 600 "$ADMIN_CONFIG_FILE"
chown -R "$ADMIN_USER:$ADMIN_USER" "$ADMIN_CONFIG_DIR"
fi
echo "=== Setting up runtime directories ==="
# The agent runs from deployed copies, not from the source repo directly.
# Source: ~/baudbot/ (typically not readable by agent in hardened default installs)
# Runtime: ~/.pi/agent/extensions/, ~/.pi/agent/skills/, ~/runtime/
sudo -u baudbot_agent bash -c '
mkdir -p ~/.pi/agent/extensions
mkdir -p ~/.pi/agent/skills
mkdir -p ~/.pi/agent/memory
mkdir -p ~/runtime
'
echo "=== Installing extension dependencies ==="
# npm install runs in source (admin-owned) then deploy copies to runtime
export PATH="$NODE_BIN_DIR:$PATH"
while IFS= read -r dir; do
ext_name="$(basename "$dir")"
if [ "$EXPERIMENTAL" -ne 1 ] && { [ "$ext_name" = "agentmail" ] || [ "$ext_name" = "email-monitor" ]; }; then
echo " Skipping deps in $dir (experimental-only)"
continue
fi
echo " Installing deps in $dir"
(cd "$dir" && npm install)
done < <(find "$REPO_DIR/pi/extensions" -name package.json -not -path '*/node_modules/*' -exec dirname {} \;)
echo "=== Installing Gateway bridge dependencies ==="
(cd "$REPO_DIR/gateway-bridge" && npm install)
echo "=== Installing varlock ==="
# varlock must be available to the agent user (start.sh adds ~/.varlock/bin to PATH).
# Install as agent user so it lands in the right home directory.
AGENT_VARLOCK="$BAUDBOT_HOME/.varlock/bin/varlock"
if [ -x "$AGENT_VARLOCK" ]; then
echo "varlock already installed for baudbot_agent, skipping"
else
sudo -u baudbot_agent bash -c 'curl -sSfL https://varlock.dev/install.sh | sh -s'
fi
echo "=== Publishing initial git-free /opt release ==="
# Build an immutable release snapshot from the local source checkout, then deploy
# from /opt/baudbot/releases/<sha>. This keeps live operations decoupled from
# the mutable source checkout.
BOOTSTRAP_BRANCH=$(sudo -u "$ADMIN_USER" git -C "$REPO_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
BAUDBOT_ROOT="$REPO_DIR" BAUDBOT_CONFIG_USER="$ADMIN_USER" BAUDBOT_EXPERIMENTAL="$EXPERIMENTAL" \
"$REPO_DIR/bin/update-release.sh" --repo "$REPO_DIR" --branch "$BOOTSTRAP_BRANCH" --skip-preflight --skip-restart
echo "Published /opt release and deployed runtime files"
echo "=== Protecting source repo ==="
# Source is now admin-owned (outside baudbot_agent's home), so the agent
# cannot write to it by default. Tool-guard also blocks writes to REPO_DIR.
# If desired, a read-only bind mount can be added for defense-in-depth:
# mount --bind "$REPO_DIR" "$REPO_DIR" && mount -o remount,bind,ro "$REPO_DIR"
echo "Source repo at $REPO_DIR is admin-owned (not writable by baudbot_agent)"
if [ "${BAUDBOT_SKIP_FIREWALL:-0}" = "1" ]; then
echo "=== Skipping firewall setup (BAUDBOT_SKIP_FIREWALL=1) ==="
else
echo "=== Setting up firewall ==="
"$REPO_DIR/bin/setup-firewall.sh"
echo "=== Making firewall persistent ==="
sed "s|__REPO_DIR__|$REPO_DIR|g" "$REPO_DIR/bin/baudbot-firewall.service" > /etc/systemd/system/baudbot-firewall.service
systemctl daemon-reload
systemctl enable baudbot-firewall
echo "Firewall will be restored on boot via systemd"
fi
echo "=== Verifying baudbot CLI path ==="
if [ -x /usr/local/bin/baudbot ]; then
CLI_TARGET=$(readlink -f /usr/local/bin/baudbot 2>/dev/null || true)
echo "Installed /usr/local/bin/baudbot → ${CLI_TARGET:-unknown}"
else
echo "⚠️ /usr/local/bin/baudbot not found after bootstrap release"
fi
echo "=== Installing baudbot systemd unit ==="
# Template the service file with the correct paths
sed \
-e "s|/home/baudbot_agent|$BAUDBOT_HOME|g" \
"$REPO_DIR/bin/baudbot.service" > /etc/systemd/system/baudbot.service
systemctl daemon-reload
systemctl enable baudbot
echo "Installed baudbot.service (enabled, not started)"
echo "Start with: baudbot start"
echo "=== Setting up /proc isolation (hidepid) ==="
# Create a group whose members can still see all processes.
# The admin user is added; baudbot_agent is NOT — it only sees its own processes.
PROC_GID_GROUP="procview"
if ! getent group "$PROC_GID_GROUP" &>/dev/null; then
groupadd "$PROC_GID_GROUP"
echo "Created group: $PROC_GID_GROUP"
fi
usermod -aG "$PROC_GID_GROUP" "$ADMIN_USER"
PROC_GID=$(getent group "$PROC_GID_GROUP" | cut -d: -f3)
# Apply immediately
mount -o remount,hidepid=2,gid="$PROC_GID" /proc
echo "Remounted /proc with hidepid=2,gid=$PROC_GID"
# Persist in /etc/fstab (idempotent)
if grep -q '^proc\s\+/proc' /etc/fstab; then
# Update existing proc line
sed -i "s|^proc\s\+/proc\s\+proc\s\+.*|proc /proc proc defaults,hidepid=2,gid=$PROC_GID 0 0|" /etc/fstab
echo "Updated existing /proc entry in /etc/fstab"
else
echo "proc /proc proc defaults,hidepid=2,gid=$PROC_GID 0 0" >> /etc/fstab
echo "Added /proc entry to /etc/fstab"
fi
echo "Process isolation: baudbot_agent can only see its own processes"
echo "=== Hardening permissions ==="
sudo -u baudbot_agent bash -c "cd ~ && '$BAUDBOT_HOME/runtime/bin/harden-permissions.sh'"
echo ""
echo "=== Setup complete ==="
echo ""
echo "Remaining manual steps:"
echo " 1. sudo passwd baudbot_agent"
echo " 2. Add secrets: sudo baudbot config"
echo " Or manually edit: $BAUDBOT_HOME/.config/.env"
echo " 3. Add SSH key to your agent's GitHub account:"
echo " cat $BAUDBOT_HOME/.ssh/id_ed25519.pub"
echo " 4. Authenticate GitHub CLI:"
echo " sudo -u baudbot_agent gh auth login"
echo " 5. Log out and back in for group membership to take effect"
echo ""
echo "Commands:"
echo " baudbot start Start the agent"
echo " baudbot stop Stop the agent"
echo " baudbot status Check agent status"
echo " baudbot logs Tail agent logs"
echo " baudbot deploy Deploy source changes to agent runtime"
echo " baudbot doctor Health check"
echo " baudbot audit Security posture audit"