Skip to content

fix(mobile): enforce local access at final transport dispatch - #5658

Closed
iscekic wants to merge 2 commits into
mobile-context-lock-758a-s2from
mobile-context-lock-758a-s3
Closed

fix(mobile): enforce local access at final transport dispatch#5658
iscekic wants to merge 2 commits into
mobile-context-lock-758a-s2from
mobile-context-lock-758a-s3

Conversation

@iscekic

@iscekic iscekic commented Aug 28, 2026

Copy link
Copy Markdown
Contributor
  • If you change accounts, switch organizations, or put the app in the background, pending chat and session actions cannot start afterward.
  • After an account change, Quick Chat, session history, and the active session list ignore results from the previous account.
  • Quick Chat can save sent messages and received replies to the original conversation when you switch organizations or put the app in the background.
  • Quick Chat removes messages that fail before sending instead of keeping them in the conversation or saved history.

Summary

The software development kit (SDK) adds optional captureActionAdmission to UserWebConnectionConfig and UserWebConnection, binding UserWebActionAdmission to UserWebActionTarget before waits.
Both SendCommandOptions and SendCommandToConnectionInput accept this local proof; senders validate it immediately before sending without changing the wire format.
Existing connections without hooks keep unrestricted commands, while guarded connections reject unclassified commands and require retries to preserve the original proof.

Files
  • packages/cloud-agent-sdk/src/user-web-connection.ts — Source, M (modified), 162 changed lines; adds frozen admission handles and a registry specific to each connection. Matches the command, session, and connection before waiting, then asserts the captured authority immediately before sending. Requires admission for send_message, send_command, interrupt, question_reply, question_reject, permission_respond, suggestion_accept, suggestion_dismiss, create_session, and exit_cli. Leaves list_models, list_commands, list_directories, and subscriptions outside action admission. Captures omitted proof at sender entry, but never puts proof in the wire frame or mutationId. Handles serialization, admission, and socket-send failures by rejecting the command, clearing its timer and pending entry, and releasing its retain.
  • packages/cloud-agent-sdk/src/index.ts — Source, M (modified), 3 changed lines; makes SendCommandOptions, UserWebActionAdmission, and UserWebActionTarget available from the public SDK entry point.
  • packages/cloud-agent-sdk/src/user-web-connection.test.ts — Test, M (modified), 340 changed lines; expands the connection admission tests.

MobileActionAdmission gives new mutations a foreground lease; AcceptedWorkReceipt permits dispatched quick-chat-turn and app-store-purchase completion under the original account and organization.
quickChat.appendMessages now requires localAccessReceipt; kiloPass.completeAppStorePurchase still accepts older StoreKit callers without it and retains backend verification.
Queries and activeSessions.createWebTicket need ownership; user.registerPushToken does too, while user.unregisterPushToken and user.revokeCurrentDeviceSession can also run during sign-out cleanup.

Files
  • apps/mobile/src/lib/local-access-transport.ts — Source, A (added), 316 changed lines; introduces shared checks for credential ownership, foreground admission, and accepted completion. Validates authentication epochs, credential generations, and known user identities while allowing bootstrap reads before account restoration finishes. Uses registries to reject copied admissions and receipts, and issues receipts only after synchronous dispatch returns. Completion checks the original owner, organization, work kind, and applicable work identifier without requiring the current foreground lease or unlock grant. Quick Chat completion must match the first message's clientId; supplied mutation admission must match the request's account and organization. Captures admission when a mutation caller omits it. Adds a mandatory mobile connection wrapper that checks ownership around token waits and event delivery, records session scopes, and clears them on destruction. Imports the narrow SDK connection entry point and recovers typed denials from Error.cause.
  • apps/mobile/src/lib/local-access-transport.test.ts — Test, A (added), 373 changed lines; introduces tests for transport admission and completion rules.

TransportOperation captures localAccessOwner and localAccessAdmission before authentication waits; trpcClient now sends mutations individually instead of batching them.
Query batches require one authentication epoch and credential generation; skipBatch still requests a single operation.
deadlineFetch keeps its deadline and abort contract; transport assertions run after artificial latency, and expired ownership produces LocalAccessDeniedError before dispatch or result delivery.

Files
  • apps/mobile/src/lib/trpc.ts — Source, M (modified), 235 changed lines; replaces shared delegates with a delegate for each mutation and query batches for each owner. Rechecks ownership around token acquisition, stored expiry reads, refreshes, and observable delivery. Accepts token rotation within the captured credential generation but prevents requests from using a replacement account. Places the final dispatch assertion after test latency and the cancellation check, while preserving deadline extension, caller abort reasons, and client metadata. Keeps the library observable's pipe and teardown behavior. Tracks cancelled batch members in a weak registry until release and removes empty batches for stale owners.
  • apps/mobile/src/lib/trpc.test.ts — Test, M (modified), 660 changed lines; revises request tests for owner checks and separate mutation requests.

