@@ -99,7 +99,7 @@ def test_browser_request_uses_curl_raw() -> None:
9999
100100@respx .mock
101101def test_telemetry_stream_routes_directly_to_vm (monkeypatch : pytest .MonkeyPatch ) -> None :
102- monkeypatch .setenv ("KERNEL_BROWSER_ROUTING_SUBRESOURCES" , "telemetry" )
102+ monkeypatch .setenv ("KERNEL_BROWSER_ROUTING_SUBRESOURCES" , "telemetry/stream " )
103103 route = respx .get ("http://browser-session.test/browser/kernel/telemetry/stream" ).mock (
104104 return_value = httpx .Response (
105105 200 ,
@@ -337,7 +337,52 @@ def test_browser_route_from_browser_requires_base_url_and_jwt() -> None:
337337
338338def test_browser_routing_config_from_env_defaults_to_curl (monkeypatch : pytest .MonkeyPatch ) -> None :
339339 monkeypatch .delenv ("KERNEL_BROWSER_ROUTING_SUBRESOURCES" , raising = False )
340- assert browser_routing_config_from_env ().subresources == ("curl" , "telemetry" )
340+ assert browser_routing_config_from_env ().subresources == ("curl" , "telemetry/stream" )
341+
342+
343+ def test_direct_vm_routing_allowlist_segment_boundary () -> None :
344+ # Pins the fix: telemetry/stream (live SSE) routes to the VM; telemetry/events
345+ # (historical, served by the control plane from S2) does NOT; and a
346+ # stream-prefixed-but-different path is not matched.
347+ from kernel .lib .browser_routing .routing import _matches_direct_vm_prefix
348+
349+ prefixes = ("curl" , "telemetry/stream" )
350+ assert _matches_direct_vm_prefix ("telemetry/stream" , prefixes ) is True
351+ assert _matches_direct_vm_prefix ("telemetry/stream/x" , prefixes ) is True
352+ assert _matches_direct_vm_prefix ("telemetry/events" , prefixes ) is False
353+ assert _matches_direct_vm_prefix ("telemetry/streaming-config" , prefixes ) is False
354+ assert _matches_direct_vm_prefix ("telemetry" , prefixes ) is False
355+ assert _matches_direct_vm_prefix ("curl/raw" , prefixes ) is True
356+ assert _matches_direct_vm_prefix ("fs/read" , prefixes ) is False
357+
358+
359+ def test_rewrite_direct_vm_options_keeps_telemetry_events_on_control_plane () -> None :
360+ # Integration through the real routing hook: telemetry/events (historical,
361+ # control-plane/S2) must NOT be rewritten to the VM, while telemetry/stream
362+ # (live SSE) must be.
363+ from kernel ._models import FinalRequestOptions
364+ from kernel .lib .browser_routing .routing import (
365+ BrowserRoute ,
366+ BrowserRouteCache ,
367+ BrowserRoutingConfig ,
368+ rewrite_direct_vm_options ,
369+ )
370+
371+ cache = BrowserRouteCache ()
372+ cache .set (
373+ BrowserRoute (session_id = "sess-1" , base_url = "http://browser-session.test/browser/kernel" , jwt = "token-abc" )
374+ )
375+ config = BrowserRoutingConfig (subresources = ("curl" , "telemetry/stream" ))
376+
377+ events = rewrite_direct_vm_options (
378+ FinalRequestOptions (method = "get" , url = "/browsers/sess-1/telemetry/events" ), cache = cache , config = config
379+ )
380+ assert events .url == "/browsers/sess-1/telemetry/events" # unchanged -> control plane
381+
382+ stream = rewrite_direct_vm_options (
383+ FinalRequestOptions (method = "get" , url = "/browsers/sess-1/telemetry/stream" ), cache = cache , config = config
384+ )
385+ assert str (stream .url ).startswith ("http://browser-session.test/browser/kernel/telemetry/stream" )
341386
342387
343388def test_browser_routing_config_from_env_empty_string_disables_routing (monkeypatch : pytest .MonkeyPatch ) -> None :
0 commit comments