mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:00:54 +00:00
fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode for remote embeddings in proxy environments (#71506)
* fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode in withRemoteHttpResponse When a HTTP/HTTPS proxy is configured via environment variables (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY), the withRemoteHttpResponse function now passes mode=TRUSTED_ENV_PROXY to fetchWithSsrFGuard. This causes DNS resolution to skip the local resolver and route through the configured proxy, fixing 'fetch failed' errors for remote memory embeddings (including GitHub Copilot embeddings) in proxy environments (e.g. Clash TUN, corporate proxies). Previously, without an explicit mode, fetchWithSsrFGuard defaulted to STRICT mode which performs local DNS pre-resolution via resolvePinnedHostnameWithPolicy(), failing in proxy environments where DNS must go through the proxy. Fixes: openclaw/openclaw#52162 * fix: harden memory env proxy guard (#71506) (thanks @DhtIsCoding) --------- Co-authored-by: Dht <dht@openclaw.ai> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
68
packages/memory-host-sdk/src/host/remote-http.test.ts
Normal file
68
packages/memory-host-sdk/src/host/remote-http.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { fetchWithSsrFGuardMock, shouldUseEnvHttpProxyForUrlMock } = vi.hoisted(() => ({
|
||||
fetchWithSsrFGuardMock: vi.fn(),
|
||||
shouldUseEnvHttpProxyForUrlMock: vi.fn(() => false),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/infra/net/fetch-guard.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../../../../src/infra/net/fetch-guard.js")>(
|
||||
"../../../../src/infra/net/fetch-guard.js",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
fetchWithSsrFGuard: fetchWithSsrFGuardMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../../../src/infra/net/proxy-env.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../../../../src/infra/net/proxy-env.js")>(
|
||||
"../../../../src/infra/net/proxy-env.js",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
shouldUseEnvHttpProxyForUrl: shouldUseEnvHttpProxyForUrlMock,
|
||||
};
|
||||
});
|
||||
|
||||
import { GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js";
|
||||
import { withRemoteHttpResponse } from "./remote-http.js";
|
||||
|
||||
describe("package withRemoteHttpResponse", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(false);
|
||||
fetchWithSsrFGuardMock.mockResolvedValue({
|
||||
response: new Response("ok", { status: 200 }),
|
||||
finalUrl: "https://memory.example/v1",
|
||||
release: vi.fn(async () => {}),
|
||||
});
|
||||
});
|
||||
|
||||
it("uses trusted env proxy mode when the target will use EnvHttpProxyAgent", async () => {
|
||||
shouldUseEnvHttpProxyForUrlMock.mockReturnValue(true);
|
||||
|
||||
await withRemoteHttpResponse({
|
||||
url: "https://memory.example/v1/embeddings",
|
||||
onResponse: async () => undefined,
|
||||
});
|
||||
|
||||
expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
url: "https://memory.example/v1/embeddings",
|
||||
mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps strict guarded fetch mode when proxy env would not proxy the target", async () => {
|
||||
await withRemoteHttpResponse({
|
||||
url: "https://internal.corp.example/v1/embeddings",
|
||||
onResponse: async () => undefined,
|
||||
});
|
||||
|
||||
const call = fetchWithSsrFGuardMock.mock.calls[0]?.[0];
|
||||
expect(call).toBeDefined();
|
||||
expect(call).not.toHaveProperty("mode");
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import { fetchWithSsrFGuard } from "../../../../src/infra/net/fetch-guard.js";
|
||||
import { fetchWithSsrFGuard, GUARDED_FETCH_MODE } from "../../../../src/infra/net/fetch-guard.js";
|
||||
import { shouldUseEnvHttpProxyForUrl } from "../../../../src/infra/net/proxy-env.js";
|
||||
import type { SsrFPolicy } from "../../../../src/infra/net/ssrf.js";
|
||||
|
||||
export function buildRemoteBaseUrlPolicy(baseUrl: string): SsrFPolicy | undefined {
|
||||
@@ -31,6 +32,9 @@ export async function withRemoteHttpResponse<T>(params: {
|
||||
init: params.init,
|
||||
policy: params.ssrfPolicy,
|
||||
auditContext: params.auditContext ?? "memory-remote",
|
||||
...(shouldUseEnvHttpProxyForUrl(params.url)
|
||||
? { mode: GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY }
|
||||
: {}),
|
||||
});
|
||||
try {
|
||||
return await params.onResponse(response);
|
||||
|
||||
Reference in New Issue
Block a user