Ctrl K
ComunidadGuías…

electron/cloud-connections.node-test.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import assert from "node:assert/strict";
import test from "node:test";

import { adoptComposioId, collectConnections, ConnectionMoveError, parseConnections, releaseConnections, sendConnections } from "./cloud-connections.mjs";

const COMPUTER = { environmentId: "env-desktop-1", label: "Milind's MacBook" };
const INSTALLATION = "0f1e2d3c-4b5a-4968-8778-695a4b3c2d1e";
const D1 = "1".repeat(64), D2 = "2".repeat(64);
const linearSignIn = (refresh) => ({ url: "https://mcp.linear.app/sse", state: "signed-in", tokens: { access: `a-${refresh}`, refresh } });

/** This computer's server: its list, and the private port's answers, each ask recorded. */
function computer({ connections, answers = {}, release = () => ({ released: true }), connected = {} }) {
  const asked = [];
  return {
    asked,
    json: async (route) => (route === "/api/cloud-connections" ? { computer: COMPUTER, connections, engines: [], commands: [] } : { services: connected }),
    handoff: async (what) => {
      asked.push(what);
      if (what.kind === "connection-release") return { ok: true, release: release(what) };
      if (what.kind === "composio-share") return { ok: true, share: { code: "c".repeat(64) } };
      const answer = typeof answers[what.id] === "function" ? answers[what.id]() : answers[what.id];
      if (!answer) throw new Error("This connection could not be read on this computer.");
      return { ok: true, ...answer };
    },
  };
}

/** My Cloud's own routes over the owner session, each call recorded; `reply` answers anything not set up here. */
function cloud({ connections = [], engines = [], commands = ["npx", "node"], reply = () => ({ status: 200, body: {} }), readyAfter = 0, vaultKeys = false } = {}) {
  const calls = [];
  let reads = 0;
  return {
    calls,
    call: async (method, route, body) => {
      calls.push([method, route, body]);
      if (method === "GET" && route === "/api/cloud-connections") {
        reads++;
        return { ok: true, status: 200, body: { computer: { environmentId: "env-cloud", label: "omb-u-1" }, connections, engines: reads > readyAfter ? engines : [], commands, ...(vaultKeys ? { vaultKeys } : {}) } };
      }
      const answer = reply(method, route, body) ?? { status: 200, body: {} };
      return { ok: answer.status >= 200 && answer.status < 300, ...answer };
    },
  };
}

const writes = (target) => target.calls.filter(([method]) => method !== "GET").map(([method, route]) => `${method} ${route}`);