MobileConnectionConfig requires captureActionAdmission, and useUserWebConnection returns MobileUserWebConnection with owner and setSessionScope.
commandScopeSchema gives explicit orgId precedence over the session scope and ready organization selection; unresolved targets fail.
UserWebConnectionProvider destroys stale sockets and remounts consumers when ownership changes, but organization changes and StrictMode cleanup retain a reusable connection.

Files
  • apps/mobile/src/components/agents/user-web-connection-provider.tsx — Source, M (modified), 109 changed lines; subscribes to published owners and creates a connection for each owner. Sends ticket requests with the captured owner and keeps the latest organization selection in a ref for action capture. Rejects commands without a resolved target organization. Invalidates the old connection synchronously during owner publication rather than waiting for React's replacement commit. Uses the account, authentication epoch, and credential generation as the provider key. Ordinary cleanup unsubscribes and releases the retain so StrictMode can replay the effect.
  • apps/mobile/src/components/agents/user-web-connection-provider.mounted.test.tsx — Test, M (modified), 320 changed lines; revises mounted tests for the provider's owner-bound connection.

CreateMobileAgentSessionManagerOptions now requires MobileUserWebConnection, so session reads, tickets, attachment caches, and failures retain their captured account owner.
Personal and organization calls to sendMessage, interruptSession, answerQuestion, rejectQuestion, and answerPermission carry admission.
prepareSession saves admission for initiateFromPreparedSession in resolution order; missing or expired admission prevents initiation, and owner replacement destroys the manager.

Files
  • apps/mobile/src/components/agents/mobile-session-manager.ts — Source, M (modified), 162 changed lines; takes ownership from the connection instead of a later global account. Checks ownership around session resolution, snapshot reads, history pages, authentication waits, and stream-ticket responses. Keeps session-load retries with that owner and records each loaded or resolved session's organization through setSessionScope. Prevents stale attachment callbacks from writing caches. Adds admission to personal and organization mutations, and queues preparation admissions by completion order when requests share a session identifier. Initiation consumes the corresponding queued admission rather than capturing another lease. Destruction clears the queue and owner subscription; stale failures stop silently, while local-access denials propagate without a generic toast.
  • apps/mobile/src/components/agents/mobile-session-manager.local-access.test.ts — Test, A (added), 334 changed lines; introduces session-manager admission tests.
  • apps/mobile/src/components/agents/mobile-session-manager.test.ts — Test, M (modified), 37 changed lines; revises existing session-manager tests for captured ownership.

createCliLiveTransport and createRemoteSessionOnConnection capture create_session authority once and pass it to both the extended attempt and compatibility retry.
A retry therefore cannot acquire permission from a later context, and connection objects without capture keep their existing arguments.
Only the delivered invalid create_session command error permits one bare retry; clone requests never use that fallback.

Files
  • packages/cloud-agent-sdk/src/cli-live-transport.ts — Source, M (modified), 29 changed lines; carries local command options through the session sender. Requires a connected command-line interface (CLI) owner before admission capture and forwards the same admission to the bare retry. Preserves separate mutation identities and omits extra arguments when callers provide no local options.
  • packages/cloud-agent-sdk/src/create-session.ts — Source, M (modified), 11 changed lines; extends the connection input with optional admission capture. Captures proof before the extended request and includes it again on the bare request, preserving distinct :ext and :bare mutation identities.
  • packages/cloud-agent-sdk/src/cli-live-transport.local-access.test.ts — Test, A (added), 379 changed lines; introduces local-admission tests for the live transport.
  • packages/cloud-agent-sdk/src/create-session.test.ts — Test, M (modified), 18 changed lines; adds checks for admission reuse during session creation.

QuickChatCompletionInput makes admission, turnId, and onDispatch mandatory; useQuickChat.onSend resolves Promise<AcceptedWorkReceipt> when the fetch call returns, before its response.
quickChat.getOrCreateThread runs on send rather than mount, and quickChat.appendMessages uses the dispatched turn's proof instead of requesting new foreground permission.
Dispatched turns can finish saving to their original organization after backgrounding or context changes; account replacement blocks both saving and visible updates.

