@@ -221,20 +221,24 @@ class TestCreate:
221221 @pytest .fixture (autouse = True )
222222 def egress_sidecar (self ):
223223 """Answer the egress sidecar's ``GET /policy``, reporting ``enforcement_mode`` (dns+nft unless a test sets it)."""
224- sidecar = SimpleNamespace (enforcement_mode = "dns+nft" , status_code = 200 , requests = [])
224+ sidecar = SimpleNamespace (
225+ enforcement_mode = "dns+nft" , status_code = 200 , transient_status = None , requests = []
226+ )
225227
226- def send (_client , request , ** _kwargs ):
228+ def send (_transport , request ):
227229 sidecar .requests .append (request )
228230 if isinstance (sidecar .enforcement_mode , Exception ):
229231 raise sidecar .enforcement_mode
232+ if sidecar .transient_status is not None and len (sidecar .requests ) == 1 :
233+ return httpx .Response (sidecar .transient_status , text = "retry" , request = request )
230234 if sidecar .status_code != 200 :
231235 return httpx .Response (sidecar .status_code , text = "upstream failed" , request = request )
232236 body = {"status" : "ok" , "mode" : "deny_all" , "policy" : {"defaultAction" : "deny" }}
233237 if sidecar .enforcement_mode is not None :
234238 body ["enforcementMode" ] = sidecar .enforcement_mode
235239 return httpx .Response (200 , json = body , request = request )
236240
237- with mock .patch .object (httpx .Client , "send " , autospec = True , side_effect = send ):
241+ with mock .patch .object (httpx .HTTPTransport , "handle_request " , autospec = True , side_effect = send ):
238242 yield sidecar
239243
240244 @mock .patch ("opensandbox.SandboxSync.create" , autospec = True )
@@ -345,11 +349,43 @@ def test_enforced_deny_policy_is_read_back_before_the_sandbox_is_handed_out(self
345349 assert request .extensions ["timeout" ]["read" ] == 12
346350 create .return_value .destroy .assert_not_called ()
347351
352+ @pytest .mark .parametrize ("transient_status" , [None , 502 , 503 ])
353+ @mock .patch ("opensandbox.SandboxSync.create" , autospec = True )
354+ def test_policy_readback_uses_owned_transport_with_proxy_environment (
355+ self , create , transient_status , egress_sidecar , monkeypatch
356+ ):
357+ monkeypatch .setenv ("HTTP_PROXY" , "http://proxy.invalid:3128" )
358+ monkeypatch .setenv ("HTTPS_PROXY" , "http://proxy.invalid:3128" )
359+ monkeypatch .setenv ("NO_PROXY" , "" )
360+ egress_sidecar .transient_status = transient_status
361+ sandbox = _created (_deny_policy ())
362+ sandbox .connection_config = sandbox .connection_config .with_transport_if_missing ()
363+ shared_transport = sandbox .connection_config .transport
364+ create .return_value = sandbox
365+ backend = OpenSandboxBackend ()
366+ backend ._connection_config = mock .sentinel .connection_config
367+ transport_init = httpx .HTTPTransport .__init__
368+ with (
369+ mock .patch .object (
370+ httpx .HTTPTransport , "__init__" , autospec = True , side_effect = transport_init
371+ ) as init ,
372+ mock .patch .object (
373+ type (shared_transport ), "close" , autospec = True , side_effect = type (shared_transport ).close
374+ ) as close ,
375+ ):
376+ assert backend .create (spec = SandboxSpec ()) == "created"
377+ assert len (egress_sidecar .requests ) == (1 if transient_status is None else 2 )
378+ assert all (call .kwargs .get ("proxy" ) is None for call in init .call_args_list )
379+ close .assert_called_once ()
380+ assert close .call_args .args [0 ] is not shared_transport
381+ shared_transport .close ()
382+ sandbox .destroy .assert_not_called ()
383+
348384 @pytest .mark .parametrize (
349385 ("sidecar" , "reason" ),
350386 [
351387 ({"enforcement_mode" : "dns" }, r"enforces it in 'dns' mode.*\[egress\] mode = \"dns\+nft\"" ),
352- ({"enforcement_mode" : None }, "does not report an enforcement mode" ),
388+ ({"enforcement_mode" : None }, "does not report an enforcement mode.*Upgrade.*v1.0.1 or later " ),
353389 ({"enforcement_mode" : httpx .ConnectError ("refused" )}, r"could not be read back \(ConnectError\)" ),
354390 ({"status_code" : 500 }, r"could not be read back \(SandboxApiException, HTTP 500\)" ),
355391 ],
0 commit comments