test("moves keys first, then MCP servers with their secrets, mailboxes and connected apps, each over My Cloud's own routes", async () => {
  const local = computer({
    connections: [
      { id: "mcp:dodo", kind: "mcp", label: "dodo", launcher: "npx" },
      { id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:aaa" },
      { id: "email", kind: "email", label: "Email" },
      { id: "key:openrouter", kind: "key", label: "OpenRouter", for: ["openrouter"] },
    ],
    answers: {
      "mcp:dodo": { connection: { mcp: { name: "dodo", server: { command: "npx", args: ["-y", "dodo"], env: { KEY: "k" }, enabled: true } } } },
      email: { connection: { email: [{ address: "ana@example.test" }] } },
      "key:openrouter": { connection: { config: { openrouter: { key: "sk-or" } } } },
    },
    connected: { gmail: { connected: true }, slack: { connected: false } },
  });
  const target = cloud({ connections: [{ id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:bbb", installationId: INSTALLATION }],
    engines: ["openrouter"], reply: (method, route) => (route === "/api/cloud-connections/connected-apps" ? { status: 200, body: { shared: true } } : undefined) });
  const progress = [];
  const result = await sendConnections(await collectConnections(local), target, { local, onProgress: (step) => progress.push(step) });
  assert.deepEqual(result.failed, []);
  assert.deepEqual(writes(target), ["PUT /api/cloud-connections/held-keys", "PATCH /api/config", "POST /api/mcp/servers", "PATCH /api/mcp/servers/dodo", "PUT /api/cloud-connections/email", "POST /api/cloud-connections/connected-apps"]);
  assert.deepEqual(result.held, [], "a Cloud with no trial credit to keep runs the key at once");
  assert.deepEqual(target.calls.find(([, route]) => route === "/api/mcp/servers")[2], { name: "dodo", command: "npx", args: ["-y", "dodo"], env: { KEY: "k" } });
  assert.deepEqual(target.calls.find(([, route]) => route === "/api/cloud-connections/connected-apps")[2], { share: "c".repeat(64), apps: ["gmail"] });
  assert.deepEqual(local.asked.find((what) => what.kind === "composio-share"), { kind: "composio-share", for: INSTALLATION });
  assert.deepEqual(target.calls.find(([, route]) => route === "/api/cloud-connections/email")[2], { accounts: [{ address: "ana@example.test" }] });
  assert.deepEqual(result.moved.map((item) => item.id), ["key:openrouter", "mcp:dodo", "email", "composio"]);
  assert.deepEqual(progress.map((step) => `${step.done}/${step.total} ${step.label}`), ["1/4 OpenRouter", "2/4 dodo", "3/4 Email", "4/4 Connected apps"]);
});

test("a trial's Cloud keeps a moved key saved but unused while its Claude credit lasts, asked before the key is saved, and the move goes on without waiting for it", async () => {
  const local = computer({
    connections: [{ id: "key:openrouter", kind: "key", label: "OpenRouter", for: ["openrouter"] }, { id: "mcp:dodo", kind: "mcp", label: "dodo", launcher: "npx" }],
    answers: {
      "key:openrouter": { connection: { config: { openrouter: { key: "sk-or" } } } },
      "mcp:dodo": { connection: { mcp: { name: "dodo", server: { command: "npx", args: ["-y", "dodo"], env: {}, enabled: true } } } },
    },
  });
  const target = cloud({ engines: [], reply: (method, route) => (route === "/api/cloud-connections/held-keys" ? { status: 200, body: { held: true } } : undefined) });
  const started = Date.now();
  const result = await sendConnections(await collectConnections(local), target, { local, waitMs: 5_000 });
  assert.ok(Date.now() - started < 2_000, "an engine kept unused is never waited for");
  assert.deepEqual(writes(target).slice(0, 2), ["PUT /api/cloud-connections/held-keys", "PATCH /api/config"]);
  assert.deepEqual(target.calls.find(([, route]) => route === "/api/cloud-connections/held-keys")[2], { for: ["openrouter"] });
  assert.deepEqual(result.held, [{ id: "key:openrouter", label: "OpenRouter" }]);
  assert.deepEqual(result.moved.map((item) => item.id), ["key:openrouter", "mcp:dodo"]);
});

test("a server that needs this computer goes marked as running on it, and a server already on My Cloud is replaced", async () => {
  const server = (name, extra = {}) => ({ connection: { mcp: { name, server: { type: "http", url: `https://${name}.example/mcp`, headers: {}, enabled: true, ...extra } } } });
  const local = computer({
    connections: [
      { id: "mcp:notes", kind: "mcp", label: "notes", runsHere: true },
      { id: "mcp:fetch", kind: "mcp", label: "fetch", launcher: "uvx" },
      { id: "mcp:lent", kind: "mcp", label: "lent" },
      { id: "mcp:docs", kind: "mcp", label: "docs" },
    ],
    answers: {
      "mcp:notes": server("notes"),
      "mcp:fetch": { connection: { mcp: { name: "fetch", server: { command: "uvx", args: ["mcp-server-fetch"], env: {}, enabled: false } } } },
      "mcp:lent": server("lent", { runsOn: { environmentId: "env-other", label: "Studio iMac" } }),
      "mcp:docs": server("docs"),
    },
  });
  const target = cloud({ connections: [{ id: "mcp:docs", kind: "mcp", label: "docs" }] });
  const result = await sendConnections(await collectConnections(local), target, { local });
  const body = (route) => target.calls.find(([, at]) => at === route)?.[2];
  const added = target.calls.filter(([method, route]) => method === "POST" && route === "/api/mcp/servers").map(([, , sent]) => [sent.name, sent.runsOn ?? null]);
  assert.deepEqual(added, [["notes", COMPUTER], ["fetch", COMPUTER], ["lent", { environmentId: "env-other", label: "Studio iMac" }]]);
  assert.deepEqual(body("/api/mcp/servers/docs"), { type: "http", url: "https://docs.example/mcp", headers: {}, enabled: true, runsOn: null });
  assert.equal(target.calls.some(([method, route]) => method === "PATCH" && route === "/api/mcp/servers/fetch"), false, "a server switched off here stays off there");
  assert.deepEqual(result.runsHere, [{ id: "mcp:notes", label: "notes" }, { id: "mcp:fetch", label: "fetch", needs: "uvx", off: true }, { id: "mcp:lent", label: "lent" }]);
  assert.deepEqual(result.moved.map((item) => item.id), ["mcp:docs"]);
});

test("a server's Vault keys go with it as pointers, and only to a Cloud that can read them", async () => {
  const item = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
  const connections = [{ id: "mcp:stripe", kind: "mcp", label: "stripe", launcher: "npx" }];
  const answers = { "mcp:stripe": { connection: { mcp: { name: "stripe", server: { command: "npx", args: ["x"], env: { KEY: `vault:${item}` }, enabled: false }, keys: [item] } } } };
  const here = computer({ connections, answers });
  const collected = await collectConnections(here);

  const newer = cloud({ vaultKeys: true });
  assert.deepEqual((await sendConnections(collected, newer, { local: here, waitMs: 0 })).failed, []);
  const added = newer.calls.find(([method, route]) => method === "POST" && route === "/api/mcp/servers");
  assert.deepEqual(added[2].vaultKeys, [item]);
  assert.equal(added[2].env.KEY, `vault:${item}`);

  const older = cloud({});
  const stayed = await sendConnections(collected, older, { local: here, waitMs: 0 });
  assert.equal(stayed.failed.length, 1);
  assert.match(stayed.failed[0].message, /update/u);
  assert.equal(stayed.failed[0].final, false);
  assert.deepEqual(writes(older), []);
});

test("a sign-in moves and this computer lets go of it; one that refreshed meanwhile goes again first", async () => {
  let refresh = "r1";
  const local = computer({
    connections: [{ id: "mcp:linear", kind: "mcp", label: "linear", signIn: true }],
    answers: { "mcp:linear": () => ({ connection: { mcp: { name: "linear", server: { type: "http", url: "https://mcp.linear.app/sse", headers: {}, enabled: true }, signIn: linearSignIn(refresh) } },
      digest: refresh === "r1" ? D1 : D2 }) },
    release: (what) => (what.digest === (refresh === "r1" ? D1 : D2) ? { released: true } : { changed: true }),
  });
  const target = cloud({ reply: (method, route) => (route.startsWith("/api/cloud-connections/mcp/linear/sign-in") ? { status: 200, body: { adopted: true } } : undefined) });
  // It refreshed here between being read and being let go of.
  const read = local.handoff;
  local.handoff = async (what) => { const answer = await read(what); if (what.kind === "connection" && refresh === "r1") refresh = "r2"; return answer; };
  const result = await sendConnections(await collectConnections(local), target, { local });
  assert.deepEqual(result.failed, []);
  assert.deepEqual(writes(target), ["POST /api/mcp/servers", "PATCH /api/mcp/servers/linear", "PUT /api/cloud-connections/mcp/linear/sign-in",
    `PUT /api/cloud-connections/mcp/linear/sign-in?replaces=${D1}`]);
  assert.equal(target.calls.at(-1)[2].tokens.refresh, "r2");
  assert.deepEqual(local.asked.filter((what) => what.kind === "connection-release"), [
    { kind: "connection-release", id: "mcp:linear", digest: D1 }, { kind: "connection-release", id: "mcp:linear", digest: D2 }]);
  assert.deepEqual(result.release, []);
});

test("My Cloud keeps a sign-in of its own; with release off the result lists what this computer still holds, for later", async () => {
  const connections = [{ id: "mcp:linear", kind: "mcp", label: "linear", signIn: true }];
  const answers = {
    "mcp:linear": { connection: { mcp: { name: "linear", server: { type: "http", url: "https://mcp.linear.app/sse", headers: {}, enabled: true }, signIn: linearSignIn("r1") } }, digest: D1 },
  };
  const keeps = computer({ connections, answers });
  const own = cloud({ connections: [{ id: "mcp:linear", kind: "mcp", label: "linear" }], reply: (method, route) => (route.includes("sign-in") ? { status: 200, body: { kept: true } } : undefined) });
  const kept = await sendConnections(await collectConnections(keeps), own, { local: keeps });
  assert.deepEqual(kept.kept.map((item) => item.id), ["mcp:linear"]);
  assert.deepEqual(kept.moved.map((item) => item.id), ["mcp:linear"], "its definition went; its sign-in there is its own");
  assert.equal(keeps.asked.some((what) => what.kind === "connection-release"), false);

  const holds = computer({ connections, answers });
  const takes = cloud({ reply: (method, route) => (route.includes("sign-in") ? { status: 200, body: { adopted: true } } : undefined) });
  const held = await sendConnections(await collectConnections(holds), takes, { local: holds, release: false });
  assert.deepEqual(held.release, [{ id: "mcp:linear", label: "linear", digest: D1 }]);
  assert.equal(holds.asked.some((what) => what.kind === "connection-release"), false);
  // A held entry of a connection kind this app does not know is dropped, never asked about.
  assert.deepEqual(await releaseConnections([...held.release, { id: "highlevel", label: "HighLevel", digest: D2 }], { local: holds, target: takes }), []);
  assert.deepEqual(holds.asked.filter((what) => what.kind === "connection-release").map((what) => what.id), ["mcp:linear"]);
});

test("one connection failing never stops the others; a refusal trying again can't fix is final", async () => {
  const local = computer({
    connections: [{ id: "key:openai", kind: "key", label: "OpenAI", for: ["openai"] }, { id: "key:groq", kind: "key", label: "Groq", for: ["groq"] },
      { id: "mcp:gone", kind: "mcp", label: "gone" }, { id: "mcp:docs", kind: "mcp", label: "docs" }],
    answers: { "key:openai": { connection: { config: { openai: { key: "k" } } } }, "key:groq": { connection: { config: { groq: { key: "g" } } } },
      "mcp:docs": { connection: { mcp: { name: "docs", server: { type: "http", url: "https://docs.example/mcp", headers: {}, enabled: true } } } } },
  });
  let config = 0;
  const target = cloud({ reply: (method, route) => {
    if (route === "/api/config") return ++config === 1 ? { status: 403, body: { error: "This workspace's AI is managed by its organization." } } : { status: 503, body: {} };
    return undefined;
  } });
  const result = await sendConnections(await collectConnections(local), target, { local, waitMs: 0 });
  assert.deepEqual(result.failed, [
    { id: "key:openai", label: "OpenAI", message: "My Cloud said: This workspace's AI is managed by its organization.", final: true },
    { id: "key:groq", label: "Groq", message: "My Cloud did not take the Groq key.", final: false },
    { id: "mcp:gone", label: "gone", message: "gone could not be read on this computer.", final: false },
  ]);
  assert.deepEqual(result.moved.map((item) => item.id), ["mcp:docs"]);
});

test("waits for My Cloud to run the engines whose keys went, before anything that follows them", async () => {
  const local = computer({ connections: [{ id: "key:openrouter", kind: "key", label: "OpenRouter", for: ["openrouter"] }, { id: "mcp:docs", kind: "mcp", label: "docs" }],
    answers: { "key:openrouter": { connection: { config: { openrouter: { key: "k" } } } },
      "mcp:docs": { connection: { mcp: { name: "docs", server: { type: "http", url: "https://docs.example/mcp", headers: {}, enabled: false } } } } } });
  const target = cloud({ engines: ["openrouter"], readyAfter: 2 });
  await sendConnections(await collectConnections(local), target, { local, waitMs: 5_000 });
  const order = target.calls.map(([method, route]) => `${method} ${route}`);
  const ready = order.lastIndexOf("GET /api/cloud-connections");
  assert.ok(ready > order.indexOf("PATCH /api/config") && ready < order.indexOf("POST /api/mcp/servers"), order.join(", "));
  assert.equal(order.filter((call) => call === "GET /api/cloud-connections").length, 3);
});

test("connected apps: the same account already, the person's own project, a Cloud not ready, and one that keeps its own", async () => {
  const here = { id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:aaa" };
  const local = computer({ connections: [], answers: { composio: { connection: { composio: { apiKey: "ck", userId: "u1" } } } }, connected: { gmail: { connected: true } } });
  const quiet = cloud();
  assert.deepEqual(await adoptComposioId(quiet, { local, here, there: { ...here, installationId: INSTALLATION } }), { shared: true });
  assert.deepEqual(quiet.calls, []);
  await assert.rejects(adoptComposioId(quiet, { local, here, there: null }), (error) => error instanceof ConnectionMoveError && error.code === "not_ready" && !error.final);

  const keeps = cloud({ reply: () => ({ status: 200, body: { kept: true, missing: ["gmail", "BAD SLUG"] } }) });
  assert.deepEqual(await adoptComposioId(keeps, { local, here: { ...here, mode: "own", account: "own:x" }, there: null }), { kept: true, missing: ["gmail"] });
  assert.deepEqual(keeps.calls[0], ["POST", "/api/cloud-connections/connected-apps", { apiKey: "ck", userId: "u1", apps: ["gmail"] }]);
});

test("a server of the person's own with no connected-apps service keeps MausBot's connected apps here for good, and still takes their own project", async () => {
  const here = { id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:aaa" };
  const local = computer({ connections: [here], answers: { composio: { connection: { composio: { apiKey: "ck", userId: "u1" } } } }, connected: { gmail: { connected: true } } });
  assert.deepEqual(parseConnections({ computer: COMPUTER, connections: [], managedApps: false }).managedApps, false);
  assert.equal(parseConnections({ computer: COMPUTER, connections: [] }).managedApps, undefined, "an Admin's Cloud says nothing: as before");
  const garage = cloud();
  await assert.rejects(adoptComposioId(garage, { local, here, there: null, managedApps: false }), (error) => error.code === "no_service" && error.final === true);
  assert.deepEqual(garage.calls, [], "nothing asked of it");
  const listing = { status: 200, body: { computer: { environmentId: "env-garage", label: "Garage server" }, connections: [], engines: [], commands: [], managedApps: false } };
  const moved = await sendConnections({ computer: COMPUTER, connections: [here] }, { call: async (method, route) => (method === "GET" && route === "/api/cloud-connections" ? { ok: true, ...listing } : { ok: true, status: 200, body: {} }) }, { local, waitMs: 0 });
  assert.deepEqual(moved.failed.map((failure) => [failure.id, failure.final]), [["composio", true]], "final: the move's check leaves it out");
  const own = cloud({ reply: () => ({ status: 200, body: { shared: true } }) });
  assert.deepEqual(await adoptComposioId(own, { local, here: { ...here, mode: "own", account: "own:x" }, there: null, managedApps: false }), { shared: true });
});

test("a Cloud too old for connections says so; one that does not answer, too; this computer must list its own", async () => {
  const local = computer({ connections: [] });
  const old = { call: async () => ({ ok: false, status: 404, body: {} }) };
  await assert.rejects(sendConnections({ computer: COMPUTER, connections: [] }, old, { local }), (error) => error.code === "outdated");
  const down = { call: async () => { throw new Error("offline"); } };
  await assert.rejects(sendConnections({ computer: COMPUTER, connections: [] }, down, { local }), (error) => error.code === "unreachable");
  await assert.rejects(collectConnections({ json: async () => ({ nope: true }) }), (error) => error.code === "local");
});

test("a server's list keeps only connections of the known shape", () => {
  const parsed = parseConnections({ computer: COMPUTER, engines: ["openrouter", "bad engine!"], commands: ["npx", "rm -rf"], connections: [
    { id: "mcp:dodo", kind: "mcp", label: "dodo", launcher: "npx", runsHere: true, extra: "x" },
    { id: "mcp:dodo", kind: "key", label: "mismatched kind" },
    { id: "../etc", kind: "mcp", label: "bad id" },
    { id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:a", installationId: "not-a-uuid" },
  ] });
  assert.deepEqual(parsed, { computer: COMPUTER, engines: ["openrouter"], commands: ["npx"], connections: [
    { id: "mcp:dodo", kind: "mcp", label: "dodo", runsHere: true, launcher: "npx" },
    { id: "composio", kind: "composio", label: "Connected apps", mode: "managed", account: "managed:a" },
  ] });
  assert.equal(parseConnections({ computer: { environmentId: "../x", label: "Mac" }, connections: [] }), null);
});