v0.8.2: build fixes, WebUI security and correctness
Build: <fcntl.h> in tui.c, format-truncation in http_srv.c and /web. WebUI: - refuse cross-site requests (Origin must be the page itself) in the default no-token mode: any page could POST approval=yolo and a prompt - session/workspace/undo/compact/attach/model changes are 409 while a turn runs (use-after-free, messages landing in the wrong session) - ask_user returned "dismissed" at once instead of waiting - cancel and shutdown wake a turn parked on a permission or question; SIGTERM mid-turn no longer hangs or crashes - a page opened while a question is pending still gets it; Last-Event-ID resumes the stream; event seq matches the SSE id - token mode: page assets load without the token, images via cookie - --web-open works, --web-port/--web-token are validated - frontend: gate keys ignored while typing, clear-images button, reasoning no longer wiped while streaming HTTP server: auth and size cap before reading the body, strict Content-Length, NUL in url_decode, 413 on keep-alive, idle timeout, absolute-form only without a leading '/', case-insensitive Connection, header deadline, 400 for long request lines, unlink before close, poll() instead of select(), SO_EXCLUSIVEADDRUSE on Windows. Markdown sanitizer escapes quotes in attribute values. /web: passes this session's provider/model/base/effort/approval (key via the environment), keeps output off the TUI, shows the real URL and keeps CURRENT on the TUI's session. Tests: scripts/e2e_webui_ask.py, scripts/e2e_webui_http.py (run from e2e_webui.sh), sanitizer quote test.
This commit is contained in:
+26
-2
@@ -47,6 +47,19 @@ BASE="http://127.0.0.1:$PORT"
|
||||
echo " port $PORT"
|
||||
|
||||
fail() { echo "FAIL: $1"; echo "--- events"; cat "$EVENTS" 2>/dev/null | head -40; exit 1; }
|
||||
# SIGTERM must shut the server down cleanly, even mid-turn (128+ = a crash)
|
||||
stop_server() {
|
||||
kill "$1" 2>/dev/null || return 0
|
||||
n=0
|
||||
while kill -0 "$1" 2>/dev/null && [ $n -lt 200 ]; do n=$((n + 1)); sleep 0.2; done
|
||||
if kill -0 "$1" 2>/dev/null; then
|
||||
kill -9 "$1" 2>/dev/null || true
|
||||
fail "$2 hung on SIGTERM"
|
||||
fi
|
||||
st=0
|
||||
wait "$1" 2>/dev/null || st=$?
|
||||
[ "$st" -lt 128 ] || fail "$2 died with status $st on SIGTERM"
|
||||
}
|
||||
|
||||
# 1. the shell page and the state endpoint
|
||||
curl -fsS --max-time 5 "$BASE/" | grep -q "<title>CST-Agent" || fail "GET / is not the shell page"
|
||||
@@ -160,7 +173,7 @@ fi
|
||||
# 7. the interactive approval path: a fresh server in ask mode must raise a
|
||||
# permission event, and answering it must let the turn continue.
|
||||
echo "== permission round trip (-A ask)"
|
||||
kill "$SRV_PID" 2>/dev/null || true # the first server's replay is spent
|
||||
stop_server "$SRV_PID" "the first server" # its replay is spent
|
||||
rm -rf "$WORK/pw"; mkdir -p "$WORK/pw"
|
||||
P_EVENTS="$WORK/permission-events.txt"
|
||||
P_LOG="$WORK/permission-server.log" # its own log: the port parse must not
|
||||
@@ -206,7 +219,7 @@ else
|
||||
i=$((i + 1)); sleep 0.2
|
||||
done
|
||||
grep -q "event: permission_done" "$P_EVENTS" || fail "the answer was not acknowledged"
|
||||
kill "$P_PID" 2>/dev/null || true
|
||||
stop_server "$P_PID" "the ask-mode server"
|
||||
kill "$P_CURL" 2>/dev/null || true
|
||||
echo " answered request $PID_REQ with 'allow once'"
|
||||
fi
|
||||
@@ -260,4 +273,15 @@ done
|
||||
kill -0 "$T_PID" 2> /dev/null && fail "the server ignored /api/quit"
|
||||
wait "$T_PID" 2>/dev/null || true
|
||||
|
||||
# 9. ask_user waits for the answer, and the HTTP hardening checks (both
|
||||
# need a scripted model: python3)
|
||||
if command -v python3 > /dev/null; then
|
||||
echo "== ask_user round trip"
|
||||
CST_AGENT="$BIN" python3 "$ROOT/scripts/e2e_webui_ask.py" > "$WORK/ask.txt" 2>&1 ||
|
||||
{ cat "$WORK/ask.txt"; fail "the ask_user round trip"; }
|
||||
echo "== HTTP hardening"
|
||||
CST_AGENT="$BIN" python3 "$ROOT/scripts/e2e_webui_http.py" > "$WORK/http.txt" 2>&1 ||
|
||||
{ cat "$WORK/http.txt"; fail "the HTTP hardening checks"; }
|
||||
fi
|
||||
|
||||
echo "== OK: (events: $(grep -c '^event: ' "$EVENTS"))"
|
||||
|
||||
Reference in New Issue
Block a user