88
99import { MockConfigurationProvider } from "../../mocks/testHelpers" ;
1010
11- const URL = "https://coder.example.com" ;
1211const proxy = "http://proxy.example.com:8080" ;
1312
1413function setup ( ) {
@@ -32,12 +31,16 @@ describe("getSshProxyEnvironment", () => {
3231 expected : { HTTP_PROXY : proxy , HTTPS_PROXY : proxy } ,
3332 } ,
3433 {
35- name : "drops the proxy when the deployment is bypassed" ,
34+ name : "passes through the proxy when the deployment is bypassed" ,
3635 settings : {
3736 "http.proxy" : proxy ,
3837 "coder.proxyBypass" : "coder.example.com" ,
3938 } ,
40- expected : { NO_PROXY : "coder.example.com" } ,
39+ expected : {
40+ HTTP_PROXY : proxy ,
41+ HTTPS_PROXY : proxy ,
42+ NO_PROXY : "coder.example.com" ,
43+ } ,
4144 } ,
4245 {
4346 name : "falls back to http.noProxy when coder.proxyBypass is unset" ,
@@ -64,17 +67,35 @@ describe("getSshProxyEnvironment", () => {
6467 NO_PROXY : "primary.example.com" ,
6568 } ,
6669 } ,
70+ {
71+ name : "ignores a whitespace-only http.proxy" ,
72+ settings : { "http.proxy" : " " } ,
73+ expected : { } ,
74+ } ,
75+ {
76+ name : "falls back to http.noProxy when coder.proxyBypass is whitespace" ,
77+ settings : {
78+ "http.proxy" : proxy ,
79+ "coder.proxyBypass" : " " ,
80+ "http.noProxy" : [ "fallback.example.com" ] ,
81+ } ,
82+ expected : {
83+ HTTP_PROXY : proxy ,
84+ HTTPS_PROXY : proxy ,
85+ NO_PROXY : "fallback.example.com" ,
86+ } ,
87+ } ,
6788 ] ) ( "$name" , ( { settings, expected } ) => {
6889 const { config } = setup ( ) ;
6990
70- expect ( getSshProxyEnvironment ( URL , config ( settings ) ) ) . toEqual ( expected ) ;
91+ expect ( getSshProxyEnvironment ( config ( settings ) ) ) . toEqual ( expected ) ;
7192 } ) ;
7293
7394 it ( "ignores an existing env proxy when http.proxy is unset" , ( ) => {
7495 const { config } = setup ( ) ;
7596 vi . stubEnv ( "HTTPS_PROXY" , "http://env-proxy.example.com:8080" ) ;
7697
77- expect ( getSshProxyEnvironment ( URL , config ( ) ) ) . toEqual ( { } ) ;
98+ expect ( getSshProxyEnvironment ( config ( ) ) ) . toEqual ( { } ) ;
7899 } ) ;
79100} ) ;
80101
@@ -84,7 +105,6 @@ describe("applySshEnvironment", () => {
84105 const env : Record < string , string | undefined > = { } ;
85106
86107 const applied = applySshEnvironment (
87- URL ,
88108 config ( {
89109 "http.proxy" : proxy ,
90110 "coder.proxyBypass" : "internal.example.com" ,
@@ -101,28 +121,42 @@ describe("applySshEnvironment", () => {
101121 expect ( env ) . toEqual ( { } ) ;
102122 } ) ;
103123
104- it ( "overwrites and restores existing lowercase variables" , ( ) => {
124+ it ( "does not overwrite existing lowercase variables" , ( ) => {
105125 const { config } = setup ( ) ;
106126 const original = {
107127 http_proxy : "http://old-http-proxy.example.com:8080" ,
108128 https_proxy : "http://old-https-proxy.example.com:8080" ,
109129 } ;
110130 const env : Record < string , string | undefined > = { ...original } ;
111131
112- const applied = applySshEnvironment (
113- URL ,
114- config ( { "http.proxy" : proxy } ) ,
115- env ,
116- ) ;
117- expect ( env ) . toEqual ( { http_proxy : proxy , https_proxy : proxy } ) ;
132+ const applied = applySshEnvironment ( config ( { "http.proxy" : proxy } ) , env ) ;
133+ expect ( env ) . toEqual ( {
134+ ... original ,
135+ HTTP_PROXY : proxy ,
136+ HTTPS_PROXY : proxy ,
137+ } ) ;
118138
119139 applied . dispose ( ) ;
120140 expect ( env ) . toEqual ( original ) ;
121141 } ) ;
122142
143+ it ( "restores existing case-insensitive variables" , ( ) => {
144+ const { config } = setup ( ) ;
145+ const original = "http://old-http-proxy.example.com:8080" ;
146+ const env = caseInsensitiveEnvironment ( { http_proxy : original } ) ;
147+
148+ const applied = applySshEnvironment ( config ( { "http.proxy" : proxy } ) , env ) ;
149+ expect ( env . HTTP_PROXY ) . toBe ( proxy ) ;
150+ expect ( env . http_proxy ) . toBe ( proxy ) ;
151+
152+ applied . dispose ( ) ;
153+ expect ( env . HTTP_PROXY ) . toBe ( original ) ;
154+ expect ( env . http_proxy ) . toBe ( original ) ;
155+ } ) ;
156+
123157 it ( "propagates proxy variables to newly spawned child processes" , ( ) => {
124158 const { config } = setup ( ) ;
125- const applied = applySshEnvironment ( URL , config ( { "http.proxy" : proxy } ) ) ;
159+ const applied = applySshEnvironment ( config ( { "http.proxy" : proxy } ) ) ;
126160
127161 try {
128162 expect ( getProxyEnvFromChild ( ) ) . toEqual ( { http : proxy , https : proxy } ) ;
@@ -132,6 +166,41 @@ describe("applySshEnvironment", () => {
132166 } ) ;
133167} ) ;
134168
169+ function caseInsensitiveEnvironment (
170+ values : Record < string , string > ,
171+ ) : Record < string , string | undefined > {
172+ return new Proxy ( values , {
173+ get ( target , property ) {
174+ if ( typeof property !== "string" ) {
175+ return undefined ;
176+ }
177+ return target [ getCaseInsensitiveKey ( target , property ) ?? property ] ;
178+ } ,
179+ set ( target , property , value ) {
180+ if ( typeof property !== "string" ) {
181+ return false ;
182+ }
183+ target [ getCaseInsensitiveKey ( target , property ) ?? property ] = value ;
184+ return true ;
185+ } ,
186+ deleteProperty ( target , property ) {
187+ if ( typeof property !== "string" ) {
188+ return false ;
189+ }
190+ return delete target [ getCaseInsensitiveKey ( target , property ) ?? property ] ;
191+ } ,
192+ } ) ;
193+ }
194+
195+ function getCaseInsensitiveKey (
196+ values : Record < string , string | undefined > ,
197+ key : string ,
198+ ) : string | undefined {
199+ return Object . keys ( values ) . find (
200+ ( valueKey ) => valueKey . toLowerCase ( ) === key . toLowerCase ( ) ,
201+ ) ;
202+ }
203+
135204function getProxyEnvFromChild ( ) : { http : string ; https : string } {
136205 const result = spawnSync (
137206 process . execPath ,
0 commit comments