Skip to content

Commit 111aa09

Browse files
committed
Only evict a stale JWT if it is still the cached one
A later 401 must not delete a route that was refreshed in flight.
1 parent 728330d commit 111aa09

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

src/kernel/lib/browser_routing/routing.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ def set(self, route: BrowserRoute) -> None:
6969
def delete(self, session_id: str) -> None:
7070
self._routes.pop(_normalize_session_id(session_id), None)
7171

72+
def delete_if_jwt(self, session_id: str, jwt: str) -> bool:
73+
key = _normalize_session_id(session_id)
74+
route = self._routes.get(key)
75+
if route is None or route.jwt != jwt.strip():
76+
return False
77+
del self._routes[key]
78+
return True
79+
7280
def values(self) -> list[BrowserRoute]:
7381
return list(self._routes.values())
7482

@@ -119,9 +127,10 @@ def maybe_evict_browser_route_from_response(response: httpx.Response, *, cache:
119127
if not is_stale_direct_vm_auth_response(response):
120128
return
121129

130+
jwt = str(response.request.url.params.get("jwt") or "").strip()
122131
session_id = _session_id_from_direct_vm_response(response, cache=cache)
123-
if session_id:
124-
cache.delete(session_id)
132+
if session_id and jwt:
133+
cache.delete_if_jwt(session_id, jwt)
125134

126135

127136
def populate_browser_route_cache_from_value(value: object, *, cache: BrowserRouteCache) -> None:

tests/test_browser_routing.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,37 @@ def _skip_retry_sleep(_self: object, **_kwargs: object) -> None:
548548
assert api_req.headers.get("Authorization") == f"Bearer {api_key}"
549549

550550

551+
def test_stale_direct_vm_jwt_does_not_evict_refreshed_route() -> None:
552+
from kernel.lib.browser_routing.routing import maybe_evict_browser_route_from_response
553+
554+
cache = BrowserRouteCache()
555+
cache.set(
556+
BrowserRoute(
557+
session_id="sess-1",
558+
base_url="http://browser-session.test/browser/kernel",
559+
jwt="token-abc",
560+
)
561+
)
562+
cache.set(
563+
BrowserRoute(
564+
session_id="sess-1",
565+
base_url="http://browser-session.test/browser/kernel",
566+
jwt="jwt-FRESH",
567+
)
568+
)
569+
request = httpx.Request(
570+
"POST",
571+
"http://browser-session.test/browser/kernel/computer/screenshot?jwt=token-abc",
572+
)
573+
maybe_evict_browser_route_from_response(
574+
httpx.Response(401, text="Invalid JWT", request=request),
575+
cache=cache,
576+
)
577+
route = cache.get("sess-1")
578+
assert route is not None
579+
assert route.jwt == "jwt-FRESH"
580+
581+
551582
def test_stale_direct_vm_auth_retry_does_not_require_cached_route() -> None:
552583
from kernel.lib.browser_routing.routing import should_retry_stale_direct_vm_auth
553584

0 commit comments

Comments
 (0)