Skip to content

Commit 1da4ee3

Browse files
paddymulclaude
andcommitted
test(server): failing test for xorq infinite_request traceback leak
#798: ``handle_infinite_request_xorq`` returns ``traceback.format_exc()`` in the ``error_info`` field unconditionally — leaking server source paths and stack frames to WS clients. The pandas-path handler in ``websocket_handler.py`` correctly gates this on ``BUCKAROO_DEBUG``. Test triggers the exception path with a sort key that doesn't exist in ``merged_sd`` (raises ``KeyError``), then asserts ``error_info`` does not start with ``"Traceback"``. Fails today; will pass once the xorq handler gates the traceback behind ``BUCKAROO_DEBUG``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7a75b5b commit 1da4ee3

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

tests/unit/server/test_load_expr.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,46 @@ async def test_ws_search_pushdown(self):
141141
finally:
142142
shutil.rmtree(builds_root, ignore_errors=True)
143143

144+
@tornado.testing.gen_test
145+
async def test_xorq_infinite_request_error_info_no_traceback(self):
146+
"""Regression for #798: the xorq path put ``traceback.format_exc()``
147+
into ``error_info`` unconditionally — leaking server-side source
148+
paths to WS clients. Pandas path gates this behind
149+
``BUCKAROO_DEBUG``; xorq must too.
150+
151+
Trigger the exception with a sort column that doesn't exist in
152+
``merged_sd`` — raises ``KeyError`` inside
153+
``handle_infinite_request_xorq``.
154+
"""
155+
builds_root = tempfile.mkdtemp()
156+
try:
157+
build_path = _build_expr_dir(builds_root)
158+
await _post(self.get_http_port(), "/load_expr",
159+
{"session": "lx-leak", "build_dir": build_path})
160+
161+
ws = await tornado.websocket.websocket_connect(
162+
f"ws://localhost:{self.get_http_port()}/ws/lx-leak")
163+
await ws.read_message() # discard initial_state
164+
165+
ws.write_message(json.dumps({
166+
"type": "infinite_request",
167+
"payload_args": {"start": 0, "end": 5,
168+
"sort": "nonexistent_col", "sort_direction": "asc",
169+
"sourceName": "default", "origEnd": 5}}))
170+
171+
r = json.loads(await ws.read_message())
172+
self.assertEqual(r["type"], "infinite_resp")
173+
self.assertIn("error_info", r)
174+
# The bug: pre-fix this carries a full traceback starting
175+
# with "Traceback (most recent call last):\n File ...".
176+
# Production runs shouldn't leak source paths to clients.
177+
self.assertFalse(r["error_info"].startswith("Traceback"),
178+
f"error_info leaked traceback to client (first 200 chars): "
179+
f"{r['error_info'][:200]!r}")
180+
ws.close()
181+
finally:
182+
shutil.rmtree(builds_root, ignore_errors=True)
183+
144184
@tornado.testing.gen_test
145185
async def test_session_reuse_xorq_then_pandas(self):
146186
"""A client that POSTs /load_expr and then POSTs /load with the

0 commit comments

Comments
 (0)