maestro/scripts/upgrade.sh
oss-sync 138401ce1b
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (a67c053)
2026-06-17 01:04:08 +00:00

143 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# upgrade.sh — bring an existing (bare-metal) MAESTRO checkout safely up to the
# latest version after a `git pull`.
#
# Why this exists
# ---------------
# `scripts/server.sh restart` rebuilds the server (dist/) but NOT the UI:
# `ui/dist` is gitignored and built separately, and npm deps are never
# refreshed. So after a `git pull` that touched dependencies or the frontend, a
# plain restart can leave a stale/missing UI bundle or ABI-mismatched native
# modules. This script runs the full, correct update sequence instead:
#
# git pull (optional) -> build-all.sh (deps + server + UI) -> restart
#
# Network bind migration (2026-06-10)
# -----------------------------------
# A security fix changed the default bind from 0.0.0.0 to 127.0.0.1 (loopback
# only). If you used to reach MAESTRO from another machine on a bare-metal
# install, after upgrading you'll get ERR_CONNECTION_REFUSED until you set HOST
# explicitly. This script detects that and offers to write HOST to .env (with a
# warning that you must enable auth before exposing a non-loopback interface).
#
# Usage:
# scripts/upgrade.sh # interactive: pull, build, restart
# scripts/upgrade.sh --no-pull # skip `git pull` (build + restart only)
# scripts/upgrade.sh --no-restart # build only, leave the server as-is
# scripts/upgrade.sh --yes # non-interactive (CI); never edits .env
# scripts/upgrade.sh --help
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env"
DO_PULL=1
DO_RESTART=1
ASSUME_YES=0
for arg in "$@"; do
case "$arg" in
--no-pull) DO_PULL=0 ;;
--no-restart) DO_RESTART=0 ;;
--yes|-y) ASSUME_YES=1 ;;
-h|--help)
sed -n '2,29p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
echo "upgrade.sh: unknown option '$arg' (try --help)" >&2
exit 2
;;
esac
done
cd "$PROJECT_DIR"
say() { printf '\n\033[1;36m==>\033[0m %s\n' "$1"; }
warn() { printf '\033[1;33mWARN:\033[0m %s\n' "$1" >&2; }
# ---------------------------------------------------------------------------
# 1. git pull (fast-forward only; never silently merge or rewrite local work)
# ---------------------------------------------------------------------------
if [[ "$DO_PULL" -eq 1 ]]; then
if [[ -n "$(git -C "$PROJECT_DIR" status --porcelain 2>/dev/null)" ]]; then
warn "working tree has local changes — skipping 'git pull'. Commit/stash and re-run, or use --no-pull."
else
say "Pulling latest changes (git pull --ff-only)"
if ! git -C "$PROJECT_DIR" pull --ff-only; then
warn "git pull --ff-only failed (diverged or offline). Continuing with the current checkout."
fi
fi
else
say "Skipping git pull (--no-pull)"
fi
# ---------------------------------------------------------------------------
# 2. Full rebuild: refresh deps + build server dist/ AND ui/dist/ + prebake.
# This is the step a plain `server.sh restart` skips for the UI.
# ---------------------------------------------------------------------------
say "Rebuilding (deps + server + UI) via scripts/build-all.sh"
"$SCRIPT_DIR/build-all.sh"
# ---------------------------------------------------------------------------
# 3. Network bind migration check (0.0.0.0 -> 127.0.0.1 default since 2026-06-10)
# ---------------------------------------------------------------------------
host_in_env=""
if [[ -f "$ENV_FILE" ]]; then
# First non-comment HOST=... line, value with surrounding quotes stripped.
host_in_env="$(grep -E '^[[:space:]]*(export[[:space:]]+)?HOST=' "$ENV_FILE" \
| grep -vE '^[[:space:]]*#' \
| head -1 | sed -E 's/^[[:space:]]*(export[[:space:]]+)?HOST=//; s/^["'\'']//; s/["'\'']$//')"
fi
say "Checking network bind"
if [[ -n "${HOST:-}" ]]; then
echo " HOST is set in the environment ($HOST) — bind is explicit, nothing to migrate."
elif [[ -n "$host_in_env" ]]; then
echo " HOST=$host_in_env found in .env — bind is explicit, nothing to migrate."
else
cat <<'EOF'
HOST is not set, so the server now binds 127.0.0.1 (loopback only).
Since 2026-06-10 the default changed from 0.0.0.0 for security: the agent
API includes a Bash tool, so an auth-less instance on the LAN is effectively
unauthenticated remote code execution.
If you ONLY open MAESTRO from this same machine (http://localhost:9876),
no action is needed.
If you reach it from ANOTHER machine, that is why you now get
ERR_CONNECTION_REFUSED. To restore remote access you must set HOST
explicitly -- and you should enable auth (auth.local or OAuth) in
config.yaml before exposing a non-loopback interface.
EOF
if [[ "$ASSUME_YES" -eq 0 ]]; then
printf '\n Append HOST=0.0.0.0 to .env now? Only do this if auth is (or will be) enabled. [y/N] '
read -r reply || reply=""
if [[ "$reply" =~ ^[Yy]$ ]]; then
{ [[ -f "$ENV_FILE" && -n "$(tail -c1 "$ENV_FILE" 2>/dev/null)" ]] && echo "" >> "$ENV_FILE"; } || true
printf '\n# Added by scripts/upgrade.sh: restore non-loopback bind (enable auth first!)\nHOST=0.0.0.0\n' >> "$ENV_FILE"
echo " Wrote HOST=0.0.0.0 to $ENV_FILE"
else
echo " Left .env unchanged. Set HOST=0.0.0.0 in .env manually when ready."
fi
else
warn "non-interactive (--yes): not editing .env. Set HOST in .env manually if you need remote access."
fi
fi
# ---------------------------------------------------------------------------
# 4. Restart
# ---------------------------------------------------------------------------
if [[ "$DO_RESTART" -eq 1 ]]; then
say "Restarting server (scripts/server.sh restart)"
"$SCRIPT_DIR/server.sh" restart
echo
echo "Done. If the server is healthy, open it at the bind address reported above"
echo "(loopback default: http://localhost:9876)."
else
say "Build complete (--no-restart). Start the server with: scripts/server.sh restart"
fi