1853 lines · 60.6 KB · TypeScript
RawDownload
import { describe, it, expect } from "@effect/vitest"; import {  parseScope,  ownerPartitionKey,  vaultV1ObjectName,  vaultV1LegacyObjectName,  vaultV2ObjectName,  oauthClientDedupKey,  serializeOAuthScopes,  migratePolicyPattern,  migrateOpenApiAuthTemplate,  API_KEY_TEMPLATE_SLUG,  migrateGrant,  migrateExpiresAt,  SYNTHETIC_CLIENT_CREDENTIALS_TTL_MS,  migrateOpenApiSourceConfig,  migrateSourceAuth,  classifyBindingSlot,  dedupeOAuthClients,  oauthClientSlugKey,  planIntegrationRow,  planConnectionRow,  migratedItemId,  migrateMcpSourceConfig,  migrateGraphqlSourceConfig,  OAUTH_TEMPLATE_SLUG,  planMigration,  buildV1RuntimeMetadataIndex,  migrateV1PluginStorageRuntimeRow,  migrateV1ToolAnnotations,} from "./migration-spec";import type { MigrationInput, MigratedSourceConfig } from "./migration-spec"; describe("parseScope", () => {  it("maps a bare org scope to owner=org, empty subject", () => {    expect(parseScope("org_01KRFBFKMP")).toEqual({      owner: "org",      subject: "",      tenant: "org_01KRFBFKMP",    });  });   it("maps a user-org scope to owner=user with subject + tenant", () => {    expect(parseScope("user-org:user_01ABC:org_01XYZ")).toEqual({      owner: "user",      subject: "user_01ABC",      tenant: "org_01XYZ",    });  });   it("fails loud (null) on unknown shapes rather than mis-owning", () => {    expect(parseScope("user_01ABC")).toBeNull(); // bare user, no org — not a v2 shape    expect(parseScope("local-folder-hash")).toBeNull();    expect(parseScope("user-org:org_01XYZ")).toBeNull(); // missing user segment    expect(parseScope("user-org:user_01:org_02:extra")).toBeNull(); // too many segments    expect(parseScope("org_01:trailing")).toBeNull(); // org with a colon    expect(parseScope("")).toBeNull();  });}); describe("ownerPartitionKey", () => {  it("collapses org apps across the org, keeps user apps per-user", () => {    expect(ownerPartitionKey({ owner: "org", subject: "", tenant: "org_X" })).toBe("org:org_X");    expect(ownerPartitionKey({ owner: "user", subject: "user_U", tenant: "org_X" })).toBe(      "user:user_U:org_X",    );  });}); describe("vault object naming", () => {  it("v1 name carries the scope segment + url-encodes both parts", () => {    expect(vaultV1ObjectName("executor", "user-org:user_U:org_O", "sec_a/b")).toBe(      "executor/user-org%3Auser_U%3Aorg_O/secrets/sec_a%2Fb",    );  });   it("v1 legacy name leaves the segments un-encoded (the 404 fallback)", () => {    expect(vaultV1LegacyObjectName("executor", "org_X", "sec_a")).toBe(      "executor/org_X/secrets/sec_a",    );  });   it("v2 name drops the scope segment (flat namespace)", () => {    expect(vaultV2ObjectName("executor", "item_a/b")).toBe("executor/secrets/item_a%2Fb");  });   it("v1 and v2 names differ → id-reuse is impossible (the whole reason to re-key)", () => {    const scope = "org_X";    const id = "sec_1";    expect(vaultV1ObjectName("executor", scope, id)).not.toBe(vaultV2ObjectName("executor", id));  });}); describe("oauthClientDedupKey", () => {  it("merges identical (partition, clientId, tokenEndpoint), distinguishes any difference", () => {    const a = oauthClientDedupKey("org:org_X", "cid", "https://t/token");    const b = oauthClientDedupKey("org:org_X", "cid", "https://t/token");    const c = oauthClientDedupKey("user:u:org_X", "cid", "https://t/token");    expect(a).toBe(b);    expect(a).not.toBe(c);  });}); describe("serializeOAuthScopes", () => {  it("space-joins, de-dupes order-preserving, drops empties", () => {    expect(serializeOAuthScopes(["data", "api", "data", ""])).toBe("data api");    expect(serializeOAuthScopes(["vanta-api.all:read", "vanta-api.vendors:read"])).toBe(      "vanta-api.all:read vanta-api.vendors:read",    );    expect(serializeOAuthScopes([])).toBe("");  });}); describe("migratePolicyPattern", () => {  const M = new Map([    ["github_v3_rest_api", "github"], // a rename    ["microsoft_graph", "microsoft_graph"], // no-op slug    ["dealcloud_api", "dealcloud_api"],  ]);   it("universal pattern passes through", () => {    expect(migratePolicyPattern("*", M)).toEqual({ kind: "ok", pattern: "*" });  });   it("static namespaces pass through verbatim", () => {    expect(migratePolicyPattern("executor.openapi.addSource", M)).toEqual({      kind: "static",      pattern: "executor.openapi.addSource",    });    expect(migratePolicyPattern("openapi.addSource", M)).toEqual({      kind: "static",      pattern: "openapi.addSource",    });  });   it("whole-integration (`slug.*`) only remaps the slug — trailing * already a subtree", () => {    expect(migratePolicyPattern("dealcloud_api.*", M)).toEqual({      kind: "ok",      pattern: "dealcloud_api.*",    });    expect(migratePolicyPattern("github_v3_rest_api.*", M)).toEqual({      kind: "ok",      pattern: "github.*",    });  });   it("exact / subtree patterns insert the owner+connection wildcards", () => {    expect(migratePolicyPattern("microsoft_graph.meEvent.meEventsEventCancel", M)).toEqual({      kind: "ok",      pattern: "microsoft_graph.*.*.meEvent.meEventsEventCancel",    });    expect(migratePolicyPattern("github_v3_rest_api.repos.deleteAccessRestrictions", M)).toEqual({      kind: "ok",      pattern: "github.*.*.repos.deleteAccessRestrictions",    });    expect(migratePolicyPattern("microsoft_graph.meCalendar.*", M)).toEqual({      kind: "ok",      pattern: "microsoft_graph.*.*.meCalendar.*",    });  });   it("an unknown first segment is flagged DEAD (source removed) — never silently dropped", () => {    expect(migratePolicyPattern("api_githubcopilot_com.delete_file", M)).toEqual({      kind: "dead",      slug: "api_githubcopilot_com",    });  });}); describe("plugin runtime metadata migration", () => {  it("stamps MCP tool annotations from the legacy binding without changing the Executor slug", () => {    const index = buildV1RuntimeMetadataIndex([      {        scopeId: "org_X",        pluginId: "mcp",        collection: "binding",        key: "axiom_mcp.querydataset",        data: {          namespace: "axiom_mcp",          toolId: "axiom_mcp.querydataset",          binding: {            toolId: "querydataset",            toolName: "queryDataset",            annotations: { title: "Query dataset", readOnlyHint: true },          },        },      },    ]);     const annotations = migrateV1ToolAnnotations(      {        scopeId: "org_X",        sourceId: "axiom_mcp",        pluginId: "mcp",        name: "querydataset",        annotations: null,      },      index,    );     expect(annotations).toEqual({      requiresApproval: false,      mcp: {        toolName: "queryDataset",        upstream: { title: "Query dataset", readOnlyHint: true },      },    });  });   it("keeps already-stamped MCP annotations unchanged for idempotent re-runs", () => {    const annotations = {      requiresApproval: true,      mcp: { toolName: "deleteDataset", upstream: { destructiveHint: true } },    };     expect(      migrateV1ToolAnnotations(        {          scopeId: "org_X",          sourceId: "axiom_mcp",          pluginId: "mcp",          name: "deletedataset",          annotations,        },        buildV1RuntimeMetadataIndex([]),      ),    ).toBe(annotations);  });   it("rewrites v1 OpenAPI operation storage to the v2 catalog-owned shape", () => {    expect(      migrateV1PluginStorageRuntimeRow({        scopeId: "user-org:user_U:org_X",        pluginId: "openapi",        collection: "operation",        key: "vercel_api.dns.getRecords",        data: {          toolId: "vercel_api.dns.getRecords",          sourceId: "vercel_api",          binding: { method: "get", pathTemplate: "/v4/domains/{domain}/records" },        },      }),    ).toEqual({      pluginId: "openapi",      collection: "operation",      key: "vercel_api.dns.getRecords",      data: {        integration: "vercel_api",        toolName: "dns.getRecords",        binding: { method: "get", pathTemplate: "/v4/domains/{domain}/records" },      },      owner: "catalog",    });  });   it("rewrites v1 GraphQL operation storage and normalizes graphql-greenfield ids", () => {    expect(      migrateV1PluginStorageRuntimeRow({        scopeId: "org_X",        pluginId: "graphql-greenfield",        collection: "operation",        key: "graphql_api.query.hello",        data: {          toolId: "graphql_api.query.hello",          sourceId: "graphql_api",          binding: { kind: "query", fieldName: "hello", operationString: "query { hello }" },        },      }),    ).toEqual({      pluginId: "graphql",      collection: "operation",      key: "graphql_api.query.hello",      data: {        integration: "graphql_api",        toolName: "query.hello",        binding: { kind: "query", fieldName: "hello", operationString: "query { hello }" },      },      owner: "catalog",    });  });   it("keeps source-owned plugin storage rows source-owned", () => {    expect(      migrateV1PluginStorageRuntimeRow({        scopeId: "org_X",        pluginId: "onepassword",        collection: "settings",        key: "config",        data: { vaultId: "vault_123" },      }),    ).toEqual({      pluginId: "onepassword",      collection: "settings",      key: "config",      data: { vaultId: "vault_123" },      owner: "source",    });  });}); describe("migrateOpenApiAuthTemplate", () => {  it("maps a single Bearer apiKey header to one apiKey method (prefix preserved)", () => {    const r = migrateOpenApiAuthTemplate({      headers: {        Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " },      },    });    expect(r.authenticationTemplate).toEqual([      {        slug: API_KEY_TEMPLATE_SLUG,        type: "apiKey",        headers: { Authorization: ["Bearer ", { type: "variable", name: "token" }] },      },    ]);    expect(r.slotToTemplateSlug).toEqual({ "header:authorization": API_KEY_TEMPLATE_SLUG });    expect(r.slotToVariable).toEqual({ "header:authorization": "token" });    expect(r.staticHeaders).toEqual({});  });   it("a prefix-less apiKey header renders a bare [token]", () => {    const r = migrateOpenApiAuthTemplate({      headers: { "X-Api-Key": { kind: "binding", slot: "header:x-api-key" } },    });    expect(r.authenticationTemplate[0]).toEqual({      slug: API_KEY_TEMPLATE_SLUG,      type: "apiKey",      headers: { "X-Api-Key": [{ type: "variable", name: "token" }] },    });  });   it("a query-param api key lands in queryParams, not headers", () => {    const r = migrateOpenApiAuthTemplate({      queryParams: { key: { kind: "binding", slot: "query_param:key" } },    });    expect(r.authenticationTemplate[0]).toEqual({      slug: API_KEY_TEMPLATE_SLUG,      type: "apiKey",      queryParams: { key: [{ type: "variable", name: "token" }] },    });    expect(r.slotToTemplateSlug).toEqual({ "query_param:key": API_KEY_TEMPLATE_SLUG });  });   it("literal-string headers pass through as static, never as credentials", () => {    const r = migrateOpenApiAuthTemplate({      headers: {        "User-Agent": "executor/1.0",        Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " },      },    });    expect(r.staticHeaders).toEqual({ "User-Agent": "executor/1.0" });    expect(r.authenticationTemplate).toHaveLength(1);    // The lone credential placement stays the canonical `token`.    expect(r.slotToVariable).toEqual({ "header:authorization": "token" });  });   it("converts oauth2 to an oauth method keyed on its security-scheme slug", () => {    const r = migrateOpenApiAuthTemplate({      oauth2: {        securitySchemeName: "googleOAuth2",        flow: "authorizationCode",        authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",        tokenUrl: "https://oauth2.googleapis.com/token",        scopes: ["https://www.googleapis.com/auth/calendar"],      },    });    expect(r.authenticationTemplate).toEqual([      {        slug: "googleOAuth2",        type: "oauth",        authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",        tokenUrl: "https://oauth2.googleapis.com/token",        scopes: ["https://www.googleapis.com/auth/calendar"],      },    ]);    expect(r.slotToTemplateSlug).toEqual({ "oauth2:googleoauth2:connection": "googleOAuth2" });  });   it("maps hyphenated legacy oauth slot names to underscored oauth slugs", () => {    const r = migrateOpenApiAuthTemplate({      oauth2: {        securitySchemeName: "oauth_2_0",        flow: "authorizationCode",        authorizationUrl: "https://accounts.spotify.com/authorize",        tokenUrl: "https://accounts.spotify.com/api/token",        scopes: ["user-read-email"],      },    });     expect(r.slotToTemplateSlug["oauth2:oauth-2-0:connection"]).toBe("oauth_2_0");    expect(r.slotToVariable["oauth2:oauth-2-0:connection"]).toBe("token");  });   it("a source offering both apiKey and oauth declares both methods", () => {    const r = migrateOpenApiAuthTemplate({      headers: {        Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " },      },      oauth2: {        securitySchemeName: "oauth2",        tokenUrl: "https://example.com/token",        scopes: [],      },    });    expect(r.authenticationTemplate.map((m) => m.type)).toEqual(["apiKey", "oauth"]);  });   it("gives two distinct credential placements (Datadog) their own variables", () => {    const r = migrateOpenApiAuthTemplate({      headers: {        "DD-API-KEY": { kind: "binding", slot: "header:dd-api-key" },        "DD-APPLICATION-KEY": { kind: "binding", slot: "header:dd-application-key" },      },    });    expect(r.authenticationTemplate).toEqual([      {        slug: API_KEY_TEMPLATE_SLUG,        type: "apiKey",        headers: {          "DD-API-KEY": [{ type: "variable", name: "dd_api_key" }],          "DD-APPLICATION-KEY": [{ type: "variable", name: "dd_application_key" }],        },      },    ]);    expect(r.slotToVariable).toEqual({      "header:dd-api-key": "dd_api_key",      "header:dd-application-key": "dd_application_key",    });    expect(r.warnings).toEqual([]);  });   it("an auth-less source yields an empty template", () => {    const r = migrateOpenApiAuthTemplate({});    expect(r.authenticationTemplate).toEqual([]);    expect(r.slotToTemplateSlug).toEqual({});    expect(r.slotToVariable).toEqual({});  });}); describe("migrateGrant", () => {  it("maps client-credentials to client_credentials, everything else to authorization_code", () => {    expect(migrateGrant("client-credentials")).toBe("client_credentials");    expect(migrateGrant("authorization-code")).toBe("authorization_code");    expect(migrateGrant("dynamic-dcr")).toBe("authorization_code");  });}); describe("migrateExpiresAt (C1a)", () => {  const now = 1_700_000_000_000;   it("synthesizes a 1h expiry for a client_credentials connection with null v1 expiry", () => {    expect(migrateExpiresAt({ grant: "client_credentials", v1ExpiresAt: null, nowMs: now })).toBe(      now + SYNTHETIC_CLIENT_CREDENTIALS_TTL_MS,    );    expect(SYNTHETIC_CLIENT_CREDENTIALS_TTL_MS).toBe(60 * 60 * 1000);  });   it("keeps a real v1 expiry for client_credentials (only backfills the null case)", () => {    expect(migrateExpiresAt({ grant: "client_credentials", v1ExpiresAt: 123, nowMs: now })).toBe(      123,    );  });   it("never synthesizes for authorization_code (null stays null — re-auth on use)", () => {    expect(      migrateExpiresAt({ grant: "authorization_code", v1ExpiresAt: null, nowMs: now }),    ).toBeNull();    expect(migrateExpiresAt({ grant: "authorization_code", v1ExpiresAt: 456, nowMs: now })).toBe(      456,    );  });}); describe("migrateOpenApiSourceConfig", () => {  it("copies structural fields, drops namespace, and converts auth to a template", () => {    const r = migrateOpenApiSourceConfig({      spec: "{openapi}",      sourceUrl: "https://api.example.com/openapi.json",      baseUrl: "https://api.example.com",      headers: {        "User-Agent": "executor/1.0",        Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " },      },    });    const config = r.config as {      readonly spec?: string;      readonly sourceUrl?: string;      readonly baseUrl?: string;      readonly headers?: Record<string, string>;      readonly authenticationTemplate?: unknown;    };    expect(config.spec).toBe("{openapi}");    expect(config.sourceUrl).toBe("https://api.example.com/openapi.json");    expect(config.baseUrl).toBe("https://api.example.com");    // The literal header is static config; the credential header became a template.    expect(config.headers).toEqual({ "User-Agent": "executor/1.0" });    expect(config.authenticationTemplate).toEqual([      {        slug: API_KEY_TEMPLATE_SLUG,        type: "apiKey",

Lines 1–500 of 1853.