feat(dsh-plugin-browserskill): strict ownership boundary — foreign sessions are invisible

Tighten the shared-daemon boundary from 'cleanup only touches owned
sessions' to 'the plugin only ever sees and operates on sessions it
created':

- browser_session_list no longer queries the daemon at all; it returns
  the plugin's own session table (with the current marker), so foreign
  sessions cannot even be enumerated through the plugin.
- Every tool's optional session argument must name a plugin-created
  session; foreign/unknown ids are rejected with a clear error before
  any command reaches the daemon (the reference-adoption channel is
  gone).
- Unchanged: dispose stops exactly the owned set, stop requires
  ownership, the start reservation protocol, and handle-precise child
  kills.

Tests updated (59): explicit-foreign rejection without daemon contact,
registry-only listing, reservation race, stale-handle-tolerant dispose.
e2e: a manually started foreign session was rejected on reference,
absent from session_list, refused on stop, and survived dispose while
both plugin sessions were cleaned up.
This commit is contained in:
BB-fat
2026-08-14 04:12:38 +00:00
parent afdc398730
commit 3d050e0f26
6 changed files with 113 additions and 92 deletions
+12 -12
View File
@@ -44,7 +44,8 @@ const DEVICE_PRESETS = [
const SESSION_PARAM = {
type: "string",
description:
"bsk session id to act on. Omit to use the current session (the one most recently started or used).",
"bsk session id to act on; must be one created by this plugin's browser_session_start. " +
"Omit to use the current session (the one most recently started or used).",
} as const;
/** Run one bsk command and return its parsed JSON payload, or throw. */
@@ -266,8 +267,9 @@ export function registerTools(deps: ToolDeps): void {
defineTool({
name: "browser_session_list",
description:
"List active browser sessions known to the bsk daemon. The session marked `current` is " +
"the one browser_* tools act on when no explicit `session` is passed.",
"List the browser sessions created by this plugin. Sessions owned by other programs on the " +
"shared bsk daemon are not visible here. The session marked `current` is the one browser_* " +
"tools act on when no explicit `session` is passed.",
parameters: {},
output: {
schema: {
@@ -305,17 +307,15 @@ export function registerTools(deps: ToolDeps): void {
],
},
isConcurrencySafe: () => true,
async execute(_args, exec) {
const reply = (await runBsk(deps, exec, ["session", "list"], "session list")) as {
session_id: string;
browser_instance_id: string;
}[];
// Registry-only by design: no daemon call, so foreign sessions on a
// shared daemon can never even be SEEN through this tool.
async execute() {
const current = registry.current();
return {
sessions: reply.map((entry) => ({
sessionId: entry.session_id,
browserInstanceId: entry.browser_instance_id,
current: entry.session_id === current,
sessions: registry.list().map((entry) => ({
sessionId: entry.sessionId,
browserInstanceId: entry.browserInstanceId ?? "",
current: entry.sessionId === current,
})),
};
},