modelbeast/scripts/serve.sh
MODELBEAST 514ec6cdcc Security hardening from adversarial review (5-agent workflow)
Fixed confirmed findings before public exposure:
HIGH:
- upload filename path traversal → store.safe_name() strips to basename
- login rate-limit XFF bypass → key on request.client.host + per-username bucket;
  auth.check_login() burns bcrypt time on unknown users (no enumeration)
- cross-user read access → per-user isolation: guests see/use/download/delete only
  their own assets & jobs (owner sees all); WS job events scoped per-user
MEDIUM:
- unbounded upload read → bounded chunked streaming to the 1GB cap
- asset member path check → Path.is_relative_to boundary + ownership gate
- WS token-in-query-string leak → session-cookie-only WS auth
LOW:
- retry_job bypassed the per-user job cap → cap now checked on retry
- wholesale API-key injection → env_for_operator injects a paid key only to
  operators that declare it (guest local jobs never receive fal/OpenRouter keys)
- session revocation → users.session_epoch, bumped on password change
- int() 500s → 400; net-lane defense-in-depth (guests blocked by requires_env AND
  resources==net, so a mis-tagged paid op is still blocked)
+ public /api/health for serve.sh & proxy; docs/VPS.md; mb MB_TOKEN bearer auth

tests/smoke.sh: 34 checks passing incl. all new hardening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 12:25:13 +10:00

17 lines
922 B
Bash
Executable File

#!/usr/bin/env bash
# Start (or restart) the MODELBEAST server headless on port 8777.
# NOTE: exactly ONE uvicorn worker (no --workers). The in-process asyncio job
# queue + the single shared SQLite connection require a single worker; adding
# workers would fork the queue and corrupt job state. Do not "optimize" this.
# On first run the owner account + one-time password print to data/server.log.
set -euo pipefail
cd "$(dirname "$0")/.."
lsof -ti:8777 | xargs kill 2>/dev/null || true
sleep 1
nohup /opt/homebrew/bin/uv run uvicorn server.main:app --host 0.0.0.0 --port 8777 \
> data/server.log 2>&1 &
sleep 2
curl -sf -o /dev/null http://localhost:8777/api/health \
&& echo "MODELBEAST up: http://$( /Applications/Tailscale.app/Contents/MacOS/Tailscale ip -4 2>/dev/null || echo localhost):8777 (log: data/server.log)" \
|| { echo "FAILED to start — tail data/server.log:"; tail -20 data/server.log; exit 1; }