1119 lines · 36.3 KB · TypeScript
RawDownload
import { describe, expect, it } from "@effect/vitest";import { Effect } from "effect";import { streamOperationBindingsFromStructure, structuralSplit } from "@executor-js/plugin-openapi"; import {  googlePresetIdForTool,  microsoftPresetIdsForTool,  microsoftToolFirstSegmentPresetIds,  operationStorageKey,  planMigration,  verifyPolicyRewriteNeverWidens,  type BlobRow,  type ConnectionRow,  type IntegrationRow,  type MigrationInput,  type PluginStorageRow,  type ToolPolicyRow,  type ToolRow,} from "./planner";import { googleCatalog } from "@executor-js/plugin-openapi/providers/google"; const now = "2026-01-01T00:00:00.000Z"; const integration = (overrides: Partial<IntegrationRow> = {}): IntegrationRow => ({  tenant: "org_1",  slug: "google",  plugin_id: "google",  name: "Google",  description: "Google APIs",  config: {    googleDiscoveryUrls: ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"],    specHash: "mono-hash",    authenticationTemplate: [{ slug: "googleOAuth", kind: "oauth2" }],  },  health_check: null,  config_revised_at: null,  can_remove: true,  can_refresh: true,  created_at: now,  updated_at: now,  row_id: "int_1",  ...overrides,}); const connection = (overrides: Partial<ConnectionRow> = {}): ConnectionRow => ({  tenant: "org_1",  owner: "org",  subject: "",  integration: "google",  name: "main",  template: "googleOAuth",  provider: "vault",  item_ids: { access: "access_item", refresh: "refresh_item" },  identity_label: "person@example.test",  description: null,  last_health: null,  tools_synced_at: 1,  oauth_client: "google",  oauth_client_owner: "org",  refresh_item_id: "refresh_item",  expires_at: 2,  oauth_scope: "calendar gmail",  oauth_token_url: "https://oauth2.googleapis.com/token",  provider_state: { token: "metadata" },  created_at: now,  updated_at: now,  row_id: "conn_1",  ...overrides,}); const tool = (name: string, overrides: Partial<ToolRow> = {}): ToolRow => ({  tenant: "org_1",  owner: "org",  subject: "",  integration: "google",  connection: "main",  plugin_id: "google",  name,  description: "tool",  input_schema: {},  output_schema: {},  annotations: {},  created_at: now,  updated_at: now,  row_id: `tool_${name}`,  ...overrides,}); const operation = (name: string, overrides: Partial<PluginStorageRow> = {}): PluginStorageRow => ({  tenant: "org_1",  owner: "org",  subject: "",  plugin_id: "google",  collection: "operation",  key: operationStorageKey("google", name),  data: {    integration: "google",    toolName: name,    binding: {      method: "get",      servers: [],      pathTemplate: `/${name}`,      parameters: [],    },    description: name,  },  created_at: now,  updated_at: now,  row_id: `op_${name}`,  ...overrides,}); const blob = (key: string, overrides: Partial<BlobRow> = {}): BlobRow => ({  id: `blob_${key}`,  namespace: "o:org_1/google",  key,  ...overrides,}); const policy = (pattern: string, overrides: Partial<ToolPolicyRow> = {}): ToolPolicyRow => ({  tenant: "org_1",  owner: "org",  subject: "",  id: `pol_${pattern.replaceAll(".", "_").replaceAll("*", "star")}`,  pattern,  action: "block",  position: "a0",  created_at: now,  updated_at: now,  row_id: `row_${pattern}`,  ...overrides,}); const googleDiscoveryConfig = (urls: readonly string[], specHash = "mono-hash") => ({  googleDiscoveryUrls: urls,  specHash,}); const youtubeDiscoveryUrl = "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"; const googleCatalogMethodPrefixFixtures: ReadonlyMap<string, readonly string[]> = new Map([  ["google-calendar", ["calendar.events.list"]],  ["google-gmail", ["gmail.users.messages.list"]],  ["google-sheets", ["sheets.spreadsheets.get"]],  ["google-drive", ["drive.files.list"]],  ["google-docs", ["docs.documents.get"]],  ["google-slides", ["slides.presentations.get"]],  ["google-forms", ["forms.forms.get"]],  ["google-tasks", ["tasks.tasks.list"]],  ["google-people", ["people.people.get"]],  ["google-photos-library", ["photoslibrary.albums.list"]],  ["google-photos-picker", ["photospicker.sessions.create"]],  ["google-chat", ["chat.spaces.list"]],  ["google-keep", ["keep.notes.list"]],  ["google-youtube-data", ["youtube.channels.list"]],  ["google-search-console", ["searchconsole.sites.list", "webmasters.sites.list"]],  ["google-classroom", ["classroom.courses.list"]],  [    "google-admin-directory",    ["directory.users.list", "admin.customer.devices.chromeos.list", "admin.customers.get"],  ],  ["google-admin-reports", ["reports.activities.list", "admin.channels.stop"]],  ["google-apps-script", ["script.projects.get"]],  ["google-bigquery", ["bigquery.datasets.list"]],  ["google-cloud-resource-manager", ["cloudresourcemanager.projects.list"]],]); const microsoftDefaultPresetIds = [  "profile",  "mail",  "calendar",  "contacts",  "tasks",  "files",  "excel",  "sites",  "onenote",  "teams-chat",  "teams-channels",  "meetings-calls",] as const; const microsoftFixtureTagForFirstSegment = (firstSegment: string): string =>  firstSegment.replace(/([a-z0-9])([A-Z])/g, "$1 $2"); const microsoftToolFirstSegmentsFromSplitterFixture = () =>  Effect.gen(function* () {    const paths = [...microsoftToolFirstSegmentPresetIds.keys()]      .map(        (firstSegment) => `  /fixture/${firstSegment}:    get:      tags:        - ${microsoftFixtureTagForFirstSegment(firstSegment)}      operationId: ${firstSegment}.Get      responses:        "200":          description: OK`,      )      .join("\n");    const structure = structuralSplit(`openapi: 3.0.4info:  title: Microsoft Graph Tool Ownership Fixture  version: v1.0paths:${paths}components: {}`);    expect(structure).not.toBeNull();    const toolNames: string[] = [];    yield* streamOperationBindingsFromStructure(structure!, { chunkSize: 100 }, (chunk) =>      Effect.sync(() => {        toolNames.push(...chunk.map((row) => row.toolName));      }),    );    return new Set(toolNames.map((toolName) => toolName.split(".")[0] ?? ""));  }); const input = (overrides: Partial<MigrationInput> = {}): MigrationInput => ({  integrations: [integration()],  connections: [connection()],  tools: [tool("calendar.events.list")],  pluginStorage: [operation("calendar.events.list")],  blobs: [blob("spec/mono-hash"), blob("defs/mono-hash")],  policies: [],  ...overrides,}); describe("provider service split migration planner", () => {  it("resolves Google reports, directory, and admin.channels tool prefixes", () => {    expect(googlePresetIdForTool("reports.activities.list")).toBe("google-admin-reports");    expect(googlePresetIdForTool("directory.users.list")).toBe("google-admin-directory");    expect(googlePresetIdForTool("admin.channels.stop")).toBe("google-admin-reports");    expect(googlePresetIdForTool("admin.channels.stopPost0019dmcn")).toBe("google-admin-reports");    expect(googlePresetIdForTool("admin.customers.chrome.printers.list")).toBe(      "google-admin-directory",    );    expect(googlePresetIdForTool("admin.customer.devices.chromeos.list")).toBe(      "google-admin-directory",    );  });   it("keeps Google catalog method prefixes mapped to their owning presets", () => {    expect([...googleCatalogMethodPrefixFixtures.keys()]).toEqual(      googleCatalog.map((preset) => preset.id),    );    for (const [presetId, methods] of googleCatalogMethodPrefixFixtures) {      for (const method of methods) {        expect(googlePresetIdForTool(method), method).toBe(presetId);      }    }  });   it.effect("keeps Microsoft planner ownership table aligned with splitter tool names", () =>    Effect.gen(function* () {      const splitterFirstSegments = yield* microsoftToolFirstSegmentsFromSplitterFixture();       expect([...splitterFirstSegments].sort()).toEqual(        [...microsoftToolFirstSegmentPresetIds.keys()].sort(),      );      for (const [firstSegment, presetIds] of microsoftToolFirstSegmentPresetIds) {        expect(microsoftPresetIdsForTool(`${firstSegment}.get`), firstSegment).toEqual(presetIds);      }      expect(microsoftPresetIdsForTool("drivesDriveItem.workbook.worksheets.list")).toEqual([        "files",        "excel",      ]);    }),  );   it("plans a single-service monolith split", () => {    const plan = planMigration(input());     expect(plan.summary.integrationsCreate).toBe(1);    expect(plan.summary.connectionsClone).toBe(1);    expect(plan.orgs[0]?.integrations.map((row) => row.target.pluginId)).toEqual(["openapi"]);    expect(plan.orgs[0]?.integrations.map((row) => row.target.slug)).toEqual(["google_calendar"]);    expect(plan.orgs[0]?.deleteMonoliths.map((row) => row.slug)).toEqual(["google"]);  });   it("plans a multi-service monolith split from stored Discovery URLs", () => {    const plan = planMigration(      input({        integrations: [          integration({            config: {              googleDiscoveryUrls: [                "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",                "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest",              ],              specHash: "mono-hash",            },          }),        ],        tools: [tool("calendar.events.list"), tool("gmail.users.messages.send")],        pluginStorage: [          operation("calendar.events.list"),          operation("gmail.users.messages.send"),          operation("oauth2.userinfo.get"),        ],      }),    );     expect(plan.orgs[0]?.integrations.map((row) => row.target.slug)).toEqual([      "google_calendar",      "google_gmail",    ]);    expect(plan.summary.connectionsClone).toBe(2);  });   it("models migrated integration serving storage under the new slug", () => {    const plan = planMigration(input());    const planned = plan.orgs[0]?.integrations[0];     expect(planned?.config).toEqual({      specHash: "mono-hash",      specUrl: "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",      specFormat: "google-discovery",      family: "google",      authenticationTemplate: [        {          slug: "googleOAuth2",          kind: "oauth2",          authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",          tokenUrl: "https://oauth2.googleapis.com/token",          scopes: expect.arrayContaining([            "openid",            "email",            "profile",            "https://www.googleapis.com/auth/calendar",          ]),        },      ],    });    expect(planned?.healthCheck).toEqual({      operation: "calendar.calendarList.list",    });    expect(planned?.servingState).toMatchObject({      specHash: "mono-hash",      specSource: "google/google",      specBlobPresent: true,      defsBlobPresent: true,      operationsToBuild: 1,      operationToolNames: ["calendar.events.list"],    });    expect(plan.orgs[0]?.blobCopies).toEqual([      expect.objectContaining({        sourceNamespace: "o:org_1/google",        targetNamespace: "o:org_1/openapi",        key: "spec/mono-hash",        sourcePresent: true,      }),      expect.objectContaining({        sourceNamespace: "o:org_1/google",        targetNamespace: "o:org_1/openapi",        key: "defs/mono-hash",        sourcePresent: true,      }),    ]);    expect(operationStorageKey("google_calendar", "calendar.events.list")).toMatch(/^op\./);  });   it("keeps only the service discovery URL and drops the oauth2 document URL", () => {    const plan = planMigration(      input({        integrations: [          integration({            config: {              googleDiscoveryUrls: [                "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",                "https://www.googleapis.com/discovery/v1/apis/oauth2/v2/rest",              ],              specHash: "mono-hash",            },          }),        ],        pluginStorage: [operation("calendar.events.list"), operation("oauth2.userinfo.get")],      }),    );     const planned = plan.orgs[0]?.integrations[0];     expect(planned?.config).toMatchObject({      specUrl: "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",      specFormat: "google-discovery",      family: "google",    });    expect((planned?.config as { readonly specUrl?: string } | undefined)?.specUrl).not.toContain(      "oauth2",    );    expect(planned?.servingState.operationToolNames).toEqual(["calendar.events.list"]);  });   it("fans out wildcard policies by matched service without widening inventory matches", () => {    const migrationInput = input({      integrations: [        integration({          config: {            googleDiscoveryUrls: [              "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",              "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest",            ],            specHash: "mono-hash",          },        }),      ],      tools: [tool("calendar.events.delete"), tool("gmail.users.messages.delete")],      pluginStorage: [        operation("calendar.events.delete"),        operation("gmail.users.messages.delete"),      ],      policies: [policy("google.*")],    });    const plan = planMigration(migrationInput);     expect(plan.orgs[0]?.policies[0]?.afterPatterns).toEqual([      "google_calendar.*",      "google_gmail.*",    ]);    expect(verifyPolicyRewriteNeverWidens(plan, migrationInput)).toMatchObject({      ok: true,      checkedPolicies: 1,    });  });   it("fans restrictive wildcard policies out to every monolith service, not only currently matching tools", () => {    const migrationInput = input({      integrations: [        integration({          config: {            googleDiscoveryUrls: [              "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest",              "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest",              "https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest",            ],            specHash: "mono-hash",          },        }),      ],      tools: [tool("calendar.events.update")],      pluginStorage: [        operation("calendar.events.update"),        operation("gmail.users.messages.update"),      ],      policies: [policy("google.*.*.*.*.update")],    });    const plan = planMigration(migrationInput);     expect(plan.orgs[0]?.policies[0]?.afterPatterns).toEqual([      "google_calendar.*.*.*.*.update",      "google_gmail.*.*.*.*.update",      "google_sheets.*.*.*.*.update",    ]);    expect(verifyPolicyRewriteNeverWidens(plan, migrationInput)).toMatchObject({      ok: true,      checkedPolicies: 1,      narrowed: [],    });  });   it("hard-errors when a policy would be dropped instead of silently skipped", () => {    expect(() =>      planMigration(        input({          integrations: [            integration({              config: {                googleDiscoveryUrls: [                  "https://www.googleapis.com/discovery/v1/apis/searchconsole/v1/rest",                ],                specHash: "mono-hash",              },            }),          ],          tools: [tool("searchconsole.sites.list")],          pluginStorage: [operation("searchconsole.sites.list")],          policies: [policy("google.*.*.gmail.users.messages.send")],        }),      ),    ).toThrow(/would be dropped/);  });   it("hard-errors when config omits a tool-implied service", () => {    expect(() =>      planMigration(        input({          tools: [tool("calendar.events.list"), tool("gmail.users.messages.send")],          pluginStorage: [            operation("calendar.events.list"),            operation("gmail.users.messages.send"),          ],        }),      ),    ).toThrow(/config omits tool-implied service preset\(s\): google-gmail/);  });   it("boot-rail mode creates a catalog-backed tool-implied service", () => {    const plan = planMigration(      input({        tools: [tool("calendar.events.list"), tool("gmail.users.messages.send")],        pluginStorage: [operation("calendar.events.list"), operation("gmail.users.messages.send")],

Lines 1–500 of 1119.