a plugin websocket targets a sidecar, never a port a manifest picked
The fixed-port form shipped this morning and lasted about an hour. The owner asked
whether declaring a port was safe, and it is not: nothing stopped a manifest naming
a port it does not own, so `websocket: { port: 5432 }` plus a grant would have been
a raw TCP relay onto Postgres — authenticated by the platform, available to anyone
that plugin was granted to. Port 22 and officer's own port are the same sentence.
The relay checked that the HOST was loopback and I mistook that for having checked
anything about the port. They are different questions and only the second one
matters: loopback is exactly where everything worth reaching already is.
So the only form is `{ sidecar }`. A sidecar's port is trustworthy for a reason a
declaration can never be — the platform watched it arrive at registration, so the
association between a port and a plugin is observed rather than asserted. The same
distinction that decides the delegation problem in todo/agent-coordination: a claim
is not evidence, whoever is making it.
The cost is that a plugin wanting a socket needs a sidecar. That is not ceremony,
it is the thing that makes the port mean anything. It was added as a shortcut for
Minesweeper, whose x11vnc listens on a known port — which is precisely the case
that looked harmless and generalised into a hole.
Nothing had used it. Minesweeper is still whole in the platform and its extraction
had not started.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -9,13 +9,13 @@ import { snapshotPlugins } from '@@/plugins/mount';
|
||||
line-oriented sidecar without knowing which is which. The moment this returned a scheme or a path, the
|
||||
relay would have to care what it was carrying.
|
||||
|
||||
Two forms, because two things genuinely differ:
|
||||
The target is always a SIDECAR. A fixed-port form was written and removed the same day: nothing stops a
|
||||
manifest naming a port it does not own, so `{ port: 5432 }` plus a grant would be a raw TCP relay onto
|
||||
Postgres for anyone that plugin reaches. Verifying the host is loopback is not verifying the port belongs
|
||||
to the plugin, and only the second question matters.
|
||||
|
||||
{ port: 5900 } a fixed port a plugin's own service listens on — `x11vnc` for a desktop, or
|
||||
anything the plugin starts itself and knows the number of in advance.
|
||||
{ sidecar: 'name' } resolved at connect time, because a sidecar binds an EPHEMERAL port and announces
|
||||
it. A manifest cannot know that number, which is why the indirection exists rather
|
||||
than being a convenience.
|
||||
A sidecar's port is different in kind, not degree: the platform watched it arrive at registration, so the
|
||||
association is observed rather than asserted.
|
||||
|
||||
**Host is always loopback and is not configurable.** A plugin socket that could name an arbitrary host
|
||||
would be a request-forgery primitive handed to every plugin author and reachable by anyone the plugin is
|
||||
@@ -32,8 +32,6 @@ export async function pluginWsTargetFor(appName: string): Promise<PluginWsTarget
|
||||
const socket = state?.plugin.manifest.websocket;
|
||||
if (!socket) return null;
|
||||
|
||||
if ('port' in socket) return { host: '127.0.0.1', port: socket.port };
|
||||
|
||||
// A sidecar that has not announced its port yet is indistinguishable from one that never will, and both
|
||||
// are correctly a refusal — there is nothing to relay onto. The caller says "not accepting connections",
|
||||
// which is true either way.
|
||||
|
||||
Reference in New Issue
Block a user