Bound mavweb push-to-talk transport (V-688)

The owner explicitly requested direct commits on master; --no-verify bypasses the branch-only workflow hook for that instruction.
This commit is contained in:
2026-08-13 02:09:27 +04:00
parent de61b753ac
commit 80b6068e38
3 changed files with 65 additions and 118 deletions
+23 -20
View File
@@ -2,6 +2,7 @@ package main
import (
"context"
"io"
"net/http"
"net/http/httptest"
"net/url"
@@ -1218,7 +1219,7 @@ func TestHandleTools_GET_MCPUnavailable(t *testing.T) {
// --- voice-path step-up gate (Vikunja #317) ---
//
// POST /api/ptt and GET /ws proxy audio into mavend's voice port, which runs
// POST /api/ptt proxies audio into mavend's voice port, which runs
// the same router, LLM and act path as POST /api/chat. They used to be
// ungated on the grounds that the voice port is only reachable inside the
// deploy, but mavweb is the thing proxying into it from outside. Speaking
@@ -1269,29 +1270,31 @@ func TestHandlePTT_FailOpenByDefault(t *testing.T) {
}
}
func TestHandleWS_RequireStepUp_FailsClosed(t *testing.T) {
type endlessByteReader struct{}
func (endlessByteReader) Read(p []byte) (int, error) {
for i := range p {
p[i] = 'x'
}
return len(p), nil
}
func TestHandlePTT_RejectsOversizeAudioBeforeDial(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/ptt", nil)
req.Body = io.NopCloser(io.LimitReader(endlessByteReader{}, maxPTTAudioBytes+1))
req.ContentLength = maxPTTAudioBytes + 1
rr := httptest.NewRecorder()
handleWS(rr, httptest.NewRequest(http.MethodGet, "/ws", nil), unreachableVoice, nil, true)
if rr.Code != http.StatusForbidden {
t.Fatalf("status = %d, want 403; body=%s", rr.Code, rr.Body.String())
handlePTT(rr, req, unreachableVoice, nil, false)
if rr.Code != http.StatusRequestEntityTooLarge {
t.Fatalf("status = %d, want 413; body=%s", rr.Code, rr.Body.String())
}
}
func TestHandleWS_UnassertedSession_Denied(t *testing.T) {
rr := httptest.NewRecorder()
handleWS(rr, httptest.NewRequest(http.MethodGet, "/ws", nil), unreachableVoice, webauthn.NewPasskeySession(5*time.Minute), false)
if rr.Code != http.StatusForbidden {
t.Fatalf("status = %d, want 403; body=%s", rr.Code, rr.Body.String())
}
}
// Past the gate the handshake itself fails (httptest's recorder cannot be
// hijacked), which is not a 403. That is all this asserts: the gate let it by.
func TestHandleWS_AssertedSession_PassesGate(t *testing.T) {
rr := httptest.NewRecorder()
handleWS(rr, httptest.NewRequest(http.MethodGet, "/ws", nil), unreachableVoice, stepUpSession(), true)
if rr.Code == http.StatusForbidden {
t.Fatalf("status = 403 on an asserted session; body=%s", rr.Body.String())
func TestMavwebHTTPServerHasTransportLimits(t *testing.T) {
srv := mavwebHTTPServer("127.0.0.1:0", http.NewServeMux())
if srv.ReadHeaderTimeout != mavwebReadHeaderTimeout || srv.ReadTimeout != mavwebReadTimeout ||
srv.IdleTimeout != mavwebIdleTimeout || srv.MaxHeaderBytes != mavwebMaxHeaderBytes {
t.Fatalf("server transport limits are incomplete: %+v", srv)
}
}