From f9860ceeef0109f97226810378e00362fb4b6607 Mon Sep 17 00:00:00 2001 From: Lann Martin Date: Sun, 23 Aug 2026 12:52:23 -0400 Subject: [PATCH] The repo gets a README: actors, realms, and trust domains as a diagram --- README.md | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8310f1c --- /dev/null +++ b/README.md @@ -0,0 +1,178 @@ +# polyvisor + +A framework for building PWAs that inverts the standard web application +architecture: applications run client-side, as WebAssembly +component-model components, under user-controlled capability +confinement — a permissions model in the spirit of modern mobile OSes, +but cross-platform because the "OS" is a set of browser primitives the +framework composes. + +**Status: nothing here is finally decided; the entire framework is +unstable until declared otherwise.** [NOTES.md](NOTES.md) is the living +design record and the authority behind everything on this page; open +questions live in the issue tracker. + +## Trust model + +The organizing invariant: + +> **Nothing in the system is both live and trusted.** +> Trusted ⇒ static (the home origin's content, release artifacts). +> Live ⇒ untrusted by construction (relays, push services, storage +> backends, peers), covered by end-to-end crypto and capability +> confinement. + +## Actors, realms, and trust domains + +```mermaid +flowchart TB + User(["User"]) + + subgraph static ["TRUSTED ⇒ STATIC — remote"] + Pub["Framework publisher
root keys · TUF-style rotation"] + AppPub["App publishers
append-only sigchains"] + Origin["Home origin
static bytes + security headers"] + SandboxO["Sandbox origin
app-frame skeleton"] + Wit["Monitors · witnesses ·
contact-graph gossip"] + end + + subgraph device ["USER DEVICE — client TCB: browser + OS + framework release"] + Visor["Visor — main window realm
trusted pixels: strip, drawer, sheets;
consent UI outside app rectangles"] + subgraph confined ["Sandboxed — untrusted by construction"] + Frame["App UI frame
opaque-origin iframe · zero direct network"] + Apps["App components — wasm
imports = grants; the linker is
the permission system"] + Services["Data services
schema authorities over doc partitions"] + Providers["Provider components
s3 / dropbox / gdrive stores + panels
egress scoped to own backend · ciphertext only"] + end + Runtime["Runtime — SharedWorker realm, per device
device store · keystore · store-egress ·
seal/unseal (DEK under keyslots)"] + Engine["Engine composite — wasm, in TCB
automerge · keyhive/BeeKEM · subduction
one non-extractable Ed25519 device identity"] + end + + subgraph infra ["LIVE ⇒ UNTRUSTED infra — pull tier at most: may fetch, never read"] + Relay["iroh relays
realtime sync path"] + Store["Storage backends
S3 / R2 / B2 / MinIO · Dropbox · Drive
dumb ciphertext stores"] + Broker["Notification broker
keyed-tag equality match · budgeted"] + Push["Web Push service"] + OAuth["OAuth providers"] + end + + subgraph peers ["PEERS — live; trust = exactly the keys they hold"] + Own["User's other devices
user = keyhive group of device identities"] + Contacts["Contacts
other users' device-groups"] + Revoked["Revoked / stolen devices"] + end + + Pub -->|"signed release manifest"| Origin + Wit -.->|"constant-root canary checks
(detection, not prevention)"| Origin + Wit -.->|"head cosigning · gossip"| AppPub + Origin -->|"static fetch — bootstrap SW
verifies release (TOFU)"| Visor + SandboxO -->|"frame skeleton + headers"| Frame + AppPub -.->|"app versions verified against sigchain:
no fork, no rollback"| Visor + + User <-->|"ceremonies + grants: powerbox picks,
petnames, pairing SAS, unseal login"| Visor + Visor <-->|"MessagePort DOM-op protocol"| Frame + Apps -.->|"embedded UI bundle, via RPC"| Frame + Apps -->|"WIT imports
(granted capabilities)"| Engine + Services -->|"WIT imports"| Engine + Visor <-->|"engine RPC — nothing secret
crosses the port"| Runtime + Runtime -->|"hosts · seals state"| Engine + Engine -->|"store strategies"| Providers + + Providers -->|"signed PUT / GET
at unguessable names"| Store + Engine <-->|"ciphertext blobs +
membership ops — iroh QUIC"| Relay + Runtime <-->|"PKCE exchange; tokens
live in worker memory"| OAuth + Runtime -->|"opaque wake tags (HMAC-keyed)"| Broker + Broker -->|"match fires"| Push + Push -->|"service-worker wake"| Runtime + + Relay <-->|"E2E sync"| Own + Relay <--> Contacts + Store <--> Own + Store <--> Contacts + Visor <-.->|"pairing ceremony (QR + SAS)"| Own + User <-.->|"contact cards, out-of-band"| Contacts + Relay -.->|"ciphertext at most"| Revoked + Store -.->|"rotated names — nothing fetchable"| Revoked + + classDef trusted fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20 + classDef tcb fill:#e3f2fd,stroke:#1565c0,color:#0d47a1 + classDef confinedC fill:#fff3e0,stroke:#ef6c00,color:#e65100 + classDef untrusted fill:#ffebee,stroke:#c62828,color:#b71c1c + classDef peer fill:#f3e5f5,stroke:#6a1b9a,color:#4a148c + classDef actor fill:#fffde7,stroke:#f9a825,color:#f57f17 + + class Pub,AppPub,Origin,SandboxO,Wit trusted + class Visor,Runtime,Engine tcb + class Frame,Apps,Services,Providers confinedC + class Relay,Store,Broker,Push,OAuth untrusted + class Own,Contacts,Revoked peer + class User actor +``` + +Reading the diagram: + +- **Realms on the device.** The visor owns the main window (trusted + pixels: the strip, drawer, and sheets where every consequential act + happens). App UI lives in an opaque-origin sandboxed iframe with zero + direct network — all state and assets arrive over RPC. The runtime is + a SharedWorker per device hosting the engine composite; wasm guest + realms inside it split into the in-TCB engine and the confined + apps/services/providers. +- **The linker is the permission system.** A component's authority is + its import set: deny = unlinked or stubbed, prompt = the async import + suspends on consent, revoke = a defined error, never a trap. Grants + flow through the powerbox pattern — picking the thing *is* the grant. +- **Remote access tiers** use keyhive's vocabulary: *pull / read / + mutate / manage*. Infra (relays, storage, broker) sits at pull — it + may fetch ciphertext, never read it. Contacts sit at read and above, + exactly as granted: read = BeeKEM epoch keys, pull = name-keys, + write = signed operations validated at merge time. +- **The consent surface is the deliberate exception.** Mechanically it + is the most confinable component in the system, but it holds *kernel + capabilities* (grant-table write, trusted surface), granted only via + the signed-release appointment path, never via the powerbox — TCB + membership, not blast radius. +- **Static trust is detection-shaped.** The web platform has no pinning + primitive; the bootstrap service worker verifies releases after a + TOFU first visit, and monitors, witnesses, and contact-graph gossip + make targeted substitution, rollback, and freezes detectable rather + than impossible. +- **Headless compute** (the same engine at an always-on node or + provider) is a conscious powerbox decision: that host holds keys for + whatever it is granted, moving it from "infra" to "peer" in this + picture. + +## Repository layout + +| Path | Contents | +| --- | --- | +| [NOTES.md](NOTES.md) | The living design record — authoritative | +| [engine/](engine/) | The engine composite: guest crates, fetcher component, native host harness | +| [runtime/](runtime/) | Embedding runtime: engine adapter, device store, keystore, pairing engine, storage egress | +| [visor/](visor/) | The visor: curated-DOM surface, frame isolation, system UI | +| [providers/](providers/) | Storage provider strategies and config panels (common, s3, dropbox, gdrive) | +| [wit/](wit/) | Framework-owned WIT contracts (surface, panel, tasks, fetch, blobstore draft) | +| [demo/](demo/) | The reference browser embedding and its e2e suite | +| [examples/](examples/) | Example app guests (todomvc) | +| [spikes/](spikes/) | Pure archive of executed validation spikes | +| [docs/](docs/) | GitHub Pages build | + +## The substrate + +The polymorph family de-risks the bottom of the stack: + +- [polyengine](https://github.com/polymorph-components/polyengine) — + components runtime-linked on stock browsers and Deno +- [component-iroh](https://github.com/polymorph-components/polymorph-iroh) + — browser peers speaking end-to-end QUIC, one Ed25519 identity across + all paths +- [polymorph:webcrypto](https://github.com/polymorph-components/polymorph-webcrypto) + — identity keys as non-extractable platform handles behind + capability-shaped WIT +- [polymorph:tls](https://github.com/polymorph-components/polymorph-tls) + — in-guest crypto under a wasm timing-class policy +- [polymorph:test](https://github.com/polymorph-components/polymorph-test) + — cross-implementation conformance machinery + +The framework layer — the visor, the linker-as-permission-system, the +data services, and the consent UX — is what this repository builds.