This commit is contained in:
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user