Files
archy/docs/security/2.1-native-assistant-boundary.md
T

5.4 KiB

Native assistant integration (2.1 candidate)

Requires UI/UX UAT approval from the maintainer.

The dashboard Chat route loads the vendored AIUI Vue components directly. It retains the dashboard's existing KeepAlive lifetime and consent dialogs. There is no AIUI shell iframe, second createApp, second router, or second Pinia. Vite deduplicates Vue, Pinia, router and DOMPurify; the assistant shell and its styles load with the chat route. Large optional renderers retain their lazy imports. AIUI's import alias and Pinia IDs are namespaced to avoid collisions.

This is a trust-model change: reviewed AIUI application code has the same DOM, origin and privileges as the rest of the dashboard. It cannot be described as an origin-isolated application. A script execution vulnerability in reviewed native UI code would compromise that shared boundary. The protection for untrusted model and document content is prevention of active rendering, plus sandboxing of content that intentionally executes code.

The native bridge is a typed in-process request/reply adapter. It exposes the existing small context/action/content/chat inventory, never an arbitrary RPC method. It installs no window-message listener. Generated code cannot acquire this adapter by posting messages. The legacy standalone/embed transport still checks both the configured origin and exact source window. Backend permissions, rate limits, tool confirmation and fresh authorization remain authoritative; AIUI neither receives node model keys nor creates fresh authorization grants.

All rich HTML renderers sanitize output, including after math/diagram rendering. Article printing escapes its title. Generated code runs only after Run in an opaque sandbox="allow-scripts" iframe, with a restrictive CSP denying network, forms, external resources and base URLs. Console messages require that exact iframe source and opaque origin and are bounded. Website/article previews use opaque sandboxed frames; their links and frame URLs must be HTTP(S). These renderer fixes also apply to the rebuilt standalone /aiui/ entry point. Structured-card links also reject executable URL schemes. The YouTube SDK runs inside a separate opaque media frame, with fixed play/pause/seek commands and bounded state/time replies checked against that frame. It cannot execute in the native dashboard document; real provider playback still requires manual UAT.

Native AIUI keeps the existing aiui-* localStorage keys and the aiui-store, aiui-vault, aiui-favorites, and aiui-nostr-dms databases. Same-origin production installs need no copy or rekey. Existing encrypted records are authenticated before accepting an unlock; a wrong passphrase leaves ciphertext intact. The conversation component waits for that unlock. Destroying the native shell clears unlocked keys and cached decrypted chat state; tab deactivation retains it. Teardown also clears decrypted wallet-connection state and rejects delayed vault callbacks, while preserving the saved vault entry. Comparison responses and active file previews are cleared; their pending requests and callbacks are cancelled or ignored after teardown. Selected comparison models and durable conversation/settings data are retained. Pending saves capture their key before asynchronous work, and a locked writer cannot overwrite an encrypted conversation with plaintext. Skipping an unlock retains existing encrypted records and shows only available plaintext chats. Native mode does not use the standalone development file mirror. The explicit data wipe touches only AIUI data; keeping keys also keeps the vault and crypto salt. Dashboard storage and service-worker caches are not cleared. A separate development origin remains separate browser storage and requires its existing export/import mechanism if its operator wants to move it.

The native entry does not import standalone main.ts, including its PWA/cache bootstrap. Theme, settings and teleports are scoped to the native shell. The native stylesheet uses CSS @scope; supported browser/Companion qualification is part of manual UAT. The build installs the vendored workspace from its committed pnpm lockfile before building the dashboard. AIUI retains its own full strict typecheck, and the dashboard retains its stricter compiler policy through a concrete no-props/no-emits component boundary and typed request/reply unions. The Docker build reuses the AIUI builder's dependency tree. Existing /aiui/ static assets and content API paths remain available; a candidate must rebuild both entry points.

Automated acceptance covers native mounting/KeepAlive/queued asks, refusal of forged messages, broker permissions/consent, an actual browser executing hostile sandbox code, renderer payload nonexecution, and wrong/correct unlock against existing encrypted conversation/vault fixtures. A real PDF.js 6 worker renders a synthetic PDF and extracts its text, and real KaTeX 0.18 renders sanitized MathML. The app unit suite passes all 408 tests across 18 files. Exact runs are recorded with the implementation handoff. Source/fixture success is not installed-node, physical-device, artifact, release, or manual UX acceptance.

Manual draft review must check desktop/mobile layout, theme isolation, tab switch latency, draft and conversation retention, settings/history, existing vault unlock, provider setup, tool consent and fresh authorization, content surfaces, math/diagrams, article/website previews, and player behavior. No production deployment or live credential migration is authorized by this patch.