Files
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.ts — Source, M (modified), 44 changed lines; validates the organization and cancellation signal before calling fetch. Issues the dispatch receipt only after that call returns, then checks ownership after the response, before each content delta, and at completion. Keeps the existing streaming request free of tools.
  • apps/mobile/src/components/quick-chat/use-quick-chat.ts — Source, M (modified), 385 changed lines; keys history and local state by user, authentication epoch, credential generation, and organization. Waits for a ready authenticated context before showing history, and prevents stale pages, errors, or loading callbacks from updating the visible scope. Moves thread creation into the send flow and revalidates admission after thread creation and token acquisition. Separates the dispatch promise from streaming completion, removes turns without receipts, and completes each dispatched turn at most once for its original organization. Stops streams on explicit stop, scope replacement, and unmount; restricts refetches, notices, and visible updates to the current scope. Propagates local-access denials without a generic toast and uses the Promise constructor for Hermes support. Adds a line-count exception so paging and turn completion keep one ownership boundary.
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.local-access.test.ts — Test, A (added), 184 changed lines; introduces gateway admission tests.
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.test.ts — Test, M (modified), 49 changed lines; supplies the new completion inputs in existing gateway tests.
  • apps/mobile/src/components/quick-chat/use-quick-chat.local-access.test.ts — Test, A (added), 339 changed lines; introduces tests for Quick Chat admission and completion.

ActiveSessionsLiveSync requires CreateLiveSyncOptions.owner and checks that owner around every query and queued cache update.
Ownership loss detaches subscriptions, cancels pending queries, and releases the retained connection before stale work can update the cache.
Callers keep context-specific query keys, serialized refreshes, enrichment, reconnect behavior, and manual refresh.

Files
  • apps/mobile/src/lib/active-sessions-live-sync.ts — Source, M (modified), 43 changed lines; wraps queries and queued writes with ownership checks before and after waits. Detaches on owner replacement, clears pending refresh reasons, and treats repeated detach calls as no-ops. Adds a line-count exception to keep the serialized refresh state machine together.
  • apps/mobile/src/lib/active-sessions-live-sync-mount.tsx — Source, M (modified), 8 changed lines; supplies the connection's owner when creating synchronization. Preserves the standing retain that keeps the socket open across organization changes.
  • apps/mobile/src/lib/active-sessions-live-sync.attention.test.ts — Test, M (modified), 8 changed lines; supplies captured ownership to the attention tests.
  • apps/mobile/src/lib/active-sessions-live-sync.departure.test.ts — Test, M (modified), 5 changed lines; supplies captured ownership to the departure tests.
  • apps/mobile/src/lib/active-sessions-live-sync.enrichment.test.ts — Test, M (modified), 36 changed lines; revises enrichment tests for owner-bound synchronization.
  • apps/mobile/src/lib/active-sessions-live-sync.manual-refresh.test.ts — Test, M (modified), 9 changed lines; passes the owner in manual-refresh tests.
  • apps/mobile/src/lib/active-sessions-live-sync.ownership.test.ts — Test, A (added), 117 changed lines; introduces tests for synchronization after ownership changes.
  • apps/mobile/src/lib/active-sessions-live-sync.pending.test.ts — Test, M (modified), 40 changed lines; revises pending-refresh tests for captured ownership.
  • apps/mobile/src/lib/active-sessions-live-sync.race.test.ts — Test, M (modified), 7 changed lines; passes the owner in synchronization race tests.
  • apps/mobile/src/lib/active-sessions-live-sync.reconnect.test.ts — Test, M (modified), 29 changed lines; revises reconnect tests for owner-bound synchronization.
  • apps/mobile/src/lib/active-sessions-live-sync.test-helpers.ts — Test, M (modified), 25 changed lines; supplies ownership through the shared synchronization helpers.
  • apps/mobile/src/lib/active-sessions-live-sync.test.ts — Test, M (modified), 31 changed lines; updates core synchronization tests to pass the owner.

Tests: 6 added files and 15 modified files (21 total). Added (6): mobile-session-manager.local-access.test.ts, quick-chat-gateway.local-access.test.ts, use-quick-chat.local-access.test.ts, active-sessions-live-sync.ownership.test.ts, local-access-transport.test.ts, cli-live-transport.local-access.test.ts. Modified (15): mobile-session-manager.test.ts, user-web-connection-provider.mounted.test.tsx, quick-chat-gateway.test.ts, active-sessions-live-sync.attention.test.ts, active-sessions-live-sync.departure.test.ts, active-sessions-live-sync.enrichment.test.ts, active-sessions-live-sync.manual-refresh.test.ts, active-sessions-live-sync.pending.test.ts, active-sessions-live-sync.race.test.ts, active-sessions-live-sync.reconnect.test.ts, active-sessions-live-sync.test-helpers.ts, active-sessions-live-sync.test.ts, trpc.test.ts, create-session.test.ts, user-web-connection.test.ts.
Generated: 0 generated files.


