mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 16:30:57 +00:00
fix(diagnostics): harden capture redaction and discord metadata fetch (#71303)
This commit is contained in:
@@ -814,7 +814,7 @@ describe("diagnostics-otel service", () => {
|
||||
toolCallId: "tool-1",
|
||||
durationMs: 20,
|
||||
toolInput: "tool input",
|
||||
toolOutput: "x".repeat(6000),
|
||||
toolOutput: `${"x".repeat(4077)} Bearer ${"a".repeat(80)}`, // pragma: allowlist secret
|
||||
} as Parameters<typeof emitDiagnosticEvent>[0]);
|
||||
await flushDiagnosticEvents();
|
||||
|
||||
@@ -842,6 +842,7 @@ describe("diagnostics-otel service", () => {
|
||||
expect(String(toolAttrs?.["openclaw.content.tool_output"]).length).toBeLessThanOrEqual(
|
||||
MAX_TEST_OTEL_CONTENT_ATTRIBUTE_CHARS + OTEL_TRUNCATED_SUFFIX_MAX_CHARS,
|
||||
);
|
||||
expect(String(toolAttrs?.["openclaw.content.tool_output"])).not.toContain("a".repeat(11));
|
||||
await service.stop?.(ctx);
|
||||
});
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ function clampOtelLogText(value: string, maxChars: number): string {
|
||||
}
|
||||
|
||||
function normalizeOtelLogString(value: string, maxChars: number): string {
|
||||
return redactSensitiveText(clampOtelLogText(value, maxChars));
|
||||
return clampOtelLogText(redactSensitiveText(value), maxChars);
|
||||
}
|
||||
|
||||
function resolveContentCapturePolicy(value: unknown): OtelContentCapturePolicy {
|
||||
|
||||
@@ -14,7 +14,6 @@ import { danger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import * as undici from "undici";
|
||||
import * as ws from "ws";
|
||||
import { validateDiscordProxyUrl } from "../proxy-fetch.js";
|
||||
import { DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT } from "./gateway-handle.js";
|
||||
@@ -473,8 +472,6 @@ export function createDiscordGatewayPlugin(params: {
|
||||
runtime: RuntimeEnv;
|
||||
__testing?: {
|
||||
HttpsProxyAgentCtor?: typeof httpsProxyAgent.HttpsProxyAgent;
|
||||
ProxyAgentCtor?: typeof undici.ProxyAgent;
|
||||
undiciFetch?: typeof undici.fetch;
|
||||
webSocketCtor?: DiscordGatewayWebSocketCtor;
|
||||
registerClient?: (
|
||||
plugin: carbonGateway.GatewayPlugin,
|
||||
@@ -520,31 +517,24 @@ export function createDiscordGatewayPlugin(params: {
|
||||
validateDiscordProxyUrl(proxy);
|
||||
const HttpsProxyAgentCtor =
|
||||
params.__testing?.HttpsProxyAgentCtor ?? httpsProxyAgent.HttpsProxyAgent;
|
||||
const ProxyAgentCtor = params.__testing?.ProxyAgentCtor ?? undici.ProxyAgent;
|
||||
const wsAgent = new HttpsProxyAgentCtor<string>(proxy);
|
||||
const fetchAgent = new ProxyAgentCtor(proxy);
|
||||
|
||||
params.runtime.log?.("discord: gateway proxy enabled");
|
||||
|
||||
return createGatewayPlugin({
|
||||
options,
|
||||
fetchImpl: async (input, init) => {
|
||||
const response = (await (params.__testing?.undiciFetch ?? undici.fetch)(
|
||||
return await fetchDiscordGatewayMetadataDirect(
|
||||
input,
|
||||
init,
|
||||
)) as unknown as Response;
|
||||
captureHttpExchange({
|
||||
url: input,
|
||||
method: (init?.method as string | undefined) ?? "GET",
|
||||
requestHeaders: init?.headers as Headers | Record<string, string> | undefined,
|
||||
requestBody: (init as RequestInit & { body?: BodyInit | null })?.body ?? null,
|
||||
response,
|
||||
flowId: randomUUID(),
|
||||
meta: { subsystem: "discord-gateway-metadata" },
|
||||
});
|
||||
return response;
|
||||
debugProxySettings.enabled
|
||||
? false
|
||||
: {
|
||||
flowId: randomUUID(),
|
||||
meta: { subsystem: "discord-gateway-metadata" },
|
||||
},
|
||||
);
|
||||
},
|
||||
fetchInit: { dispatcher: fetchAgent },
|
||||
wsAgent,
|
||||
runtime: params.runtime,
|
||||
testing: params.__testing
|
||||
|
||||
@@ -18,18 +18,12 @@ const {
|
||||
globalFetchMock,
|
||||
HttpsProxyAgent,
|
||||
getLastAgent,
|
||||
restProxyAgentSpy,
|
||||
resolveDebugProxySettingsMock,
|
||||
undiciFetchMock,
|
||||
undiciProxyAgentSpy,
|
||||
resetLastAgent,
|
||||
webSocketSpy,
|
||||
wsProxyAgentSpy,
|
||||
} = vi.hoisted(() => {
|
||||
const wsProxyAgentSpy = vi.fn();
|
||||
const undiciProxyAgentSpy = vi.fn();
|
||||
const restProxyAgentSpy = vi.fn();
|
||||
const undiciFetchMock = vi.fn();
|
||||
const globalFetchMock = vi.fn();
|
||||
const baseRegisterClientSpy = vi.fn();
|
||||
const webSocketSpy = vi.fn();
|
||||
@@ -86,12 +80,9 @@ const {
|
||||
globalFetchMock,
|
||||
HttpsProxyAgent,
|
||||
getLastAgent: () => HttpsProxyAgent.lastCreated,
|
||||
restProxyAgentSpy,
|
||||
captureHttpExchangeSpy,
|
||||
captureWsEventSpy,
|
||||
resolveDebugProxySettingsMock,
|
||||
undiciFetchMock,
|
||||
undiciProxyAgentSpy,
|
||||
resetLastAgent: () => {
|
||||
HttpsProxyAgent.lastCreated = undefined;
|
||||
},
|
||||
@@ -115,15 +106,6 @@ vi.mock("https-proxy-agent", () => ({
|
||||
HttpsProxyAgent,
|
||||
}));
|
||||
|
||||
vi.mock("undici", () => ({
|
||||
ProxyAgent: function ProxyAgent(this: { proxyUrl: string }, proxyUrl: string) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
undiciProxyAgentSpy(proxyUrl);
|
||||
restProxyAgentSpy(proxyUrl);
|
||||
},
|
||||
fetch: undiciFetchMock,
|
||||
}));
|
||||
|
||||
vi.mock("ws", () => ({
|
||||
default: function MockWebSocket(url: string, options?: { agent?: unknown }) {
|
||||
webSocketSpy(url, options);
|
||||
@@ -176,12 +158,6 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
return {
|
||||
HttpsProxyAgentCtor:
|
||||
HttpsProxyAgent as unknown as typeof import("https-proxy-agent").HttpsProxyAgent,
|
||||
ProxyAgentCtor: function ProxyAgentCtor(this: { proxyUrl: string }, proxyUrl: string) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
undiciProxyAgentSpy(proxyUrl);
|
||||
restProxyAgentSpy(proxyUrl);
|
||||
} as unknown as typeof import("undici").ProxyAgent,
|
||||
undiciFetch: undiciFetchMock,
|
||||
webSocketCtor: function WebSocketCtor(url: string, options?: { agent?: unknown }) {
|
||||
webSocketSpy(url, options);
|
||||
} as unknown as new (url: string, options?: { agent?: unknown }) => import("ws").WebSocket,
|
||||
@@ -276,9 +252,6 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
vi.useRealTimers();
|
||||
baseRegisterClientSpy.mockClear();
|
||||
globalFetchMock.mockClear();
|
||||
restProxyAgentSpy.mockClear();
|
||||
undiciFetchMock.mockClear();
|
||||
undiciProxyAgentSpy.mockClear();
|
||||
wsProxyAgentSpy.mockClear();
|
||||
webSocketSpy.mockClear();
|
||||
captureHttpExchangeSpy.mockClear();
|
||||
@@ -454,7 +427,7 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
expect(runtime.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses proxy fetch for gateway metadata lookup before registering", async () => {
|
||||
it("keeps gateway metadata lookup on the guarded direct fetch when proxy is configured", async () => {
|
||||
const runtime = createRuntime();
|
||||
const plugin = createDiscordGatewayPlugin({
|
||||
discordConfig: { proxy: "http://127.0.0.1:8080" },
|
||||
@@ -462,14 +435,12 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
__testing: createProxyTestingOverrides(),
|
||||
});
|
||||
|
||||
await registerGatewayClientWithMetadata({ plugin, fetchMock: undiciFetchMock });
|
||||
await registerGatewayClientWithMetadata({ plugin, fetchMock: globalFetchMock });
|
||||
|
||||
expect(restProxyAgentSpy).toHaveBeenCalledWith("http://127.0.0.1:8080");
|
||||
expect(undiciFetchMock).toHaveBeenCalledWith(
|
||||
expect(globalFetchMock).toHaveBeenCalledWith(
|
||||
"https://discord.com/api/v10/gateway/bot",
|
||||
expect.objectContaining({
|
||||
headers: { Authorization: "Bot token-123" },
|
||||
dispatcher: expect.objectContaining({ proxyUrl: "http://127.0.0.1:8080" }),
|
||||
}),
|
||||
);
|
||||
expect(baseRegisterClientSpy).toHaveBeenCalledTimes(1);
|
||||
@@ -488,7 +459,7 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
expect(captureHttpExchangeSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("accepts IPv6 loopback proxy URLs for gateway metadata and websocket setup", async () => {
|
||||
it("accepts IPv6 loopback proxy URLs for websocket setup", async () => {
|
||||
const runtime = createRuntime();
|
||||
const plugin = createDiscordGatewayPlugin({
|
||||
discordConfig: { proxy: "http://[::1]:8080" },
|
||||
@@ -499,10 +470,9 @@ describe("createDiscordGatewayPlugin", () => {
|
||||
const createWebSocket = (plugin as unknown as { createWebSocket: (url: string) => unknown })
|
||||
.createWebSocket;
|
||||
createWebSocket("wss://gateway.discord.gg");
|
||||
await registerGatewayClientWithMetadata({ plugin, fetchMock: undiciFetchMock });
|
||||
await registerGatewayClientWithMetadata({ plugin, fetchMock: globalFetchMock });
|
||||
|
||||
expect(wsProxyAgentSpy).toHaveBeenCalledWith("http://[::1]:8080");
|
||||
expect(restProxyAgentSpy).toHaveBeenCalledWith("http://[::1]:8080");
|
||||
expect(runtime.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user