Skip to content

Commit ef2131a

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
fix: Correct the URL scheme and port used on the psc_endpoint branch in Sandboxes.send_command and Sandboxes.generate_browser_ws_headers. The branch added in cl/981254234 built https://{psc_endpoint} and defaulted to port 443, but PSC endpoints for VPC-SC sandboxes route directly to the sandbox router pod, which serves plain HTTP on the caller-supplied port (default 8080) and does not terminate TLS on 443. As a result every VPC-SC data-plane call through the SDK hung on ConnectTimeout at HTTPSConnectionPool(host='<psc-ip>', port=443). The endpoint is now built as http://{psc_endpoint}:{port} for send_command and ws://{psc_endpoint}:{port} for generate_browser_ws_headers, so the URL matches what the router serves. Non-VPC-SC callers (load_balancer_hostname / load_balancer_ip branches) are unaffected.
PiperOrigin-RevId: 983303249
1 parent 9b9f2b3 commit ef2131a

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

‎agentplatform/_genai/sandboxes.py‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,14 @@ def send_command(
14051405
if psc_endpoint:
14061406
# VPC-SC path: caller has provisioned a PSC endpoint against
14071407
# connection_info.service_attachment and passes its host here.
1408-
endpoint = "https://" + psc_endpoint
1408+
# The forwarding rule targets the router's Service Attachment
1409+
# directly, and the router pod serves plain HTTP on `port` (the
1410+
# router NetworkPolicy allows ingress only on that TCP port).
1411+
# Unlike the non-VPC-SC load_balancer_hostname case, no
1412+
# Google-managed L7 LB terminates TLS or translates ports in
1413+
# front, so the URL must be http://host:port, not https://host
1414+
# on the default 443.
1415+
endpoint = f"http://{psc_endpoint}:{port}"
14091416
elif connection_info.load_balancer_hostname:
14101417
endpoint = "https://" + connection_info.load_balancer_hostname
14111418
elif connection_info.load_balancer_ip:
@@ -1489,7 +1496,11 @@ def generate_browser_ws_headers(
14891496

14901497
connection_info = sandbox_environment.connection_info
14911498
if psc_endpoint:
1492-
ws_base_url = "wss://" + psc_endpoint
1499+
# See send_command's psc_endpoint branch for the rationale: the
1500+
# PSC forwarding rule targets the router's Service Attachment
1501+
# directly (no L7 LB in front), so this must be plain ws:// with
1502+
# the explicit port, not wss:// on the default 443.
1503+
ws_base_url = f"ws://{psc_endpoint}:{port}"
14931504
elif connection_info.load_balancer_hostname:
14941505
ws_base_url = "wss://" + connection_info.load_balancer_hostname
14951506
elif connection_info.load_balancer_ip:

‎tests/unit/agentplatform/genai/test_sandbox.py‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ def test_send_command_vpcsc_uses_psc_endpoint(self, mock_request):
186186

187187
args, kwargs = mock_request.call_args
188188
assert args[0] == "GET"
189-
assert args[1] == "https://10.0.0.10/test/path"
189+
# PSC-E ingress goes to the router pod directly (no Google-managed L7
190+
# LB in front), and the router serves plain HTTP on the sandbox port.
191+
# The URL must therefore be http://host:port, not https://host on the
192+
# default 443.
193+
assert args[1] == "http://10.0.0.10:9000/test/path"
190194
assert kwargs["headers"]["Authorization"] == "Bearer test_token"
191195
assert kwargs["headers"]["X-Sandbox-Routing-Token"] == "test_routing_token"
192196
# X-Sandbox-Port must flow through even on the VPC-SC path; the
@@ -215,7 +219,11 @@ def test_send_command_vpcsc_accepts_hostname_as_psc_endpoint(self, mock_request)
215219
)
216220

217221
args, _ = mock_request.call_args
218-
assert args[1] == "https://psc-endpoint.internal.example.com/test/path"
222+
# Default port "8080" is baked into the URL; scheme is plain http.
223+
assert (
224+
args[1]
225+
== "http://psc-endpoint.internal.example.com:8080/test/path"
226+
)
219227

220228
def test_send_command_raises_when_no_endpoint_available(self):
221229
mock_sandbox = mock.Mock()
@@ -253,15 +261,17 @@ def test_generate_browser_ws_headers_vpcsc_uses_psc_endpoint(
253261
timeout=3600,
254262
psc_endpoint="10.0.0.10",
255263
)
256-
assert ws_url == "wss://10.0.0.10/test/endpoint"
264+
# Plain ws:// with the explicit port for the same reason send_command
265+
# uses http://host:port on this branch — see that method's docstring.
266+
assert ws_url == "ws://10.0.0.10:8080/test/endpoint"
257267
assert (
258268
headers["Sec-WebSocket-Protocol"]
259269
== "v1.stream, test_token, test_routing_token, 9222"
260270
)
261271
# The delegated send_command call that fetches the CDP endpoint must
262272
# also target the PSC endpoint host, not the (empty) load balancer.
263273
req_args, req_kwargs = mock_request.call_args
264-
assert req_args[1] == "https://10.0.0.10/cdp_ws_endpoint"
274+
assert req_args[1] == "http://10.0.0.10:8080/cdp_ws_endpoint"
265275
assert req_kwargs["headers"]["X-Sandbox-Routing-Token"] == "test_routing_token"
266276

267277
@mock.patch.object(sandboxes.Sandboxes, "_create")

0 commit comments

Comments
 (0)