Skip to content

Commit 4389e19

Browse files
committed
arch: extract config to ~/.baudbot/, deploy copies to agent
Phase 2 of CLI restructure: - bin/config.sh: standalone interactive config command - Writes secrets to ~/.baudbot/.env (admin-owned) - Shows masked existing values on re-run - Accepts BAUDBOT_CONFIG_USER env var for install.sh - bin/deploy.sh: copies ~/.baudbot/.env → agent's ~/.config/.env - Falls back to existing agent config if no admin config found - Sets 600 perms and correct ownership - install.sh: calls 'baudbot config' then 'baudbot deploy' instead of inline prompting. ~200 lines removed. - bin/baudbot: config command now routes to config.sh - bin/doctor.sh: checks for admin config dir - CI: verifies admin config written + deployed to agent
1 parent ff460e1 commit 4389e19

7 files changed

Lines changed: 373 additions & 212 deletions

File tree

bin/baudbot

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,7 @@ case "${1:-}" in
152152

153153
config)
154154
shift
155-
# config writes to ~/.baudbot/ on the calling user
156-
# For now, point to install.sh's config section
157-
echo "Config management is not yet extracted into a standalone command."
158-
echo "Use: sudo $BAUDBOT_ROOT/install.sh"
159-
exit 1
155+
exec "$BAUDBOT_ROOT/bin/config.sh" "$@"
160156
;;
161157

162158
deploy)

bin/ci/setup-arch.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent"
3131
# Runtime deployed
3232
test -f /home/baudbot_agent/runtime/start.sh
3333
test -d /home/baudbot_agent/.pi/agent/extensions
34-
# Required secrets written
34+
# Admin config written
35+
test -f /home/baudbot_admin/.baudbot/.env
36+
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_admin/.baudbot/.env
37+
# Deployed to agent
3538
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
3639
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
3740
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env

bin/ci/setup-ubuntu.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent"
4242
# Runtime deployed
4343
test -f /home/baudbot_agent/runtime/start.sh
4444
test -d /home/baudbot_agent/.pi/agent/extensions
45-
# Required secrets written
45+
# Admin config written
46+
test -f /home/baudbot_admin/.baudbot/.env
47+
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_admin/.baudbot/.env
48+
# Deployed to agent
4649
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
4750
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
4851
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env

