OXYGENHUB

Browser runners: a tab runs WASM jobs issue #80 open andymccall opened this · 1 comment

andymccall

A page on the hub turns the tab into a WASM-tier runner (issue #75) in a Web Worker: WASI through a shim, OPFS for files, outputs uploaded as for any runner, the key kept non-extractable in WebCrypto; trust class anonymous unless signed in as a member (device). Closing or hiding the tab drains it (issue #76). Mostly the demonstration that handover and spot checks hold for the least reliable runner of all. Design: docs/handover.md §10.

andymccall set labels feature ·

andymccall edited ·

andymccall referenced by change 39e737fbc7a9 on main ·

andymccall

First part built (hub, goes out with 0.9.15): Run in this tab, /OWNER/NAME/flow/tab, linked from Flow. It lists the pipeline's WASM jobs on a bookmark; a Web Worker (/static/wasi-worker.js) fetches the bookmark's zip once, unpacks it in memory (central directory, stored and deflate-raw via DecompressionStream), and runs each job's modules with an in-memory WASI preview 1 shim: /src and . preopened, the job's args and env (PWD=/src), stdout/stderr streamed by line, files writable in memory, unknown imports answer ENOSYS, * module patterns resolved as flow does. Checked in Node against oxygenflow's .flow/checks.wasm: layout, todos, size and summary give flow's output and exit codes. Nothing is claimed or reported yet.

What is left, in order:

  1. Register a tab as a runner. A signed-in member presses Offer this tab; the page makes an Ed25519 key in WebCrypto (non-extractable) and the hub registers a runner for the member's own repositories with label browser, tier wasm only, trust class device (anonymous would need issue #79 first). The browser cannot build an oxy Identity object itself, so the hub makes it from the raw public key and a name, and signs nothing on the tab's behalf.
  2. Claim and run. The worker polls /api/v1/flow/claim with runtimes: ["wasm"], fetches the job's state as a zip by its state hash (a new archive?state= the claim's token may read, scoped to the job's scope), runs it, sends log batches and finishes with exit code, duration and peak memory.
  3. Receipts. The receipt's canonical encoding is Rust (flow_core::receipt); rather than port it, the hub hands the tab the bytes to sign (the receipt it would expect, canonical), the tab signs them with its WebCrypto key, and the hub checks the signature against the registered key as for any runner.
  4. Drain. visibilitychange to hidden and pagehide leave (issue #76): hand the job back; a tab never holds a lease past being hidden.
  5. Limits. A memory limit by checking the module's memory after each growth is not possible from JS; cap it by refusing modules whose declared maximum exceeds the sandbox's memory-limit, and say so.