mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
fix(cli): bound docs search API response reads with committed test (#98188)
This commit is contained in:
@@ -94,4 +94,33 @@ describe("docsSearchCommand", () => {
|
||||
expect(runtime.exit).not.toHaveBeenCalled();
|
||||
expect(runtime.log).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects oversized docs search responses", async () => {
|
||||
const ONE_MIB = 1024 * 1024;
|
||||
const cancel = vi.fn();
|
||||
const stream = new ReadableStream<Uint8Array>({
|
||||
cancel,
|
||||
start(controller) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
controller.enqueue(new Uint8Array(ONE_MIB));
|
||||
}
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
fetchMock.mockResolvedValueOnce(
|
||||
new Response(stream, {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
);
|
||||
const runtime = makeRuntime();
|
||||
|
||||
await docsSearchCommand(["oversized"], runtime);
|
||||
|
||||
expect(runtime.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Docs search response exceeds"),
|
||||
);
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
expect(cancel).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Implements docs link/search output for `openclaw docs`.
|
||||
import { readResponseWithLimit } from "@openclaw/media-core/read-response-with-limit";
|
||||
import { formatDocsLink } from "../../packages/terminal-core/src/links.js";
|
||||
import { isRich, theme } from "../../packages/terminal-core/src/theme.js";
|
||||
import { formatCliCommand } from "../cli/command-format.js";
|
||||
@@ -6,6 +7,7 @@ import type { RuntimeEnv } from "../runtime.js";
|
||||
|
||||
const SEARCH_API = "https://docs.openclaw.ai/api/search";
|
||||
const SEARCH_TIMEOUT_MS = 30_000;
|
||||
const DOCS_SEARCH_RESPONSE_MAX_BYTES = 8 * 1024 * 1024;
|
||||
|
||||
type DocResult = {
|
||||
title: string;
|
||||
@@ -75,7 +77,10 @@ async function fetchDocsSearch(query: string): Promise<DocResult[]> {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
const payload = (await response.json()) as DocsSearchResponse;
|
||||
const bytes = await readResponseWithLimit(response, DOCS_SEARCH_RESPONSE_MAX_BYTES, {
|
||||
onOverflow: ({ maxBytes }) => new Error(`Docs search response exceeds ${maxBytes} bytes`),
|
||||
});
|
||||
const payload = JSON.parse(new TextDecoder().decode(bytes)) as DocsSearchResponse;
|
||||
return parseDocsSearchResults(payload.results);
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
|
||||
Reference in New Issue
Block a user