Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .c8rc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"all": false,
"include": [
"slack-bridge/security.mjs",
"gateway-bridge/security.mjs",
"bin/scan-extensions.mjs"
],
"exclude": [
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
*.pem
node_modules/
# Gateway bridge
gateway-bridge/node_modules/
gateway-bridge/.env
# Legacy compat path (symlink)
slack-bridge/node_modules/
slack-bridge/.env
.pi/
Expand Down
7 changes: 4 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Baudbot is hardened infrastructure for running always-on AI agents.
Use this file for **repo-wide** guidance. For directory-specific rules, use the nearest nested `AGENTS.md`:
- [`bin/AGENTS.md`](bin/AGENTS.md)
- [`pi/extensions/AGENTS.md`](pi/extensions/AGENTS.md)
- [`slack-bridge/AGENTS.md`](slack-bridge/AGENTS.md)
- [`gateway-bridge/AGENTS.md`](gateway-bridge/AGENTS.md)

## How Baudbot works

Expand All @@ -16,7 +16,7 @@ Baudbot is a persistent, team-facing coding agent system. It connects to Slack,
```text
Slack
Gateway bridge (slack-bridge dir; broker pull-mode or legacy Socket Mode)
Gateway bridge (gateway-bridge dir; broker pull-mode or legacy Socket Mode)
control-agent (always-on, manages todo/routing/Slack threads)
├── dev-agent(s) — ephemeral coding workers in isolated worktrees
Expand Down Expand Up @@ -47,7 +47,8 @@ There are two startup phases with distinct ownership:
- `dev-agent/` — coding worker persona
- `sentry-agent/` — incident triage persona
- `pi/settings.json` — pi agent settings
- `slack-bridge/` — Gateway bridge runtime + security module
- `gateway-bridge/` — Gateway bridge runtime + security module
- `slack-bridge` → symlink to `gateway-bridge/` (legacy compatibility shim)
- `docs/` — architecture/operations/security documentation
- `test/` — vitest wrappers for shell scripts, integration, and legacy Node tests
- `hooks/` — git hooks (security-critical `pre-commit` protecting admin-managed files)
Expand Down
2 changes: 1 addition & 1 deletion bin/ci/setup-arch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ echo "=== Installing test dependencies ==="
export PATH="/home/baudbot_agent/opt/node/bin:$PATH"
cd /home/baudbot_admin/baudbot
npm install --ignore-scripts 2>&1 | tail -1
cd slack-bridge && npm install 2>&1 | tail -1
cd gateway-bridge && npm install 2>&1 | tail -1
cd ..

echo "=== Running tests ==="
Expand Down
2 changes: 1 addition & 1 deletion bin/ci/setup-ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ echo "=== Installing test dependencies ==="
export PATH="/home/baudbot_agent/opt/node/bin:$PATH"
cd /home/baudbot_admin/baudbot
npm install --ignore-scripts 2>&1 | tail -1
cd slack-bridge && npm install 2>&1 | tail -1
cd gateway-bridge && npm install 2>&1 | tail -1
cd ..

echo "=== Running tests ==="
Expand Down
5 changes: 3 additions & 2 deletions bin/ci/smoke-agent-runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ readonly AGENT_USER="baudbot_agent"
readonly AGENT_HOME="/home/${AGENT_USER}"
readonly CONTROL_DIR="${AGENT_HOME}/.pi/session-control"
readonly CONTROL_ALIAS="${CONTROL_DIR}/control-agent.alias"
readonly BRIDGE_STATUS_FILE="${AGENT_HOME}/.pi/agent/slack-bridge-supervisor.json"
readonly BRIDGE_STATUS_FILE="${AGENT_HOME}/.pi/agent/gateway-bridge-supervisor.json"
readonly BRIDGE_STATUS_FILE_LEGACY="${AGENT_HOME}/.pi/agent/slack-bridge-supervisor.json"
readonly START_TIMEOUT_SECONDS=60
readonly STABILIZE_SECONDS=20

Expand Down Expand Up @@ -143,7 +144,7 @@ main() {
# start.sh. In CI the agent doesn't run long enough for startup-pi.sh
# to execute, so the status file may not exist. Log but don't fail.
log "checking bridge supervisor status file"
if [[ -f "$BRIDGE_STATUS_FILE" ]]; then
if [[ -f "$BRIDGE_STATUS_FILE" ]] || [[ -f "$BRIDGE_STATUS_FILE_LEGACY" ]]; then
log "bridge supervisor status file exists"
else
log "bridge supervisor status file not found (expected — bridge starts inside agent)"
Expand Down
10 changes: 5 additions & 5 deletions bin/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,12 @@ deploy_runtime_asset_entry() {

bb_manifest_for_each RUNTIME_ASSET_MANIFEST deploy_runtime_asset_entry

# Clean up legacy bridge runtime path; bridge now runs from /opt release only.
# Clean up legacy bridge runtime paths; bridge now runs from /opt release only.
if [ "$DRY_RUN" -eq 0 ]; then
as_agent bash -c "rm -rf '$BAUDBOT_HOME/runtime/slack-bridge'"
log "✓ removed legacy runtime/slack-bridge"
as_agent bash -c "rm -rf '$BAUDBOT_HOME/runtime/gateway-bridge' '$BAUDBOT_HOME/runtime/slack-bridge'"
log "✓ removed legacy runtime/gateway-bridge and runtime/slack-bridge"
else
log "would remove: runtime/slack-bridge (legacy path)"
log "would remove: runtime/gateway-bridge and runtime/slack-bridge (legacy paths)"
fi

# ── Memory Seeds ─────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -441,7 +441,7 @@ VEOF
echo ' \"source_sha\": \"$GIT_SHA\",'
echo ' \"files\": {'
first=1
for dir in '$BAUDBOT_HOME/.pi/agent/extensions' '$BAUDBOT_HOME/.pi/agent/skills' '/opt/baudbot/current/slack-bridge' '$BAUDBOT_HOME/runtime/bin'; do
for dir in '$BAUDBOT_HOME/.pi/agent/extensions' '$BAUDBOT_HOME/.pi/agent/skills' '/opt/baudbot/current/gateway-bridge' '$BAUDBOT_HOME/runtime/bin'; do
if [ -d \"\$dir\" ]; then
while IFS= read -r f; do
hash=\$(sha256sum \"\$f\" | cut -d' ' -f1)
Expand Down
7 changes: 5 additions & 2 deletions bin/doctor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,17 @@ else
fi
fi

BRIDGE_DIR="$BAUDBOT_CURRENT_LINK/slack-bridge"
BRIDGE_DIR="$BAUDBOT_CURRENT_LINK/gateway-bridge"
BRIDGE_DIR_LEGACY="$BAUDBOT_CURRENT_LINK/slack-bridge"
if [ -d "$BRIDGE_DIR" ] && [ -f "$BRIDGE_DIR/bridge.mjs" ]; then
pass "gateway bridge deployed ($BRIDGE_DIR)"
elif [ -d "$BRIDGE_DIR_LEGACY" ] && [ -f "$BRIDGE_DIR_LEGACY/bridge.mjs" ]; then
pass "gateway bridge deployed via legacy path ($BRIDGE_DIR_LEGACY)"
else
if [ "$IS_ROOT" -ne 1 ] && { [ -d "$BAUDBOT_CURRENT_LINK" ] || [ -e "$BAUDBOT_CURRENT_LINK" ]; }; then
warn "cannot verify gateway bridge files as non-root (run: sudo baudbot doctor)"
else
fail "gateway bridge not deployed (expected: $BRIDGE_DIR; run: sudo baudbot update)"
fail "gateway bridge not deployed (expected: $BRIDGE_DIR or $BRIDGE_DIR_LEGACY; run: sudo baudbot update)"
fi
fi

Expand Down
9 changes: 7 additions & 2 deletions bin/lib/baudbot-runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,20 @@ PY

print_bridge_supervisor_status() {
local agent_user="${BAUDBOT_AGENT_USER:-baudbot_agent}"
local status_file="/home/$agent_user/.pi/agent/slack-bridge-supervisor.json"
local status_file="/home/$agent_user/.pi/agent/gateway-bridge-supervisor.json"
local legacy_status_file="/home/$agent_user/.pi/agent/slack-bridge-supervisor.json"
local summary=""
local mode=""
local state=""
local failures=""
local threshold=""

if [ ! -r "$status_file" ]; then
return 0
if [ -r "$legacy_status_file" ]; then
status_file="$legacy_status_file"
else
return 0
fi
fi

summary="$(python3 - "$status_file" <<'PY'
Expand Down
27 changes: 22 additions & 5 deletions bin/security-audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,17 @@ else
ok "~/.pi/agent/skills/ is a real directory"
fi

BRIDGE_DIR="$BAUDBOT_CURRENT_LINK/slack-bridge"
BRIDGE_DIR="$BAUDBOT_CURRENT_LINK/gateway-bridge"
BRIDGE_DIR_LEGACY="$BAUDBOT_CURRENT_LINK/slack-bridge"
# shellcheck disable=SC2088
if [ -d "$BRIDGE_DIR" ]; then
ok "Release bridge directory exists ($BRIDGE_DIR)"
elif [ -d "$BRIDGE_DIR_LEGACY" ]; then
ok "Release bridge directory exists via legacy path ($BRIDGE_DIR_LEGACY)"
BRIDGE_DIR="$BRIDGE_DIR_LEGACY"
else
finding "WARN" "release bridge directory not found" \
"Expected: $BRIDGE_DIR (run: sudo baudbot update)"
"Expected: $BRIDGE_DIR or $BRIDGE_DIR_LEGACY (run: sudo baudbot update)"
fi

# Check version stamp exists
Expand All @@ -252,21 +256,34 @@ if [ -f "$MANIFEST_FILE" ]; then
for critical_file in \
".pi/agent/extensions/tool-guard.ts" \
".pi/agent/extensions/tool-guard.test.mjs" \
"release/slack-bridge/security.mjs" \
"release/slack-bridge/security.test.mjs"; do
"release/gateway-bridge/security.mjs" \
"release/gateway-bridge/security.test.mjs"; do

if [[ "$critical_file" == release/* ]]; then
full_path="$BAUDBOT_CURRENT_LINK/${critical_file#release/}"
else
full_path="$BAUDBOT_HOME/$critical_file"
fi

expected_hash=$(grep "\"$critical_file\"" "$MANIFEST_FILE" 2>/dev/null | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")

# Legacy compatibility: manifests from older releases used release/slack-bridge/* keys.
if [[ "$critical_file" == "release/gateway-bridge/security.mjs" ]] && [ -z "$expected_hash" ]; then
critical_file="release/slack-bridge/security.mjs"
full_path="$BAUDBOT_CURRENT_LINK/slack-bridge/security.mjs"
expected_hash=$(grep "\"$critical_file\"" "$MANIFEST_FILE" 2>/dev/null | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")
elif [[ "$critical_file" == "release/gateway-bridge/security.test.mjs" ]] && [ -z "$expected_hash" ]; then
critical_file="release/slack-bridge/security.test.mjs"
full_path="$BAUDBOT_CURRENT_LINK/slack-bridge/security.test.mjs"
expected_hash=$(grep "\"$critical_file\"" "$MANIFEST_FILE" 2>/dev/null | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")
fi

if [ ! -f "$full_path" ]; then
finding "WARN" "Missing critical file: $critical_file" "Run deploy.sh"
missing=$((missing + 1))
continue
fi

expected_hash=$(grep "\"$critical_file\"" "$MANIFEST_FILE" 2>/dev/null | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")
if [ -z "$expected_hash" ]; then
finding "WARN" "$critical_file not in manifest" "Run deploy.sh to regenerate"
continue
Expand Down
10 changes: 5 additions & 5 deletions bin/security-audit.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ trap cleanup EXIT
setup_base() {
local home="$1"
rm -rf "$home"
mkdir -p "$home/.config" "$home/.ssh" "$home/.pi" "$home/opt/baudbot/current/slack-bridge" "$home/baudbot/.git"
mkdir -p "$home/.config" "$home/.ssh" "$home/.pi" "$home/opt/baudbot/current/gateway-bridge" "$home/baudbot/.git"

# Secrets file
echo "SLACK_BOT_TOKEN=xoxb-test" > "$home/.config/.env"
Expand All @@ -38,8 +38,8 @@ setup_base() {
echo -e "[user]\n\tname = test\n\temail = test@test.com" > "$home/.gitconfig"

# Bridge security module
echo "// security" > "$home/opt/baudbot/current/slack-bridge/security.mjs"
echo "// tests" > "$home/opt/baudbot/current/slack-bridge/security.test.mjs"
echo "// security" > "$home/opt/baudbot/current/gateway-bridge/security.mjs"
echo "// tests" > "$home/opt/baudbot/current/gateway-bridge/security.test.mjs"

# Audit log (fallback location)
mkdir -p "$home/logs"
Expand Down Expand Up @@ -183,7 +183,7 @@ echo ""
echo "Test: missing bridge security module"
HOME8="$TMPDIR/no-bridge-sec"
setup_base "$HOME8"
rm -f "$HOME8/opt/baudbot/current/slack-bridge/security.mjs"
rm -f "$HOME8/opt/baudbot/current/gateway-bridge/security.mjs"

output=$(run_audit "$HOME8")
expect_contains "reports missing security module" "$output" "Bridge security module not found"
Expand All @@ -195,7 +195,7 @@ echo ""
echo "Test: missing bridge tests"
HOME9="$TMPDIR/no-bridge-tests"
setup_base "$HOME9"
rm -f "$HOME9/opt/baudbot/current/slack-bridge/security.test.mjs"
rm -f "$HOME9/opt/baudbot/current/gateway-bridge/security.test.mjs"

output=$(run_audit "$HOME9")
expect_contains "reports missing tests" "$output" "No tests for bridge security"
Expand Down
4 changes: 2 additions & 2 deletions bin/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ JS_TEST_FILES=(
pi/extensions/tool-guard.test.mjs
pi/extensions/heartbeat.test.mjs
pi/extensions/memory.test.mjs
slack-bridge/security.test.mjs
slack-bridge/env-aliases.test.mjs
gateway-bridge/security.test.mjs
gateway-bridge/env-aliases.test.mjs
bin/scan-extensions.test.mjs
bin/broker-register.test.mjs
)
Expand Down
10 changes: 7 additions & 3 deletions bin/update-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,18 @@ EOF

install_release_bridge_dependencies() {
local release_dir="$1"
local bridge_dir="$release_dir/slack-bridge"
local bridge_dir="$release_dir/gateway-bridge"

if [ ! -d "$bridge_dir" ] || [ ! -f "$bridge_dir/package.json" ]; then
log "slack-bridge package.json missing; skipping bridge dependency install"
bridge_dir="$release_dir/slack-bridge"
fi

if [ ! -d "$bridge_dir" ] || [ ! -f "$bridge_dir/package.json" ]; then
log "gateway-bridge/slack-bridge package.json missing; skipping bridge dependency install"
return 0
fi

log "installing production Gateway bridge dependencies in release"
log "installing production Gateway bridge dependencies in release ($bridge_dir)"
rm -rf "$bridge_dir/node_modules"

# Resolve npm via the embedded Node runtime. update-release runs as root
Expand Down
8 changes: 4 additions & 4 deletions bin/verify-manifest.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ make_manifest() {

local ext_file="$home_dir/.pi/agent/extensions/test.ts"
local runtime_file="$home_dir/runtime/bin/helper.sh"
local bridge_file="$release_dir/slack-bridge/bridge.mjs"
local bridge_file="$release_dir/gateway-bridge/bridge.mjs"
local log_file="$home_dir/.pi/agent/logs/bridge.log"

cat >"$manifest_file" <<EOF
Expand All @@ -52,7 +52,7 @@ make_manifest() {
"files": {
".pi/agent/extensions/test.ts": "$(hash_file "$ext_file")",
"runtime/bin/helper.sh": "$(hash_file "$runtime_file")",
"release/slack-bridge/bridge.mjs": "$(hash_file "$bridge_file")",
"release/gateway-bridge/bridge.mjs": "$(hash_file "$bridge_file")",
".pi/agent/logs/bridge.log": "$(hash_file "$log_file")"
}
}
Expand All @@ -72,11 +72,11 @@ echo ""

HOME1="$TMPDIR/home1"
RELEASE1="$TMPDIR/release1"
mkdir -p "$HOME1/.pi/agent/extensions" "$HOME1/runtime/bin" "$HOME1/.pi/agent/logs" "$RELEASE1/slack-bridge"
mkdir -p "$HOME1/.pi/agent/extensions" "$HOME1/runtime/bin" "$HOME1/.pi/agent/logs" "$RELEASE1/gateway-bridge"

printf 'console.log("ok");\n' > "$HOME1/.pi/agent/extensions/test.ts"
printf '#!/bin/bash\necho helper\n' > "$HOME1/runtime/bin/helper.sh"
printf 'export const bridge = true;\n' > "$RELEASE1/slack-bridge/bridge.mjs"
printf 'export const bridge = true;\n' > "$RELEASE1/gateway-bridge/bridge.mjs"
printf 'mutable log\n' > "$HOME1/.pi/agent/logs/bridge.log"

MANIFEST1="$HOME1/.pi/agent/baudbot-manifest.json"
Expand Down
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"bin/**/*.mjs",
"pi/extensions/**/*.ts",
"pi/extensions/**/*.mjs",
"slack-bridge/**/*.mjs"
"gateway-bridge/**/*.mjs"
]
},
"linter": {
Expand Down
4 changes: 2 additions & 2 deletions slack-bridge/AGENTS.md → gateway-bridge/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# slack-bridge/ (Gateway bridge) — Agent Guidelines
# gateway-bridge/ — Agent Guidelines

Scope: Gateway bridge runtime and security modules under `slack-bridge/`.
Scope: Gateway bridge runtime and security modules under `gateway-bridge/` (legacy shim: `slack-bridge/`).

## Focus areas

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion slack-bridge/package.json → gateway-bridge/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "slack-bridge",
"name": "gateway-bridge",
"version": "1.0.0",
"description": "Gateway bridge runtimes (Socket Mode + broker pull mode)",
"main": "bridge.mjs",
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
# The agent can freely modify:
# - pi/skills/ (operational knowledge)
# - pi/extensions/ (non-security extensions like zen-provider.ts, auto-name.ts, etc.)
# - slack-bridge/bridge.mjs (non-security bridge code)
# - gateway-bridge/bridge.mjs (non-security bridge code)
# - README.md, .gitignore, etc.
#
# The agent CANNOT modify (blocked by this hook):
# - bin/ (security scripts: tool deny lists, firewall, audit, hardening)
# - pi/extensions/tool-guard.ts (and its tests)
# - slack-bridge/security.mjs (and its tests)
# - gateway-bridge/security.mjs (and its tests)
# - SECURITY.md
# - setup.sh
# - start.sh
Expand All @@ -34,6 +34,9 @@ PROTECTED_PREFIXES=(
PROTECTED_FILES=(
"pi/extensions/tool-guard.ts"
"pi/extensions/tool-guard.test.mjs"
"gateway-bridge/security.mjs"
"gateway-bridge/security.test.mjs"
# Legacy compat path (symlink)
"slack-bridge/security.mjs"
"slack-bridge/security.test.mjs"
)
Expand Down
Loading