22import http from "node:http" ;
33import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts" ;
44import { fetch as undiciFetch } from "undici" ;
5- import { beforeEach , describe , expect , it , vi } from "vitest" ;
5+ import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
66import { createDiscordRestClient } from "./client.js" ;
77import { createDiscordRequestClient } from "./proxy-request-client.js" ;
88
@@ -26,9 +26,14 @@ vi.mock("openclaw/plugin-sdk/fetch-runtime", async () => {
2626
2727describe ( "createDiscordRestClient proxy support" , ( ) => {
2828 beforeEach ( ( ) => {
29+ vi . unstubAllEnvs ( ) ;
2930 makeProxyFetchMock . mockClear ( ) ;
3031 } ) ;
3132
33+ afterEach ( ( ) => {
34+ vi . unstubAllEnvs ( ) ;
35+ } ) ;
36+
3237 it ( "injects a custom fetch into RequestClient when a Discord proxy is configured" , ( ) => {
3338 const cfg = {
3439 channels : {
@@ -50,6 +55,110 @@ describe("createDiscordRestClient proxy support", () => {
5055 expect ( requestClient . customFetch ) . toBe ( requestClient . options ?. fetch ) ;
5156 } ) ;
5257
58+ it ( "accepts the configured process proxy DNS host" , ( ) => {
59+ vi . stubEnv ( "HTTPS_PROXY" , "http://mitm-proxy:8080" ) ;
60+ const cfg = {
61+ channels : {
62+ discord : {
63+ token : "Bot test-token" ,
64+ proxy : "http://mitm-proxy:8080" ,
65+ } ,
66+ } ,
67+ } as OpenClawConfig ;
68+
69+ const { rest } = createDiscordRestClient ( { cfg } ) ;
70+ const requestClient = rest as unknown as {
71+ customFetch ?: typeof fetch ;
72+ options ?: { fetch ?: typeof fetch } ;
73+ } ;
74+
75+ expect ( makeProxyFetchMock ) . toHaveBeenCalledWith ( "http://mitm-proxy:8080" ) ;
76+ expect ( requestClient . options ?. fetch ) . toBe ( makeProxyFetchMock . mock . results [ 0 ] ?. value ) ;
77+ expect ( requestClient . customFetch ) . toBe ( requestClient . options ?. fetch ) ;
78+ } ) ;
79+
80+ it ( "accepts a proxy URL that matches ALL_PROXY" , ( ) => {
81+ vi . stubEnv ( "ALL_PROXY" , "http://mitm-proxy:8080" ) ;
82+ const cfg = {
83+ channels : {
84+ discord : {
85+ token : "Bot test-token" ,
86+ proxy : "http://mitm-proxy:8080" ,
87+ } ,
88+ } ,
89+ } as OpenClawConfig ;
90+
91+ const { rest } = createDiscordRestClient ( { cfg } ) ;
92+ const requestClient = rest as unknown as {
93+ customFetch ?: typeof fetch ;
94+ options ?: { fetch ?: typeof fetch } ;
95+ } ;
96+
97+ expect ( makeProxyFetchMock ) . toHaveBeenCalledWith ( "http://mitm-proxy:8080" ) ;
98+ expect ( requestClient . options ?. fetch ) . toBe ( makeProxyFetchMock . mock . results [ 0 ] ?. value ) ;
99+ expect ( requestClient . customFetch ) . toBe ( requestClient . options ?. fetch ) ;
100+ } ) ;
101+
102+ it ( "rejects a configured process proxy host when credentials do not match" , ( ) => {
103+ vi . stubEnv ( "HTTPS_PROXY" , "http://user:secret@mitm-proxy:8080" ) ;
104+ const cfg = {
105+ channels : {
106+ discord : {
107+ token : "Bot test-token" ,
108+ proxy : "http://mitm-proxy:8080" ,
109+ } ,
110+ } ,
111+ } as OpenClawConfig ;
112+
113+ const { rest } = createDiscordRestClient ( { cfg } ) ;
114+ const requestClient = rest as unknown as {
115+ options ?: { fetch ?: typeof fetch } ;
116+ } ;
117+
118+ expect ( makeProxyFetchMock ) . not . toHaveBeenCalledWith ( "http://mitm-proxy:8080" ) ;
119+ expect ( requestClient . options ?. fetch ) . toBeUndefined ( ) ;
120+ } ) ;
121+
122+ it ( "rejects a shadowed uppercase proxy env URL" , ( ) => {
123+ vi . stubEnv ( "HTTPS_PROXY" , "http://mitm-proxy:8080" ) ;
124+ vi . stubEnv ( "https_proxy" , "http://active-proxy:8080" ) ;
125+ const cfg = {
126+ channels : {
127+ discord : {
128+ token : "Bot test-token" ,
129+ proxy : "http://mitm-proxy:8080" ,
130+ } ,
131+ } ,
132+ } as OpenClawConfig ;
133+
134+ const { rest } = createDiscordRestClient ( { cfg } ) ;
135+ const requestClient = rest as unknown as {
136+ options ?: { fetch ?: typeof fetch } ;
137+ } ;
138+
139+ expect ( makeProxyFetchMock ) . not . toHaveBeenCalledWith ( "http://mitm-proxy:8080" ) ;
140+ expect ( requestClient . options ?. fetch ) . toBeUndefined ( ) ;
141+ } ) ;
142+
143+ it ( "falls back to direct fetch when the Discord proxy URL is arbitrary DNS" , ( ) => {
144+ const cfg = {
145+ channels : {
146+ discord : {
147+ token : "Bot test-token" ,
148+ proxy : "http://proxy.test:8080" ,
149+ } ,
150+ } ,
151+ } as OpenClawConfig ;
152+
153+ const { rest } = createDiscordRestClient ( { cfg } ) ;
154+ const requestClient = rest as unknown as {
155+ options ?: { fetch ?: typeof fetch } ;
156+ } ;
157+
158+ expect ( makeProxyFetchMock ) . not . toHaveBeenCalledWith ( "http://proxy.test:8080" ) ;
159+ expect ( requestClient . options ?. fetch ) . toBeUndefined ( ) ;
160+ } ) ;
161+
53162 it ( "does not inject fetch when no proxy is configured" , ( ) => {
54163 const cfg = {
55164 channels : {
@@ -86,12 +195,12 @@ describe("createDiscordRestClient proxy support", () => {
86195 expect ( requestClient . options ?. fetch ) . toBeUndefined ( ) ;
87196 } ) ;
88197
89- it ( "falls back to direct fetch when the Discord proxy URL is remote " , ( ) => {
198+ it ( "falls back to direct fetch when the Discord proxy URL is a non-loopback IP " , ( ) => {
90199 const cfg = {
91200 channels : {
92201 discord : {
93202 token : "Bot test-token" ,
94- proxy : "http://proxy.test :8080" ,
203+ proxy : "http://10.0.0.10 :8080" ,
95204 } ,
96205 } ,
97206 } as OpenClawConfig ;
@@ -101,7 +210,7 @@ describe("createDiscordRestClient proxy support", () => {
101210 options ?: { fetch ?: typeof fetch } ;
102211 } ;
103212
104- expect ( makeProxyFetchMock ) . not . toHaveBeenCalledWith ( "http://proxy.test :8080" ) ;
213+ expect ( makeProxyFetchMock ) . not . toHaveBeenCalledWith ( "http://10.0.0.10 :8080" ) ;
105214 expect ( requestClient . options ?. fetch ) . toBeUndefined ( ) ;
106215 } ) ;
107216
0 commit comments