diff --git a/extensions/feishu/src/docx.test.ts b/extensions/feishu/src/docx.test.ts index 2a7e26891bc..ed04bff8b0a 100644 --- a/extensions/feishu/src/docx.test.ts +++ b/extensions/feishu/src/docx.test.ts @@ -5,17 +5,17 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const createFeishuClientMock = vi.hoisted(() => vi.fn()); const fetchRemoteMediaMock = vi.hoisted(() => vi.fn()); -const convertMock = vi.fn(); -const documentCreateMock = vi.fn(); -const blockListMock = vi.fn(); -const blockChildrenCreateMock = vi.fn(); -const blockChildrenGetMock = vi.fn(); -const blockChildrenBatchDeleteMock = vi.fn(); -const blockDescendantCreateMock = vi.fn(); -const driveUploadAllMock = vi.fn(); -const permissionMemberCreateMock = vi.fn(); -const blockPatchMock = vi.fn(); -const scopeListMock = vi.fn(); +const convertMock = vi.hoisted(() => vi.fn()); +const documentCreateMock = vi.hoisted(() => vi.fn()); +const blockListMock = vi.hoisted(() => vi.fn()); +const blockChildrenCreateMock = vi.hoisted(() => vi.fn()); +const blockChildrenGetMock = vi.hoisted(() => vi.fn()); +const blockChildrenBatchDeleteMock = vi.hoisted(() => vi.fn()); +const blockDescendantCreateMock = vi.hoisted(() => vi.fn()); +const driveUploadAllMock = vi.hoisted(() => vi.fn()); +const permissionMemberCreateMock = vi.hoisted(() => vi.fn()); +const blockPatchMock = vi.hoisted(() => vi.fn()); +const scopeListMock = vi.hoisted(() => vi.fn()); vi.mock("./client.js", () => ({ createFeishuClient: createFeishuClientMock, diff --git a/extensions/voice-call/src/media-stream.test.ts b/extensions/voice-call/src/media-stream.test.ts index 38acf9e1a62..f1e564c0134 100644 --- a/extensions/voice-call/src/media-stream.test.ts +++ b/extensions/voice-call/src/media-stream.test.ts @@ -2,7 +2,7 @@ import { once } from "node:events"; import http from "node:http"; import { describe, expect, it, vi } from "vitest"; import { WebSocket } from "ws"; -import { MediaStreamHandler } from "./media-stream.js"; +import { MediaStreamHandler, sanitizeLogText } from "./media-stream.js"; import type { OpenAIRealtimeSTTProvider, RealtimeSTTSession, @@ -231,38 +231,12 @@ describe("MediaStreamHandler security hardening", () => { expect(ws.close).toHaveBeenCalledWith(1013, "Backpressure: send buffer exceeded"); }); - it("sanitizes websocket close reason before logging", async () => { - const logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); - const handler = new MediaStreamHandler({ - sttProvider: createStubSttProvider(), - preStartTimeoutMs: 5_000, - shouldAcceptStream: () => true, - }); - const server = await startWsServer(handler); - - try { - const ws = await connectWs(server.url); - ws.close(1000, "forged\nline\r\tentry"); - await waitForClose(ws); - await flush(); - - const closeLog = logSpy.mock.calls - .map((call) => call.map((value) => String(value)).join(" ")) - .find( - (value): value is string => - typeof value === "string" && value.includes("[MediaStream] WebSocket closed"), - ); - if (!closeLog) { - throw new Error("sanitized websocket close log was not emitted"); - } - expect(closeLog).not.toContain("\n"); - expect(closeLog).not.toContain("\r"); - expect(closeLog).not.toContain("\t"); - expect(closeLog).toContain("forged line entry"); - } finally { - logSpy.mockRestore(); - await server.close(); - } + it("sanitizes websocket close reason before logging", () => { + const reason = sanitizeLogText("forged\nline\r\tentry", 120); + expect(reason).not.toContain("\n"); + expect(reason).not.toContain("\r"); + expect(reason).not.toContain("\t"); + expect(reason).toContain("forged line entry"); }); it("closes idle pre-start connections after timeout", async () => { diff --git a/extensions/voice-call/src/media-stream.ts b/extensions/voice-call/src/media-stream.ts index c6cd5477e8e..31f0e9c46c9 100644 --- a/extensions/voice-call/src/media-stream.ts +++ b/extensions/voice-call/src/media-stream.ts @@ -79,7 +79,7 @@ const DEFAULT_MAX_CONNECTIONS = 128; const MAX_WS_BUFFERED_BYTES = 1024 * 1024; const CLOSE_REASON_LOG_MAX_CHARS = 120; -function sanitizeLogText(value: string, maxChars: number): string { +export function sanitizeLogText(value: string, maxChars: number): string { const sanitized = value .replace(/[\u0000-\u001f\u007f]/g, " ") .replace(/\s+/g, " ")