Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions bin/baudbot
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,7 @@ case "${1:-}" in

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

deploy)
Expand Down
5 changes: 4 additions & 1 deletion bin/ci/setup-arch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent"
# Runtime deployed
test -f /home/baudbot_agent/runtime/start.sh
test -d /home/baudbot_agent/.pi/agent/extensions
# Required secrets written
# Admin config written
test -f /home/baudbot_admin/.baudbot/.env
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_admin/.baudbot/.env
# Deployed to agent
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env
Expand Down
5 changes: 4 additions & 1 deletion bin/ci/setup-ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ test "$(stat -c '%U' /home/baudbot_agent/.config/.env)" = "baudbot_agent"
# Runtime deployed
test -f /home/baudbot_agent/runtime/start.sh
test -d /home/baudbot_agent/.pi/agent/extensions
# Required secrets written
# Admin config written
test -f /home/baudbot_admin/.baudbot/.env
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_admin/.baudbot/.env
# Deployed to agent
grep -q "ANTHROPIC_API_KEY=sk-ant-testkey" /home/baudbot_agent/.config/.env
grep -q "SLACK_BOT_TOKEN=xoxb-test" /home/baudbot_agent/.config/.env
grep -q "BAUDBOT_SOURCE_DIR=" /home/baudbot_agent/.config/.env
Expand Down
304 changes: 304 additions & 0 deletions bin/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
#!/bin/bash
# Baudbot Config — interactive secrets and configuration setup.
# Writes to ~/.baudbot/.env (admin-owned). Deploy copies to agent runtime.
#
# Usage: baudbot config
# sudo baudbot config (when run via install.sh)
#
# Can be re-run to update existing config. Existing values shown as defaults.

set -euo pipefail

# ── Formatting ───────────────────────────────────────────────────────────────

BOLD='\033[1m'
DIM='\033[2m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
CYAN='\033[0;36m'
RESET='\033[0m'

info() { echo -e "${BOLD}${GREEN}▸${RESET} $1"; }
warn() { echo -e "${BOLD}${YELLOW}▸${RESET} $1"; }
ask() { echo -en "${BOLD}${CYAN}?${RESET} $1"; }
dim() { echo -e "${DIM}$1${RESET}"; }

# ── Determine config directory ───────────────────────────────────────────────

# If run as root via sudo, write to the admin user's ~/.baudbot/
# If run as a normal user, write to their own ~/.baudbot/
# BAUDBOT_CONFIG_USER env var overrides detection (used by install.sh)
if [ -n "${BAUDBOT_CONFIG_USER:-}" ]; then
CONFIG_USER="$BAUDBOT_CONFIG_USER"
CONFIG_HOME=$(getent passwd "$CONFIG_USER" | cut -d: -f6)
elif [ "$(id -u)" -eq 0 ]; then
CONFIG_USER="${SUDO_USER:-root}"
if [ "$CONFIG_USER" = "root" ]; then
echo "Run as: sudo baudbot config (not as root directly)"
exit 1
fi
CONFIG_HOME=$(getent passwd "$CONFIG_USER" | cut -d: -f6)
else
CONFIG_USER="$(whoami)"
CONFIG_HOME="$HOME"
fi

CONFIG_DIR="$CONFIG_HOME/.baudbot"
Comment thread
sentry[bot] marked this conversation as resolved.
Outdated
CONFIG_FILE="$CONFIG_DIR/.env"

mkdir -p "$CONFIG_DIR"
# Ensure owned by the admin user (not root)
if [ "$(id -u)" -eq 0 ]; then
chown "$CONFIG_USER:$CONFIG_USER" "$CONFIG_DIR"
fi

# ── Load existing config ─────────────────────────────────────────────────────

declare -A ENV_VARS
declare -A EXISTING

if [ -f "$CONFIG_FILE" ]; then
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ "$key" =~ ^#.*$ ]] && continue
[ -z "$key" ] && continue
EXISTING[$key]="$value"
done < "$CONFIG_FILE"
fi

# ── Prompting ────────────────────────────────────────────────────────────────

# prompt_secret KEY "description" "url" [required] [prefix]
# If an existing value is set, shows [****] and allows Enter to keep it.
prompt_secret() {
local key="$1" desc="$2" url="${3:-}" required="${4:-}" prefix="${5:-}"
local label="" existing="${EXISTING[$key]:-}"

if [ "$required" = "required" ]; then
label="${RED}*${RESET} "
fi

if [ -n "$url" ]; then
dim " $url"
fi

if [ -n "$existing" ]; then
# Show masked existing value
local masked="${existing:0:4}****"
ask "${label}${desc} [${masked}]: "
else
ask "${label}${desc}: "
fi
read -r value

# Empty input with existing value = keep existing
if [ -z "$value" ] && [ -n "$existing" ]; then
ENV_VARS[$key]="$existing"
return
fi

# Validate prefix if provided
if [ -n "$value" ] && [ -n "$prefix" ]; then
local match=false
IFS='|' read -ra prefixes <<< "$prefix"
for p in "${prefixes[@]}"; do
if [[ "$value" == "$p"* ]]; then
match=true
break
fi
done
if [ "$match" = false ]; then
warn "Expected prefix '${prefix}' — saved anyway"
fi
fi

# Warn if required and empty
if [ -z "$value" ] && [ "$required" = "required" ]; then
warn "Skipped (required — agent won't fully work without this)"
fi

if [ -n "$value" ]; then
ENV_VARS[$key]="$value"
fi
}

