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. Load more
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.4 info: title: Microsoft Graph Tool Ownership Fixture version: v1.0 paths: ${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")],