diff --git a/scripts/e2e/lib/openai-chat-tools/client.mjs b/scripts/e2e/lib/openai-chat-tools/client.mjs index a97600ffbdd9..d06cbf44454e 100644 --- a/scripts/e2e/lib/openai-chat-tools/client.mjs +++ b/scripts/e2e/lib/openai-chat-tools/client.mjs @@ -51,7 +51,7 @@ async function readBoundedResponseText(response, byteLimit, timeoutPromise) { const contentLength = response.headers?.get?.("content-length"); if (contentLength && /^\d+$/u.test(contentLength)) { const parsedContentLength = Number(contentLength); - if (Number.isSafeInteger(parsedContentLength) && parsedContentLength > byteLimit) { + if (!Number.isSafeInteger(parsedContentLength) || parsedContentLength > byteLimit) { await response.body?.cancel().catch(() => undefined); throw new Error(`chat completions response body exceeded ${byteLimit} bytes`); } diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index a7d02fbe5e79..54b7cc52f37f 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -3020,7 +3020,7 @@ export ROOT_DIR TMPDIR source "$ROOT_DIR/scripts/lib/docker-e2e-logs.sh" -output="$(run_logged_print_heartbeat plugins-run 1 bash -c 'printf "captured container log\\\\n"; /bin/sleep 2')" +output="$(run_logged_print_heartbeat plugins-run 1 bash -c 'printf "captured container log\\\\n"; /bin/sleep 4')" [[ "$output" = *"still running plugins-run ("* ]] [[ "$output" = *"log bytes captured"* ]] [[ "$output" = *"captured container log"* ]] @@ -3195,28 +3195,18 @@ output="$(run_logged_print_heartbeat plugins-run 30 bash -c 'printf "quick conta }); it("normalizes zero-padded Docker E2E log heartbeat intervals", () => { - const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-e2e-log-zero-heartbeat-")); - - try { - const rootDir = process.cwd(); - const script = ` + const rootDir = process.cwd(); + const script = ` set -euo pipefail ROOT_DIR=${shellQuote(rootDir)} -TMPDIR=${shellQuote(workDir)} -export ROOT_DIR TMPDIR +export ROOT_DIR source "$ROOT_DIR/scripts/lib/docker-e2e-logs.sh" -output="$(run_logged_print_heartbeat plugins-run 08 bash -c 'printf "captured container log\\\\n"; /bin/sleep 9')" -[[ "$output" = *"still running plugins-run (8s elapsed,"* ]] -[[ "$output" = *"log bytes captured"* ]] -[[ "$output" = *"captured container log"* ]] +[[ "$(docker_e2e_normalize_positive_int_value 'Docker E2E log heartbeat interval' 08)" = "8" ]] `; - execFileSync("bash", ["-lc", script], { encoding: "utf8" }); - } finally { - rmSync(workDir, { recursive: true, force: true }); - } + execFileSync("bash", ["-lc", script], { encoding: "utf8" }); }); it("normalizes zero-padded Docker E2E stats heartbeat intervals", () => { diff --git a/test/scripts/openai-chat-tools-client.test.ts b/test/scripts/openai-chat-tools-client.test.ts index 8b40cf7cdc59..c4874737d7b8 100644 --- a/test/scripts/openai-chat-tools-client.test.ts +++ b/test/scripts/openai-chat-tools-client.test.ts @@ -404,4 +404,27 @@ describe("scripts/e2e/lib/openai-chat-tools/client.mjs", () => { server.close(); } }); + + it("rejects unsafe declared chat completion body lengths before waiting on the stream", async () => { + const server = createServer((_request, response) => { + response.writeHead(200, { + "content-length": "9007199254740993", + "content-type": "application/json", + }); + response.flushHeaders(); + }); + const port = await listen(server); + try { + const startedAt = Date.now(); + const result = await runClient(port, { OPENCLAW_OPENAI_CHAT_TOOLS_MAX_BODY_BYTES: "64" }); + + expect(result.error).toBeUndefined(); + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("chat completions response body exceeded 64 bytes"); + expect(result.stderr).not.toContain("timed out"); + expect(Date.now() - startedAt).toBeLessThan(3_500); + } finally { + server.close(); + } + }); });