# ── Collect secrets ──────────────────────────────────────────────────────────

echo ""
if [ -f "$CONFIG_FILE" ]; then
echo -e "Updating config in ${BOLD}$CONFIG_FILE${RESET}"
echo -e "Press ${BOLD}Enter${RESET} to keep existing values."
else
echo -e "Baudbot needs API keys to talk to services."
echo -e "Press ${BOLD}Enter${RESET} to skip optional values."
fi
echo -e " ${DIM}$CONFIG_FILE${RESET}"
echo ""

# -- Required --
echo -e "${BOLD}Required${RESET} ${DIM}(agent won't start without these)${RESET}"
echo ""

echo -e "${BOLD}LLM provider${RESET} ${DIM}(set at least one)${RESET}"
echo ""

prompt_secret "ANTHROPIC_API_KEY" \
"Anthropic API key" \
"https://console.anthropic.com/settings/keys" \
"" \
"sk-ant-"

prompt_secret "OPENAI_API_KEY" \
"OpenAI API key" \
"https://platform.openai.com/api-keys" \
"" \
"sk-"

prompt_secret "GEMINI_API_KEY" \
"Google Gemini API key" \
"https://aistudio.google.com/apikey"

prompt_secret "OPENCODE_ZEN_API_KEY" \
"OpenCode Zen API key (multi-provider router)" \
"https://opencode.ai"

HAS_LLM_KEY=false
for k in ANTHROPIC_API_KEY OPENAI_API_KEY GEMINI_API_KEY OPENCODE_ZEN_API_KEY; do
if [ -n "${ENV_VARS[$k]:-}" ]; then HAS_LLM_KEY=true; break; fi
done
if [ "$HAS_LLM_KEY" = false ]; then
warn "No LLM key set — agent needs at least one to work"
fi

echo ""

prompt_secret "GITHUB_TOKEN" \
"GitHub personal access token" \
"https://github.com/settings/tokens" \
"required" \
"ghp_|github_pat_"

prompt_secret "SLACK_BOT_TOKEN" \
"Slack bot token" \
"https://api.slack.com/apps → OAuth & Permissions" \
"required" \
"xoxb-"

prompt_secret "SLACK_APP_TOKEN" \
"Slack app-level token (Socket Mode)" \
"https://api.slack.com/apps → Basic Information → App-Level Tokens" \
"required" \
"xapp-"

prompt_secret "SLACK_ALLOWED_USERS" \
"Slack user IDs (comma-separated)" \
"Click your Slack profile → ··· → Copy member ID" \
"required" \
"U"

echo ""

# -- Optional --
echo -e "${BOLD}Optional${RESET} ${DIM}(press Enter to skip)${RESET}"
echo ""

prompt_secret "AGENTMAIL_API_KEY" \
"AgentMail API key" \
"https://app.agentmail.to"

prompt_secret "BAUDBOT_EMAIL" \
"Agent email address (e.g. agent@agentmail.to)"

if [ -n "${ENV_VARS[AGENTMAIL_API_KEY]:-}" ]; then
prompt_secret "BAUDBOT_SECRET" \
"Email auth secret (or press Enter to auto-generate)"
if [ -z "${ENV_VARS[BAUDBOT_SECRET]:-}" ]; then
ENV_VARS[BAUDBOT_SECRET]="$(openssl rand -hex 32)"
dim " Auto-generated: ${ENV_VARS[BAUDBOT_SECRET]}"
fi

prompt_secret "BAUDBOT_ALLOWED_EMAILS" \
"Allowed sender emails (comma-separated)"
fi

prompt_secret "SENTRY_AUTH_TOKEN" \
"Sentry API token" \
"https://sentry.io/settings/account/api/auth-tokens/"

if [ -n "${ENV_VARS[SENTRY_AUTH_TOKEN]:-}" ]; then
prompt_secret "SENTRY_ORG" "Sentry org slug"
prompt_secret "SENTRY_CHANNEL_ID" "Slack channel ID for Sentry alerts" "" "" "C"
fi

prompt_secret "KERNEL_API_KEY" \
"Kernel cloud browser API key" \
"https://kernel.computer"

# ── Auto-set values ──────────────────────────────────────────────────────────

# These are set automatically based on the system state
ENV_VARS[BAUDBOT_AGENT_USER]="baudbot_agent"

