Repository navigation
Page: register Installation runtimes with the proxy, and name the Installation's app id (#1700) - #1729
Page: register Installation runtimes with the proxy, and name the Installation's app id (#1700)#1729michielbdejong wants to merge 3 commits into
Conversation
…lay (atomic-plugins#54) Replaces #1657's `proxy` relay op, which kept LocalThought's rotating connection code in the page and made every call for the frame. The #54 proxy has no tenant login and no connection codes (decision 6, flag day), so the relay is removed rather than kept alongside. Frame (server/src/plugins/assets/view-client.js): - generates an Ed25519 key in memory, non-extractable, on first use; fails with a clear message where WebCrypto has no Ed25519 (#1688); - asks the page for a capability (`proxyCapability` {platform, connectionId, publicKey}), caches it until 60 s before `exp`; - fetches `{aud}/proxy/{connection_id}/{platform}{path}` itself with `Authorization: Capability <payload>.<sig>` and v2 request-signature headers signed by the frame key; re-mints once on 401 `capability_expired`. `store.proxy.request(...)` keeps its signature and `{status, headers, body}` result. Page (helpers/proxyConnections.ts, AppFrame, ProxyConnectReturn): - every call to the proxy is signed v2 with the user key, as `atomic:agent:<pubkey>`: POST /connect/redeem, GET /connections, POST /connections/{id}/agents, DELETE /connections/{id}[/agents/{agent}]; - /connect without `user_id`; the PKCE verifier is the only thing kept in localStorage, for the handoff window; - after redeem, the connection is delegated to the app's agent (from GET /app-agent); the connect bar also offers an existing connection for the platform, which only adds the delegation; - mints capabilities only for a connection the user owns, of that platform, delegated to this app: claims {v:2, connection_id, platform, aud, app, cnf: atomic:agent:<frame key>, exp: now + 600 s}, payload base64url(JSON), signature by the user key over "integration-proxy-capability-v2\n" + JSON. - Apps without their own agent (installed catalog plugins) are told they cannot be given a connection yet (#54 decision 2, later). A fixed capability vector (user key of authentication_v2_vectors.json) is pinned in proxyConnections.test.ts for the proxy's tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto claude/page-runtimes
…s app id (#1700) Gap 1: the page now calls the integration proxy's runtimes routes (ontola/atomic-plugins#122), signed v2 with the user key: - POST /runtimes {app, agent, label} for each InstallationRuntime child whose genesis the named agent signed, with the Installation's integrationAppAgent as app and the node's name as label. Runs when an Installation page or app frame opens, when a runtime child appears, and after a delegation. Skips runtimes already registered in this page or listed by GET /connections for the same app and label; the proxy upserts anyway. In the background; failures are toasted. - DELETE /runtimes/{agent} on revoke and on uninstall. Gap 2: appAgentOf prefers the Installation's integrationAppAgent and only falls back to GET /app-agent (createApp apps, older Installations), so delegations and frame capabilities name the app id rather than one node's agent. Merges #1697 (claude/frame-proxy-capability), which holds appAgentOf and the v2 ProxyConnections this builds on and is not in #1725's stack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merge-risk triage (2026-09-28). This is a read-only review of this PR's own diff. The rule it applies: nothing that works today may break for existing users or clients, and new behaviour is added alongside the old. The stack is being rebased onto Verdict: SAFE-WITH-FIX (merge together with #1733) After the rebase this PR's delta should be only Fix before merging: 🤖 Generated with Claude Code |
|
Closing as part of the plugin-host stack cleanup (Q-101): not needed by atomic-plugins now. See the inventory at #1726 (comment). The branch is kept, and pin candidates are unaffected. Closed by Claude (VPS coordinator) on behalf of Michiel. |
Closes two data-browser gaps from #1700 (answers 1 and 2), stacked on #1725.
Merges #1697.
appAgentOfand the v2-signedProxyConnections(delegations, capabilities) live in #1697 (claude/frame-proxy-capability), which is not in #1725's stack (#1696 → #1702 → #1710 → #1725). This branch merges it cleanly (it touches only data-browser,browser/pluginandview-client.js), so this diff also shows #1697 until that lands. The commit of its own isc98a30233.Gap 1: the page calls
POST /runtimesNew
helpers/installationRuntimes.ts, plusruntimes(),registerRuntime()andunregisterRuntime()onProxyConnections. Every call is signed v2 with the user key through the existingcall().POST {proxy}/runtimes {app, agent, label}.appis the Installation'sintegrationAppAgentandagentthe node's agent from anInstallationRuntimechild, both canonicalatomic:agent:.labelis the child'sname, the node's device name, cut to the proxy's 200 characters.agent, notruntime: the proxy'sRuntimeBodyisdeny_unknown_fields.getCreatedBy) is the agent it names, so another drive writer can't get an agent of their choice registered. A runtime equal to the app or the owner is skipped, because the proxy refuses those.useChildren);integrationAppAgentit does nothing.GET /connections, and only runtimes the proxy doesn't list with the same app and label get posted.DELETE /runtimes/{agent}for each runtime child. On uninstall they're read before the destroy.ProxyErrormessage ("The integration proxy refused …: …").Gap 2:
appAgentOfprefersintegrationAppAgentIt reads the resource first and returns the Installation's app id.
GET /app-agentis only the fallback, forcreateAppapps and Installations from before app ids. Its callers are AppFrame's connect and "Use existing connection", and the cached agent behindhost()(capabilities anddelegated). So delegations, the pending connect'sappAgentand frame capabilities all name the app id, not the node's agent.Tests
The fake proxy mirrors atomic-plugins#122 and verifies each v2 signature over method, URL, timestamp and body hash. It refuses unknown body fields and agent = app/owner, upserts, and supports DELETE.
helpers/installationRuntimes.test.ts:chunks/AppPage/appAgent.test.ts: the preference, the fallback's signedGET /app-agent, and the error when neither side has an identity.src/helpers,src/chunks/AppPageandsrc/views/Installationpasses (68 files, 545 tests).No new UI text and no
.pochanges. The only visible change is a toast when the proxy refuses, so there are no screenshots.Not done / follow-ups
createAppapps. The page also doesn't writeintegrationConnections(answer 3) when it delegates.https://localthought.io) whenever runtime children exist, even when no connection is delegated. That's oneGET /connectionsper page load. If the proxy is down, the user sees a toast.Refs #1700, ontola/atomic-plugins#122.
🤖 Generated with Claude Code