Verification

  • No manual runtime paths were tested for level 3; full iOS and Android verification runs on the final stack level.

Runtime verification remains bot-e2e, not human delegation.

Visual Changes

Visual Changes: N/A

Reviewer Notes

Human steps

No human steps are required before merge or after merge.

Automated evidence

  • The handoff reports 206 passing focused tests for the software development kit.
  • The final mobile checks passed 161 tests across 17 suites and all six scoped checks.
  • These results are automated evidence, not manual device verification.

Scope

  • Repository: Kilo-Org/cloud.
  • Worktree: /Users/igor/Projects/.worktrees/mobile-context-lock-758a.
  • Review range: mobile-context-lock-758a-s2...mobile-context-lock-758a-s3.
  • This description covers level 3 of eight planned levels; levels 1–5 now have PRs, and levels 6–8 remain unfinished.
  • The change contains 33 files, with 4,047 insertions and 800 deletions; each file's size counts added and deleted lines.

Notes

This level adds transport admission and ownership boundaries without exposing biometric controls. Full iOS and Android verification runs on the final stack level.

Device verification remains bot-e2e, not human delegation.

Stacked PRs — merge bottom to top. Each level shows only its own diff.

Runtime verification (E2E, user advocacy, simplify) runs on the tip PR over every level.
Every level keeps its own checks, its own bot review, and its own threads; each one is answered on its own PR.
Each level is its own deliverable: it builds and passes its own checks alone.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.

  1. mobile-context-lock-758afeat(mobile): add account-owned local access state #5642
  2. mobile-context-lock-758a-s2fix(mobile): bind restored context and drafts to account scope #5651
  3. mobile-context-lock-758a-s3fix(mobile): enforce local access at final transport dispatch #5658 ← this PR
  4. mobile-context-lock-758a-s4fix(mobile): bind Kilo Chat effects to local access #5664
  5. mobile-context-lock-758a-s5feat(mobile): protect native privacy and accessibility boundaries #5683 (tip)

@kilo-code-bot

kilo-code-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (33 files)
  • apps/mobile/src/components/agents/mobile-session-manager.local-access.test.ts
  • apps/mobile/src/components/agents/mobile-session-manager.test.ts
  • apps/mobile/src/components/agents/mobile-session-manager.ts
  • apps/mobile/src/components/agents/user-web-connection-provider.mounted.test.tsx
  • apps/mobile/src/components/agents/user-web-connection-provider.tsx
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.local-access.test.ts
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.test.ts
  • apps/mobile/src/components/quick-chat/quick-chat-gateway.ts
  • apps/mobile/src/components/quick-chat/use-quick-chat.local-access.test.ts
  • apps/mobile/src/components/quick-chat/use-quick-chat.ts
  • apps/mobile/src/lib/active-sessions-live-sync-mount.tsx
  • apps/mobile/src/lib/active-sessions-live-sync.attention.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.departure.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.enrichment.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.manual-refresh.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.ownership.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.pending.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.race.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.reconnect.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.test-helpers.ts
  • apps/mobile/src/lib/active-sessions-live-sync.test.ts
  • apps/mobile/src/lib/active-sessions-live-sync.ts
  • apps/mobile/src/lib/local-access-transport.test.ts
  • apps/mobile/src/lib/local-access-transport.ts
  • apps/mobile/src/lib/trpc.test.ts
  • apps/mobile/src/lib/trpc.ts
  • packages/cloud-agent-sdk/src/cli-live-transport.local-access.test.ts
  • packages/cloud-agent-sdk/src/cli-live-transport.ts
  • packages/cloud-agent-sdk/src/create-session.test.ts
  • packages/cloud-agent-sdk/src/create-session.ts
  • packages/cloud-agent-sdk/src/index.ts
  • packages/cloud-agent-sdk/src/user-web-connection.test.ts
  • packages/cloud-agent-sdk/src/user-web-connection.ts

Reviewed by grok-4.6 · Input: 377.2K · Output: 26.6K · Cached: 795K

Review guidance: REVIEW.md from base branch mobile-context-lock-758a-s2

@iscekic

iscekic commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Retired. The owner cancelled this section and restarted the work with a tighter brief. The biometric gate scope grew into a full native-action admission audit; the replacement covers initial app unlock only.

@iscekic iscekic closed this Aug 29, 2026
@iscekic
iscekic deleted the mobile-context-lock-758a-s3 branch August 29, 2026 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant