Files
openclaw/extensions
Frederic David blum 1e1cf14da2 fix(gateway): reject RPCs from invalidated device-token clients durin… (#70707)
* fix(gateway): reject RPCs from invalidated device-token clients during rotation/revoke race

device.token.rotate, device.token.revoke and device.pair.remove all
respond 200 OK to the admin, then schedule disconnectClientsForDevice
via queueMicrotask so the response can flush before the socket close.
That microtask window plus the absence of a per-RPC re-check for
device-token auth (unlike shared-auth, which gets checked at
message-handler.ts:1444-1458) created a race: an attacker with RPCs
already pipelined in the WS socket buffer could land a few more
authenticated operations with the rotated/revoked token before the
socket actually closed.

Fix: add a cheap in-memory 'invalidated' flag on GatewayWsClient and
mark it synchronously *before* responding in the three handlers. Add
a mirror check at the start of the per-RPC dispatch that force-closes
the client if the flag is set, regardless of whether socket.close()
has taken effect yet. Disconnect still happens via queueMicrotask so
the admin's rotate/revoke response flushes normally.

Introduces context.invalidateClientsForDevice(deviceId, opts) as a
sync companion to the existing disconnectClientsForDevice. Also
defense-in-depth: disconnectClientsForDevice now sets the flag too,
so any other caller of the hard-disconnect path gets the per-RPC
gate for free.

* test(gateway): use vi.mocked instead of direct Mock casts in devices tests

check-test-types failed on the PR because direct 'as ReturnType<typeof vi.fn>' casts from RespondFn (or the optional context methods) don't structurally overlap with the Mock type — Mock has mockImplementation/mockReturnValue that RespondFn lacks, so strict tsgo rejects the conversion. vi.mocked() is the intended helper for reinterpreting an already-mocked function, and drops through to the Mock surface cleanly.

* test(gateway): align tests with upstream type/shape changes after rebase

After rebasing onto upstream main, two test surfaces drifted:

1. GatewayRequestContextParams gained two required fields upstream
   (getRuntimeConfig, broadcastVoiceWakeRoutingChanged). The
   makeContextParams test helper was missing them, so every consumer
   tripped tsgo with a missing-field error. Add both as vi.fn()
   stubs.

2. revokeDeviceToken's return shape changed upstream from a bare
   entry record to a discriminated union {ok: true, entry: ...} | {ok:
   false, reason}. The new device.token.revoke synchronous-invalidate
   test still mocked the old shape, so the production handler took the
   !revoked.ok branch and never reached the invalidateClientsForDevice
   call the test asserted. Update the mock to the new union shape.

Also fix three new Set([...] as never) sites in server-request-
context.test.ts that produced Set<unknown> rather than Set<never>.
Move the cast outside the Set constructor so the literal stays
inferred while the wrapper is type-erased to never, which is
assignable to the Partial<GatewayRequestContextParams> clients field.

* fix(gateway): export GatewayRequestContextParams for test access

* fix(ci): resolve check-test-types and lint failures from PR #70707 branch

- server-request-context.test.ts: hasConnectedMobileNode → hasConnectedTalkNode
  (field renamed in server-request-context.ts but test fixture not updated)
- status.summary.redaction.test.ts: add configuredModel/selectedModel/
  modelSelectionReason to createRecentSessionRow fixture
  (SessionStatus gained these fields in a13468320c; test was not updated)
- video-generation-providers.live.test.ts: replace empty {} fallbacks in
  conditional spreads with undefined (oxlint 1.65.0, 5 occurrences)
- music-generation-providers.live.test.ts: same fix for 4 occurrences

Remaining CI failures (FsSafeError/Python helper, media tests, Windows ACL,
session-memory hooks) are pre-existing infra failures unrelated to this PR.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): add missing GatewayRequestContextParams fields to test fixture

chatDeltaLastBroadcastText, agentDeltaSentAt, and bufferedAgentEvents are
required fields in GatewayRequestContextParams but were absent from the
makeContextParams fixture, causing TS2322 in check-test-types.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* fix(gateway): serialize credential invalidating RPCs

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-26 23:09:56 +01:00
..
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 04:35:20 +01:00
2026-05-26 01:26:00 +01:00
2026-05-15 07:28:28 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 21:55:57 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 01:26:00 +01:00
2026-05-26 17:30:34 -04:00