bin/config.sh

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/bin/bash
2+
# Baudbot Config — interactive secrets and configuration setup.
3+
# Writes to ~/.baudbot/.env (admin-owned). Deploy copies to agent runtime.
4+
#
5+
# Usage: baudbot config
6+
# sudo baudbot config (when run via install.sh)
7+
#
8+
# Can be re-run to update existing config. Existing values shown as defaults.
9+
10+
set -euo pipefail
11+
12+
# ── Formatting ───────────────────────────────────────────────────────────────
13+
14+
BOLD='\033[1m'
15+
DIM='\033[2m'
16+
GREEN='\033[0;32m'
17+
YELLOW='\033[0;33m'
18+
RED='\033[0;31m'
19+
CYAN='\033[0;36m'
20+
RESET='\033[0m'
21+
22+
info() { echo -e "${BOLD}${GREEN}${RESET} $1"; }
23+
warn() { echo -e "${BOLD}${YELLOW}${RESET} $1"; }
24+
ask() { echo -en "${BOLD}${CYAN}?${RESET} $1"; }
25+
dim() { echo -e "${DIM}$1${RESET}"; }
26+
27+
# ── Determine config directory ───────────────────────────────────────────────
28+
29+
# If run as root via sudo, write to the admin user's ~/.baudbot/
30+
# If run as a normal user, write to their own ~/.baudbot/
31+
# BAUDBOT_CONFIG_USER env var overrides detection (used by install.sh)
32+
if [ -n "${BAUDBOT_CONFIG_USER:-}" ]; then
33+
CONFIG_USER="$BAUDBOT_CONFIG_USER"
34+
CONFIG_HOME=$(getent passwd "$CONFIG_USER" | cut -d: -f6)
35+
elif [ "$(id -u)" -eq 0 ]; then
36+
CONFIG_USER="${SUDO_USER:-root}"
37+
if [ "$CONFIG_USER" = "root" ]; then
38+
echo "Run as: sudo baudbot config (not as root directly)"
39+
exit 1
40+
fi
41+
CONFIG_HOME=$(getent passwd "$CONFIG_USER" | cut -d: -f6)
42+
else
43+
CONFIG_USER="$(whoami)"
44+
CONFIG_HOME="$HOME"
45+
fi
46+
47+
CONFIG_DIR="$CONFIG_HOME/.baudbot"
48+
CONFIG_FILE="$CONFIG_DIR/.env"
49+
50+
mkdir -p "$CONFIG_DIR"
51+
# Ensure owned by the admin user (not root)
52+
if [ "$(id -u)" -eq 0 ]; then
53+
chown "$CONFIG_USER:$CONFIG_USER" "$CONFIG_DIR"
54+
fi
55+
56+
# ── Load existing config ─────────────────────────────────────────────────────
57+
58+
declare -A ENV_VARS
59+
declare -A EXISTING
60+
61+
if [ -f "$CONFIG_FILE" ]; then
62+
while IFS='=' read -r key value; do
63+
# Skip comments and empty lines
64+
[[ "$key" =~ ^#.*$ ]] && continue
65+
[ -z "$key" ] && continue
66+
EXISTING[$key]="$value"
67+
done < "$CONFIG_FILE"
68+
fi
69+
70+
# ── Prompting ────────────────────────────────────────────────────────────────
71+
72+
# prompt_secret KEY "description" "url" [required] [prefix]
73+
# If an existing value is set, shows [****] and allows Enter to keep it.
74+
prompt_secret() {
75+
local key="$1" desc="$2" url="${3:-}" required="${4:-}" prefix="${5:-}"
76+
local label="" existing="${EXISTING[$key]:-}"
77+
78+
if [ "$required" = "required" ]; then
79+
label="${RED}*${RESET} "
80+
fi
81+
82+
if [ -n "$url" ]; then
83+
dim " $url"
84+
fi
85+
86+
if [ -n "$existing" ]; then
87+
# Show masked existing value
88+
local masked="${existing:0:4}****"
89+
ask "${label}${desc} [${masked}]: "
90+
else
91+
ask "${label}${desc}: "
92+
fi
93+
read -r value
94+
95+
# Empty input with existing value = keep existing
96+
if [ -z "$value" ] && [ -n "$existing" ]; then
97+
ENV_VARS[$key]="$existing"
98+
return
99+
fi
100+
101+
# Validate prefix if provided
102+
if [ -n "$value" ] && [ -n "$prefix" ]; then
103+
local match=false
104+
IFS='|' read -ra prefixes <<< "$prefix"
105+
for p in "${prefixes[@]}"; do
106+
if [[ "$value" == "$p"* ]]; then
107+
match=true
108+
break
109+
fi
110+
done
111+
if [ "$match" = false ]; then
112+
warn "Expected prefix '${prefix}' — saved anyway"
113+
fi
114+
fi
115+
116+
# Warn if required and empty
117+
if [ -z "$value" ] && [ "$required" = "required" ]; then
118+
warn "Skipped (required — agent won't fully work without this)"
119+
fi
120+
121+
if [ -n "$value" ]; then
122+
ENV_VARS[$key]="$value"
123+
fi
124+
}
125+
126+
# ── Collect secrets ──────────────────────────────────────────────────────────
127+
128+
echo ""
129+
if [ -f "$CONFIG_FILE" ]; then
130+
echo -e "Updating config in ${BOLD}$CONFIG_FILE${RESET}"
131+
echo -e "Press ${BOLD}Enter${RESET} to keep existing values."
132+
else
133+
echo -e "Baudbot needs API keys to talk to services."
134+
echo -e "Press ${BOLD}Enter${RESET} to skip optional values."
135+
fi
136+
echo -e " ${DIM}$CONFIG_FILE${RESET}"
137+
echo ""
138+
139+
# -- Required --
140+
echo -e "${BOLD}Required${RESET} ${DIM}(agent won't start without these)${RESET}"
141+
echo ""
142+
143+
echo -e "${BOLD}LLM provider${RESET} ${DIM}(set at least one)${RESET}"
144+
echo ""
145+
146+
prompt_secret "ANTHROPIC_API_KEY" \
147+
"Anthropic API key" \
148+
"https://console.anthropic.com/settings/keys" \
149+
"" \
150+
"sk-ant-"
151+
152+
prompt_secret "OPENAI_API_KEY" \
153+
"OpenAI API key" \
154+
"https://platform.openai.com/api-keys" \
155+
"" \
156+
"sk-"
157+
158+
prompt_secret "GEMINI_API_KEY" \
159+
"Google Gemini API key" \
160+
"https://aistudio.google.com/apikey"
161+
162+
prompt_secret "OPENCODE_ZEN_API_KEY" \
163+
"OpenCode Zen API key (multi-provider router)" \
164+
"https://opencode.ai"
165+
166+
HAS_LLM_KEY=false
167+
for k in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do
168+
if [ -n "${ENV_VARS[$k]:-}" ]; then HAS_LLM_KEY=true; break; fi
169+
done
170+
if [ "$HAS_LLM_KEY" = false ]; then
171+
warn "No LLM key set — agent needs at least one to work"
172+
fi
173+
174+
echo ""
175+
176+
prompt_secret "GITHUB_TOKEN" \
177+
"GitHub personal access token" \
178+
"https://github.com/settings/tokens" \
179+
"required" \
180+
"ghp_|github_pat_"
181+
182+
prompt_secret "SLACK_BOT_TOKEN" \
183+
"Slack bot token" \
184+
"https://api.slack.com/apps → OAuth & Permissions" \
185+
"required" \
186+
"xoxb-"
187+
188+
prompt_secret "SLACK_APP_TOKEN" \
189+
"Slack app-level token (Socket Mode)" \
190+
"https://api.slack.com/apps → Basic Information → App-Level Tokens" \
191+
"required" \
192+
"xapp-"
193+
194+
prompt_secret "SLACK_ALLOWED_USERS" \
195+
"Slack user IDs (comma-separated)" \
196+
"Click your Slack profile → ··· → Copy member ID" \
197+
"required" \
198+
"U"
199+
200+
echo ""
201+
202+
# -- Optional --
203+
echo -e "${BOLD}Optional${RESET} ${DIM}(press Enter to skip)${RESET}"
204+
echo ""
205+
206+
prompt_secret "AGENTMAIL_API_KEY" \
207+
"AgentMail API key" \
208+
"https://app.agentmail.to"
209+
210+
prompt_secret "BAUDBOT_EMAIL" \
211+
"Agent email address (e.g. agent@agentmail.to)"
212+
213+
if [ -n "${ENV_VARS[AGENTMAIL_API_KEY]:-}" ]; then
214+
prompt_secret "BAUDBOT_SECRET" \
215+
"Email auth secret (or press Enter to auto-generate)"
216+
if [ -z "${ENV_VARS[BAUDBOT_SECRET]:-}" ]; then
217+
ENV_VARS[BAUDBOT_SECRET]="$(openssl rand -hex 32)"
218+
dim " Auto-generated: ${ENV_VARS[BAUDBOT_SECRET]}"
219+
fi
220+
221+
prompt_secret "BAUDBOT_ALLOWED_EMAILS" \
222+
"Allowed sender emails (comma-separated)"
223+
fi
224+
225+
prompt_secret "SENTRY_AUTH_TOKEN" \
226+
"Sentry API token" \
227+
"https://sentry.io/settings/account/api/auth-tokens/"
228+
229+
if [ -n "${ENV_VARS[SENTRY_AUTH_TOKEN]:-}" ]; then
230+
prompt_secret "SENTRY_ORG" "Sentry org slug"
231+
prompt_secret "SENTRY_CHANNEL_ID" "Slack channel ID for Sentry alerts" "" "" "C"
232+
fi
233+
234+
prompt_secret "KERNEL_API_KEY" \
235+
"Kernel cloud browser API key" \
236+
"https://kernel.computer"
237+
238+
# ── Auto-set values ──────────────────────────────────────────────────────────
239+
240+
# These are set automatically based on the system state
241+
ENV_VARS[BAUDBOT_AGENT_USER]="baudbot_agent"
242+
243+
if id baudbot_agent &>/dev/null; then
244+
ENV_VARS[BAUDBOT_AGENT_HOME]=$(getent passwd baudbot_agent | cut -d: -f6)
245+
else
246+
ENV_VARS[BAUDBOT_AGENT_HOME]="/home/baudbot_agent"
247+
fi
248+
249+
# Source dir: resolve from this script's location, or keep existing
250+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd || echo "")"
251+
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/setup.sh" ]; then
252+
ENV_VARS[BAUDBOT_SOURCE_DIR]="$SCRIPT_DIR"
253+
elif [ -n "${EXISTING[BAUDBOT_SOURCE_DIR]:-}" ]; then
254+
ENV_VARS[BAUDBOT_SOURCE_DIR]="${EXISTING[BAUDBOT_SOURCE_DIR]}"
255+
fi
256+
257+
# ── Write config ─────────────────────────────────────────────────────────────
258+
259+
ENV_CONTENT="# Baudbot configuration
260+
# Generated by baudbot config on $(date -Iseconds)
261+
# Re-run: baudbot config
262+
# Deploy: baudbot deploy
263+
"
264+
265+
ordered_keys=(
266+
ANTHROPIC_API_KEY
267+
OPENAI_API_KEY
268+
GEMINI_API_KEY
269+
OPENCODE_ZEN_API_KEY
270+
GITHUB_TOKEN
271+
SLACK_BOT_TOKEN
272+
SLACK_APP_TOKEN
273+
SLACK_ALLOWED_USERS
274+
AGENTMAIL_API_KEY
275+
BAUDBOT_EMAIL
276+
BAUDBOT_SECRET
277+
BAUDBOT_ALLOWED_EMAILS
278+
SENTRY_AUTH_TOKEN
279+
SENTRY_ORG
280+
SENTRY_CHANNEL_ID
281+
KERNEL_API_KEY
282+
BAUDBOT_AGENT_USER
283+
BAUDBOT_AGENT_HOME
284+
BAUDBOT_SOURCE_DIR
285+
)
286+
287+
for key in "${ordered_keys[@]}"; do
288+
if [ -n "${ENV_VARS[$key]:-}" ]; then
289+
ENV_CONTENT+="${key}=${ENV_VARS[$key]}"$'\n'
290+
fi
291+
done
292+
293+
echo "$ENV_CONTENT" > "$CONFIG_FILE"
294+
chmod 600 "$CONFIG_FILE"
295+
# Ensure owned by admin user
296+
if [ "$(id -u)" -eq 0 ]; then
297+
chown "$CONFIG_USER:$CONFIG_USER" "$CONFIG_FILE"
298+
fi
299+
300+
VAR_COUNT=$(grep -c '=' "$CONFIG_FILE")
301+
info "Wrote $VAR_COUNT variables to $CONFIG_FILE"
302+
echo ""
303+
echo -e "Next: ${BOLD}sudo baudbot deploy${RESET} to push config to the agent"
304+
echo ""

bin/deploy.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,34 @@ if [ -f "$STAGE_DIR/.env.schema" ]; then
225225
fi
226226
fi
227227

228+
# ── Admin config (secrets) ────────────────────────────────────────────────────
229+
230+
echo "Deploying config..."
231+
232+
# Determine who invoked this (the admin user)
233+
DEPLOY_USER="${SUDO_USER:-$(whoami)}"
234+
DEPLOY_HOME=$(getent passwd "$DEPLOY_USER" | cut -d: -f6 2>/dev/null || echo "")
235+
ADMIN_CONFIG="$DEPLOY_HOME/.baudbot/.env"
236+
237+
if [ -f "$ADMIN_CONFIG" ]; then
238+
if [ "$DRY_RUN" -eq 0 ]; then
239+
as_agent bash -c "mkdir -p '$BAUDBOT_HOME/.config'"
240+
cp "$ADMIN_CONFIG" "$BAUDBOT_HOME/.config/.env"
241+
chown "$AGENT_USER:$AGENT_USER" "$BAUDBOT_HOME/.config/.env"
242+
chmod 600 "$BAUDBOT_HOME/.config/.env"
243+
log "✓ .env → ~/.config/.env (600)"
244+
else
245+
log "would copy: $ADMIN_CONFIG → ~/.config/.env"
246+
fi
247+
else
248+
# Fallback: check if agent already has a .env (written directly by old install.sh)
249+
if as_agent test -f "$BAUDBOT_HOME/.config/.env" 2>/dev/null; then
250+
log "- .env: using existing agent config (no ~/.baudbot/.env found)"
251+
else
252+
log "⚠ no config found — run: baudbot config"
253+
fi
254+
fi
255+
228256
# ── Version stamp + integrity manifest ────────────────────────────────────────
229257

230258
echo "Stamping version..."

bin/doctor.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,21 @@ fi
7171
# ── Secrets ──────────────────────────────────────────────────────────────────
7272

7373
echo ""
74-
echo "Secrets:"
74+
echo "Admin config:"
75+
76+
# Check for admin config dir
77+
ADMIN_USER="${SUDO_USER:-$(whoami)}"
78+
ADMIN_HOME=$(getent passwd "$ADMIN_USER" | cut -d: -f6 2>/dev/null || echo "")
79+
ADMIN_CONFIG="$ADMIN_HOME/.baudbot/.env"
80+
81+
if [ -n "$ADMIN_HOME" ] && [ -f "$ADMIN_CONFIG" ]; then
82+
pass "~/.baudbot/.env exists ($ADMIN_CONFIG)"
83+
else
84+
warn "~/.baudbot/.env not found (run: baudbot config)"
85+
fi
86+
87+
echo ""
88+
echo "Agent secrets:"
7589

7690
ENV_FILE="$BAUDBOT_HOME/.config/.env"
7791
if [ -f "$ENV_FILE" ]; then

0 commit comments

Comments
 (0)