if id baudbot_agent &>/dev/null; then
ENV_VARS[BAUDBOT_AGENT_HOME]=$(getent passwd baudbot_agent | cut -d: -f6)
else
ENV_VARS[BAUDBOT_AGENT_HOME]="/home/baudbot_agent"
fi

# Source dir: resolve from this script's location, or keep existing
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd || echo "")"
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/setup.sh" ]; then
ENV_VARS[BAUDBOT_SOURCE_DIR]="$SCRIPT_DIR"
elif [ -n "${EXISTING[BAUDBOT_SOURCE_DIR]:-}" ]; then
ENV_VARS[BAUDBOT_SOURCE_DIR]="${EXISTING[BAUDBOT_SOURCE_DIR]}"
fi

# ── Write config ─────────────────────────────────────────────────────────────

ENV_CONTENT="# Baudbot configuration
# Generated by baudbot config on $(date -Iseconds)
# Re-run: baudbot config
# Deploy: baudbot deploy
"

ordered_keys=(
ANTHROPIC_API_KEY
OPENAI_API_KEY
GEMINI_API_KEY
OPENCODE_ZEN_API_KEY
GITHUB_TOKEN
SLACK_BOT_TOKEN
SLACK_APP_TOKEN
SLACK_ALLOWED_USERS
AGENTMAIL_API_KEY
BAUDBOT_EMAIL
BAUDBOT_SECRET
BAUDBOT_ALLOWED_EMAILS
SENTRY_AUTH_TOKEN
SENTRY_ORG
SENTRY_CHANNEL_ID
KERNEL_API_KEY
BAUDBOT_AGENT_USER
BAUDBOT_AGENT_HOME
BAUDBOT_SOURCE_DIR
)

for key in "${ordered_keys[@]}"; do
if [ -n "${ENV_VARS[$key]:-}" ]; then
ENV_CONTENT+="${key}=${ENV_VARS[$key]}"$'\n'
fi
done

echo "$ENV_CONTENT" > "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
# Ensure owned by admin user
if [ "$(id -u)" -eq 0 ]; then
chown "$CONFIG_USER:$CONFIG_USER" "$CONFIG_FILE"
fi

VAR_COUNT=$(grep -c '=' "$CONFIG_FILE")
info "Wrote $VAR_COUNT variables to $CONFIG_FILE"
echo ""
echo -e "Next: ${BOLD}sudo baudbot deploy${RESET} to push config to the agent"
echo ""
28 changes: 28 additions & 0 deletions bin/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,34 @@ if [ -f "$STAGE_DIR/.env.schema" ]; then
fi
fi

# ── Admin config (secrets) ────────────────────────────────────────────────────

echo "Deploying config..."

# Determine who invoked this (the admin user)
DEPLOY_USER="${SUDO_USER:-$(whoami)}"
DEPLOY_HOME=$(getent passwd "$DEPLOY_USER" | cut -d: -f6 2>/dev/null || echo "")
ADMIN_CONFIG="$DEPLOY_HOME/.baudbot/.env"

if [ -f "$ADMIN_CONFIG" ]; then
if [ "$DRY_RUN" -eq 0 ]; then
as_agent bash -c "mkdir -p '$BAUDBOT_HOME/.config'"
cp "$ADMIN_CONFIG" "$BAUDBOT_HOME/.config/.env"
chown "$AGENT_USER:$AGENT_USER" "$BAUDBOT_HOME/.config/.env"
chmod 600 "$BAUDBOT_HOME/.config/.env"
log "✓ .env → ~/.config/.env (600)"
else
log "would copy: $ADMIN_CONFIG → ~/.config/.env"
fi
else
# Fallback: check if agent already has a .env (written directly by old install.sh)
if as_agent test -f "$BAUDBOT_HOME/.config/.env" 2>/dev/null; then
log "- .env: using existing agent config (no ~/.baudbot/.env found)"
else
log "⚠ no config found — run: baudbot config"
fi
fi

# ── Version stamp + integrity manifest ────────────────────────────────────────

echo "Stamping version..."
Expand Down
16 changes: 15 additions & 1 deletion bin/doctor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,21 @@ fi
# ── Secrets ──────────────────────────────────────────────────────────────────

echo ""
echo "Secrets:"
echo "Admin config:"

# Check for admin config dir
ADMIN_USER="${SUDO_USER:-$(whoami)}"
ADMIN_HOME=$(getent passwd "$ADMIN_USER" | cut -d: -f6 2>/dev/null || echo "")
ADMIN_CONFIG="$ADMIN_HOME/.baudbot/.env"

if [ -n "$ADMIN_HOME" ] && [ -f "$ADMIN_CONFIG" ]; then
pass "admin config exists ($ADMIN_CONFIG)"
else
warn "admin config not found at $ADMIN_CONFIG (run: baudbot config)"
fi

echo ""
echo "Agent secrets:"

ENV_FILE="$BAUDBOT_HOME/.config/.env"
if [ -f "$ENV_FILE" ]; then
Expand Down
Loading
Loading