Skip to content

Commit 0484d47

Browse files
committed
fix(websocket): preserve owner transport diagnostics
1 parent 812dcef commit 0484d47

2 files changed

Lines changed: 81 additions & 3 deletions

File tree

lib/codex_pooler/gateway/transports/websocket/websocket_owner_session.ex

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -697,9 +697,18 @@ defmodule CodexPooler.Gateway.Transports.Websocket.WebsocketOwnerSession do
697697
request = %{request | writer: writer}
698698

699699
case UpstreamWebSocketSession.request(upstream_pid, request) do
700-
{:ok, result} -> {:ok, result}
701-
{:error, %{reason: reason}} when is_atom(reason) -> {:error, reason}
702-
{:error, response} when is_map(response) -> {:error, response}
700+
{:ok, result} ->
701+
{:ok, result}
702+
703+
{:error, %{transport_failure: transport_failure} = response}
704+
when is_map(transport_failure) and map_size(transport_failure) > 0 ->
705+
{:error, response}
706+
707+
{:error, %{reason: reason}} when is_atom(reason) ->
708+
{:error, reason}
709+
710+
{:error, response} when is_map(response) ->
711+
{:error, response}
703712
end
704713
end
705714

test/codex_pooler_web/controllers/runtime/backend_codex_websocket_owner_forwarding_test.exs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,75 @@ defmodule CodexPoolerWeb.Runtime.BackendCodexWebsocketOwnerForwardingTest do
182182
end
183183
end
184184

185+
test "owner-forwarded upstream close before terminal persists safe transport metadata" do
186+
upstream =
187+
start_upstream(
188+
FakeUpstream.websocket_sse_then_close(
189+
[
190+
{"response.output_text.delta",
191+
%{
192+
"type" => "response.output_text.delta",
193+
"response_id" => "resp_owner_transport_failure",
194+
"output_index" => 0,
195+
"content_index" => 0,
196+
"delta" => @sentinel
197+
}}
198+
],
199+
reason: "owner upstream close reason sentinel"
200+
)
201+
)
202+
203+
setup = gateway_setup(upstream)
204+
{:ok, auth} = Access.authenticate_authorization_header(setup.authorization)
205+
{:ok, state} = owner_socket(auth, "ws-owner-transport-failure", "owner-transport-failure")
206+
207+
try do
208+
payload =
209+
websocket_payload(setup, "owner forwarded transport failure", %{
210+
"request_id" => "ws-owner-transport-failure"
211+
})
212+
213+
assert {:ok, state} = CodexResponsesSocket.handle_in({payload, [opcode: :text]}, state)
214+
215+
assert {:push, {:text, partial_frame}, state} = receive_owner_socket_push(state)
216+
217+
assert %{"type" => "response.output_text.delta", "delta" => @sentinel} =
218+
Jason.decode!(partial_frame)
219+
220+
assert {:push, {:text, error_frame}, _state} = receive_socket_done(state)
221+
222+
assert %{"type" => "error", "error" => %{"code" => "upstream_request_failed"}} =
223+
Jason.decode!(error_frame)
224+
225+
assert [request_log] = request_logs(setup.pool.id)
226+
assert request_log.status == "failed"
227+
assert request_log.transport == "websocket"
228+
assert request_log.last_error_code == "upstream_stream_error"
229+
230+
assert [attempt] = Repo.all(from(a in Attempt, where: a.request_id == ^request_log.id))
231+
assert attempt.status == "failed"
232+
233+
assert attempt.response_metadata["transport_failure"] == %{
234+
"phase" => "upstream_close",
235+
"pre_visible_output" => false,
236+
"reason" => "upstream_websocket_closed_before_terminal",
237+
"reason_class" => "upstream_websocket_closed_before_terminal",
238+
"terminal_seen" => false,
239+
"text_frame_count" => 1
240+
}
241+
242+
metadata_text = inspect(attempt.response_metadata)
243+
refute metadata_text =~ @sentinel
244+
refute metadata_text =~ "owner upstream close reason sentinel"
245+
refute metadata_text =~ setup.authorization
246+
refute metadata_text =~ setup.raw_key
247+
refute metadata_text =~ "Bearer "
248+
refute metadata_text =~ "upstream-token"
249+
after
250+
CodexResponsesSocket.terminate(:closed, state)
251+
end
252+
end
253+
185254
@tag :feature_websocket_terminal_auth_refresh
186255
test "owner-forwarded websocket terminal auth refresh retries through the same owner session" do
187256
upstream =

0 commit comments

Comments
 (0)