import { describe, expect, it } from "@effect/vitest";import { AuthTemplateSlug, IntegrationSlug, OAuthClientSlug, ProviderItemId, ProviderKey, type OAuthProbeResult, type Owner,} from "@executor-js/sdk/shared"; import type { AuthMethod } from "../lib/auth-placements";import type { OAuthPopupReservation } from "../plugins/oauth-sign-in";import { connectionNameFrom, connectionLabel, connectionLabelForHost, createCredentialPayloadOrigin, DEFAULT_CONNECTION_OWNER, hasDcr, mergeCustomMethods, oauthIdentityLabelFromHealth, runAutomaticOAuthConnect, runCimdConnect, typedIdentityLabel, uniqueConnectionName,} from "./add-account-modal"; const apiKeyMethod = (id: string, source: "spec" | "custom", template = id): AuthMethod => ({ id, label: `API key (${id})`, kind: "apikey", source, template: AuthTemplateSlug.make(template), placements: [{ carrier: "header", name: "Authorization", prefix: "" }],}); type ProbeResult = OAuthProbeResult; type RegisterArgs = { readonly owner: Owner; readonly slug: OAuthClientSlug; readonly issuer?: string | null; readonly registrationEndpoint: string; readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly scopes: readonly string[]; readonly tokenEndpointAuthMethodsSupported?: readonly string[]; readonly clientName: string; readonly redirectUri?: string; readonly originIntegration?: IntegrationSlug;}; type StartArgs = { readonly client: OAuthClientSlug; readonly owner: Owner; readonly reservation: OAuthPopupReservation;}; // A reservation the browser honoured. The desktop shape is the one that carries// no `Window`, so the orchestrators' ordering is testable without a DOM.const RESERVED: OAuthPopupReservation = { kind: "desktop", bridge: { openExternal: (): Promise<void> => Promise.resolve() },}; /** Records the reserve/release calls alongside the network steps, so a test can * assert the window is claimed BEFORE the first round trip and closed again * whenever the flow ends without signing in. */const popupSpy = (reservation: OAuthPopupReservation = RESERVED) => { const calls: string[] = []; return { calls, reserve: (): OAuthPopupReservation => { calls.push("reserve"); return reservation; }, release: (): void => { calls.push("release"); }, };}; type AutomaticOAuthDeps = Parameters<typeof runAutomaticOAuthConnect>[0];type AutomaticOAuthInput = Parameters<typeof runAutomaticOAuthConnect>[1]; /** DCR-focused tests use defaults for the CIMD branch they intentionally do * not exercise (and an always-mounted surface unless a test closes it). * Discovery-level tests call the orchestrator directly. */const runDcrConnect = ( deps: Omit<AutomaticOAuthDeps, "createCimdClient" | "isActive"> & Partial<Pick<AutomaticOAuthDeps, "isActive">>, input: Omit<AutomaticOAuthInput, "cimd">,) => runAutomaticOAuthConnect( { isActive: (): boolean => true, ...deps, createCimdClient: (): Promise<OAuthClientSlug | null> => Promise.resolve(null), }, { ...input, cimd: { integrationName: "Test MCP", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [], }, }, ); type CimdCreateArgs = { readonly owner: Owner; readonly slug: OAuthClientSlug; readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly grant: "authorization_code"; readonly clientId: string; readonly clientSecret: "";}; type CimdStartArgs = { readonly client: OAuthClientSlug; readonly owner: Owner; readonly reservation: OAuthPopupReservation;}; const TEST_INTEGRATION = IntegrationSlug.make("linear_mcp"); describe("connectionLabel (name placeholder derivation)", () => { // The name field is optional but prefilled-via-derivation. With an empty // label this is the derived name shown as the input's placeholder, so the // intent ("leave blank ⇒ use this name") is visible. it("derives '<owner> <integration>' for an empty label (the placeholder)", () => { expect(connectionLabel("", "user", "GitHub")).toBe("Personal GitHub"); expect(connectionLabel("", "org", "GitHub")).toBe("Workspace GitHub"); }); it("treats whitespace-only labels as empty (still derives the placeholder)", () => { expect(connectionLabel(" ", "user", "GitHub")).toBe("Personal GitHub"); }); it("uses the typed label (trimmed) when one is provided", () => { expect(connectionLabel(" My Bot ", "user", "GitHub")).toBe("My Bot"); }); it("uses Local in derived labels for non-org-scoped hosts", () => { expect(connectionLabelForHost("", "org", "GitHub", null)).toBe("Local GitHub"); expect(connectionLabelForHost("", "org", "GitHub", "org_123")).toBe("Workspace GitHub"); });}); describe("connectionNameFrom", () => { it("derives the JS-callable name from the display name", () => { expect(String(connectionNameFrom("Autumn Production", "user", "Autumn", "org_123"))).toBe( "autumnProduction", ); expect(String(connectionNameFrom("linear-mcp-oauth", "user", "Linear MCP", "org_123"))).toBe( "linearMcpOauth", ); }); it("derives a callable default from owner and integration when the display name is empty", () => { expect(String(connectionNameFrom("", "org", "GitHub", "org_123"))).toBe("workspaceGithub"); expect(String(connectionNameFrom("", "org", "GitHub", null))).toBe("localGithub"); });}); describe("uniqueConnectionName", () => { const base = connectionNameFrom("", "user", "Gmail", "org_123"); it("keeps the derived name when it is not taken", () => { expect(String(uniqueConnectionName(base, new Set()))).toBe("personalGmail"); }); it("suffixes past taken names so a second untyped connect mints a NEW connection", () => { expect(String(uniqueConnectionName(base, new Set(["personalGmail"])))).toBe("personalGmail2"); expect(String(uniqueConnectionName(base, new Set(["personalGmail", "personalGmail2"])))).toBe( "personalGmail3", ); });}); describe("typedIdentityLabel", () => { it("returns undefined for empty/whitespace labels so oauth.start omits the label", () => { expect(typedIdentityLabel("")).toBeUndefined(); expect(typedIdentityLabel(" ")).toBeUndefined(); }); it("returns the trimmed label the user typed", () => { expect(typedIdentityLabel(" Work Gmail ")).toBe("Work Gmail"); });}); describe("oauthIdentityLabelFromHealth", () => { const healthyResult = { status: "healthy" as const, identity: " user@example.com ", checkedAt: 1, }; it("fills an unset label (untyped connect with no OIDC claims)", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: null, }), ).toBe("user@example.com"); }); it("does not overwrite a hand-typed label", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "My Google Account", storedIdentityLabel: "My Google Account", }), ).toBeNull(); }); it("does not overwrite a stored custom label", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: "Finance Google", }), ).toBeNull(); }); it("does not overwrite a label already filled from OIDC claims", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: "alice@example.com", }), ).toBeNull(); }); it("requires a healthy result with an identity", () => { expect( oauthIdentityLabelFromHealth({ result: { status: "degraded", checkedAt: 1 }, typedLabel: "", storedIdentityLabel: null, }), ).toBeNull(); expect( oauthIdentityLabelFromHealth({ result: { status: "healthy", checkedAt: 1 }, typedLabel: "", storedIdentityLabel: null, }), ).toBeNull(); });}); describe("DEFAULT_CONNECTION_OWNER", () => { // The 'saved to' owner defaults to Personal: a connection is most often a // personal credential. it("defaults a new connection's owner to Personal (user)", () => { expect(DEFAULT_CONNECTION_OWNER).toBe("user"); });}); describe("mergeCustomMethods (in-session custom method append)", () => { // A just-created custom method joins the selectable list (custom last) so it // can be selected before the catalog refresh lands. it("appends a session-created method after the declared methods", () => { const declared = [apiKeyMethod("spec-1", "spec")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes by stable identity (a refreshed catalog method wins over its session copy)", () => { const declared = [apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a", "custom")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes custom methods by template even when their rendered ids differ", () => { const declared = [ apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a_refreshed", "custom", "custom_a"), ]; const created = [apiKeyMethod("custom_a", "custom", "custom_a")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a_refreshed"]); }); it("returns the declared list unchanged when nothing was created", () => { const declared = [apiKeyMethod("spec-1", "spec")]; expect(mergeCustomMethods(declared, [])).toEqual(declared); });}); describe("createCredentialPayloadOrigin", () => { it("creates an empty-string sentinel value for no-auth connection methods", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [], values: {}, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "" } }); }); it("keeps pasted credential values trimmed and keyed by input variable", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [{ variable: "token", label: "Authorization" }], values: { token: " secret-token " }, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "secret-token" } }); }); it("creates a 1Password external origin for single-input methods", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [{ variable: "token", label: "Authorization" }], values: {}, onePasswordItemId: " op://Private/Vercel/token ", singleInput: true, }), ).toEqual({ from: { provider: ProviderKey.make("onepassword"), id: ProviderItemId.make("op://Private/Vercel/token"), }, }); }); it("does not allow 1Password selection for multi-input methods yet", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [ { variable: "apiKey", label: "API key" }, { variable: "appKey", label: "Application key" }, ], values: {}, onePasswordItemId: "op://Private/Datadog/api-key", singleInput: false, }), ).toBeNull(); });}); describe("runCimdConnect", () => { it("creates a public metadata-document OAuth client and starts OAuth", async () => { let createArgs: CimdCreateArgs | null = null; let startArgs: CimdStartArgs | null = null; const outcome = await runCimdConnect( { reserve: (): OAuthPopupReservation => RESERVED, release: (): void => {}, createClient: (args: CimdCreateArgs): Promise<OAuthClientSlug | null> => { createArgs = args; return Promise.resolve(args.slug); }, start: (args: CimdStartArgs): void => { startArgs = args; }, }, { owner: "user", integrationName: "PostHog API", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata/acme.json", existingClients: [], }, ); expect(outcome.kind).toBe("started"); expect(createArgs).toMatchObject({ owner: "user", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", grant: "authorization_code", clientId: "https://executor.example/api/oauth/client-id-metadata/acme.json", clientSecret: "", }); expect(String(createArgs!.slug)).toBe("posthog-api-cimd"); expect(String(startArgs!.client)).toBe("posthog-api-cimd"); expect(startArgs!.owner).toBe("user"); }); it("reuses an existing matching metadata-document client", async () => { const existingSlug = OAuthClientSlug.make("posthog-api-cimd"); let created = false; let startArgs: CimdStartArgs | null = null; const outcome = await runCimdConnect( { reserve: (): OAuthPopupReservation => RESERVED, release: (): void => {}, createClient: (): Promise<OAuthClientSlug | null> => { created = true; return Promise.resolve(OAuthClientSlug.make("new-client")); }, start: (args: CimdStartArgs): void => { startArgs = args; }, }, { owner: "user", integrationName: "PostHog API", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [ { owner: "user", slug: existingSlug, grant: "authorization_code", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientId: "https://executor.example/api/oauth/client-id-metadata.json", }, ], }, ); expect(outcome).toEqual({ kind: "started", client: existingSlug, reused: true }); expect(created).toBe(false); expect(startArgs).toEqual({ client: existingSlug, owner: "user", reservation: RESERVED }); });}); describe("runAutomaticOAuthConnect", () => { it("prefers advertised CIMD over DCR and keeps the original popup reservation", async () => { const popup = popupSpy(); const calls: string[] = []; let createArgs: CimdCreateArgs | null = null; let startArgs: StartArgs | null = null; const outcome = await runAutomaticOAuthConnect( { ...popup, isActive: (): boolean => true, probe: (): Promise<ProbeResult> => { calls.push("probe"); return Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", resource: "https://mcp.example.com/mcp", registrationEndpoint: "https://auth.example.com/register", clientIdMetadataDocumentSupported: true, }); }, createCimdClient: (args: CimdCreateArgs): Promise<OAuthClientSlug> => { calls.push("create-cimd"); createArgs = args; return Promise.resolve(args.slug); }, register: (): Promise<OAuthClientSlug> => { calls.push("register-dcr"); return Promise.resolve(OAuthClientSlug.make("unexpected-dcr-client")); }, start: (args: StartArgs): void => { calls.push("start"); startArgs = args; }, }, { discoveryUrl: "https://mcp.example.com/mcp", resourceFallback: "https://mcp.example.com/mcp", owner: "user", integration: TEST_INTEGRATION, cimd: { integrationName: "Test MCP", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [], }, }, ); expect(outcome).toEqual({ kind: "started", flow: "cimd" }); expect(calls).toEqual(["probe", "create-cimd", "start"]); expect(createArgs).toMatchObject({ clientId: "https://executor.example/api/oauth/client-id-metadata.json", clientSecret: "",Lines 1–500 of 1440. Load more
import { describe, expect, it } from "@effect/vitest"; import { AuthTemplateSlug, IntegrationSlug, OAuthClientSlug, ProviderItemId, ProviderKey, type OAuthProbeResult, type Owner, } from "@executor-js/sdk/shared"; import type { AuthMethod } from "../lib/auth-placements"; import type { OAuthPopupReservation } from "../plugins/oauth-sign-in"; import { connectionNameFrom, connectionLabel, connectionLabelForHost, createCredentialPayloadOrigin, DEFAULT_CONNECTION_OWNER, hasDcr, mergeCustomMethods, oauthIdentityLabelFromHealth, runAutomaticOAuthConnect, runCimdConnect, typedIdentityLabel, uniqueConnectionName, } from "./add-account-modal"; const apiKeyMethod = (id: string, source: "spec" | "custom", template = id): AuthMethod => ({ id, label: `API key (${id})`, kind: "apikey", source, template: AuthTemplateSlug.make(template), placements: [{ carrier: "header", name: "Authorization", prefix: "" }], }); type ProbeResult = OAuthProbeResult; type RegisterArgs = { readonly owner: Owner; readonly slug: OAuthClientSlug; readonly issuer?: string | null; readonly registrationEndpoint: string; readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly scopes: readonly string[]; readonly tokenEndpointAuthMethodsSupported?: readonly string[]; readonly clientName: string; readonly redirectUri?: string; readonly originIntegration?: IntegrationSlug; }; type StartArgs = { readonly client: OAuthClientSlug; readonly owner: Owner; readonly reservation: OAuthPopupReservation; }; // A reservation the browser honoured. The desktop shape is the one that carries // no `Window`, so the orchestrators' ordering is testable without a DOM. const RESERVED: OAuthPopupReservation = { kind: "desktop", bridge: { openExternal: (): Promise<void> => Promise.resolve() }, }; /** Records the reserve/release calls alongside the network steps, so a test can * assert the window is claimed BEFORE the first round trip and closed again * whenever the flow ends without signing in. */ const popupSpy = (reservation: OAuthPopupReservation = RESERVED) => { const calls: string[] = []; return { calls, reserve: (): OAuthPopupReservation => { calls.push("reserve"); return reservation; }, release: (): void => { calls.push("release"); }, }; }; type AutomaticOAuthDeps = Parameters<typeof runAutomaticOAuthConnect>[0]; type AutomaticOAuthInput = Parameters<typeof runAutomaticOAuthConnect>[1]; /** DCR-focused tests use defaults for the CIMD branch they intentionally do * not exercise (and an always-mounted surface unless a test closes it). * Discovery-level tests call the orchestrator directly. */ const runDcrConnect = ( deps: Omit<AutomaticOAuthDeps, "createCimdClient" | "isActive"> & Partial<Pick<AutomaticOAuthDeps, "isActive">>, input: Omit<AutomaticOAuthInput, "cimd">, ) => runAutomaticOAuthConnect( { isActive: (): boolean => true, ...deps, createCimdClient: (): Promise<OAuthClientSlug | null> => Promise.resolve(null), }, { ...input, cimd: { integrationName: "Test MCP", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [], }, }, ); type CimdCreateArgs = { readonly owner: Owner; readonly slug: OAuthClientSlug; readonly authorizationUrl: string; readonly tokenUrl: string; readonly resource?: string | null; readonly grant: "authorization_code"; readonly clientId: string; readonly clientSecret: ""; }; type CimdStartArgs = { readonly client: OAuthClientSlug; readonly owner: Owner; readonly reservation: OAuthPopupReservation; }; const TEST_INTEGRATION = IntegrationSlug.make("linear_mcp"); describe("connectionLabel (name placeholder derivation)", () => { // The name field is optional but prefilled-via-derivation. With an empty // label this is the derived name shown as the input's placeholder, so the // intent ("leave blank ⇒ use this name") is visible. it("derives '<owner> <integration>' for an empty label (the placeholder)", () => { expect(connectionLabel("", "user", "GitHub")).toBe("Personal GitHub"); expect(connectionLabel("", "org", "GitHub")).toBe("Workspace GitHub"); }); it("treats whitespace-only labels as empty (still derives the placeholder)", () => { expect(connectionLabel(" ", "user", "GitHub")).toBe("Personal GitHub"); }); it("uses the typed label (trimmed) when one is provided", () => { expect(connectionLabel(" My Bot ", "user", "GitHub")).toBe("My Bot"); }); it("uses Local in derived labels for non-org-scoped hosts", () => { expect(connectionLabelForHost("", "org", "GitHub", null)).toBe("Local GitHub"); expect(connectionLabelForHost("", "org", "GitHub", "org_123")).toBe("Workspace GitHub"); }); }); describe("connectionNameFrom", () => { it("derives the JS-callable name from the display name", () => { expect(String(connectionNameFrom("Autumn Production", "user", "Autumn", "org_123"))).toBe( "autumnProduction", ); expect(String(connectionNameFrom("linear-mcp-oauth", "user", "Linear MCP", "org_123"))).toBe( "linearMcpOauth", ); }); it("derives a callable default from owner and integration when the display name is empty", () => { expect(String(connectionNameFrom("", "org", "GitHub", "org_123"))).toBe("workspaceGithub"); expect(String(connectionNameFrom("", "org", "GitHub", null))).toBe("localGithub"); }); }); describe("uniqueConnectionName", () => { const base = connectionNameFrom("", "user", "Gmail", "org_123"); it("keeps the derived name when it is not taken", () => { expect(String(uniqueConnectionName(base, new Set()))).toBe("personalGmail"); }); it("suffixes past taken names so a second untyped connect mints a NEW connection", () => { expect(String(uniqueConnectionName(base, new Set(["personalGmail"])))).toBe("personalGmail2"); expect(String(uniqueConnectionName(base, new Set(["personalGmail", "personalGmail2"])))).toBe( "personalGmail3", ); }); }); describe("typedIdentityLabel", () => { it("returns undefined for empty/whitespace labels so oauth.start omits the label", () => { expect(typedIdentityLabel("")).toBeUndefined(); expect(typedIdentityLabel(" ")).toBeUndefined(); }); it("returns the trimmed label the user typed", () => { expect(typedIdentityLabel(" Work Gmail ")).toBe("Work Gmail"); }); }); describe("oauthIdentityLabelFromHealth", () => { const healthyResult = { status: "healthy" as const, identity: " user@example.com ", checkedAt: 1, }; it("fills an unset label (untyped connect with no OIDC claims)", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: null, }), ).toBe("user@example.com"); }); it("does not overwrite a hand-typed label", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "My Google Account", storedIdentityLabel: "My Google Account", }), ).toBeNull(); }); it("does not overwrite a stored custom label", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: "Finance Google", }), ).toBeNull(); }); it("does not overwrite a label already filled from OIDC claims", () => { expect( oauthIdentityLabelFromHealth({ result: healthyResult, typedLabel: "", storedIdentityLabel: "alice@example.com", }), ).toBeNull(); }); it("requires a healthy result with an identity", () => { expect( oauthIdentityLabelFromHealth({ result: { status: "degraded", checkedAt: 1 }, typedLabel: "", storedIdentityLabel: null, }), ).toBeNull(); expect( oauthIdentityLabelFromHealth({ result: { status: "healthy", checkedAt: 1 }, typedLabel: "", storedIdentityLabel: null, }), ).toBeNull(); }); }); describe("DEFAULT_CONNECTION_OWNER", () => { // The 'saved to' owner defaults to Personal: a connection is most often a // personal credential. it("defaults a new connection's owner to Personal (user)", () => { expect(DEFAULT_CONNECTION_OWNER).toBe("user"); }); }); describe("mergeCustomMethods (in-session custom method append)", () => { // A just-created custom method joins the selectable list (custom last) so it // can be selected before the catalog refresh lands. it("appends a session-created method after the declared methods", () => { const declared = [apiKeyMethod("spec-1", "spec")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes by stable identity (a refreshed catalog method wins over its session copy)", () => { const declared = [apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a", "custom")]; const created = [apiKeyMethod("custom_a", "custom")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a"]); }); it("dedupes custom methods by template even when their rendered ids differ", () => { const declared = [ apiKeyMethod("spec-1", "spec"), apiKeyMethod("custom_a_refreshed", "custom", "custom_a"), ]; const created = [apiKeyMethod("custom_a", "custom", "custom_a")]; const merged = mergeCustomMethods(declared, created); expect(merged.map((m: AuthMethod) => m.id)).toEqual(["spec-1", "custom_a_refreshed"]); }); it("returns the declared list unchanged when nothing was created", () => { const declared = [apiKeyMethod("spec-1", "spec")]; expect(mergeCustomMethods(declared, [])).toEqual(declared); }); }); describe("createCredentialPayloadOrigin", () => { it("creates an empty-string sentinel value for no-auth connection methods", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [], values: {}, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "" } }); }); it("keeps pasted credential values trimmed and keyed by input variable", () => { expect( createCredentialPayloadOrigin({ origin: "paste", inputs: [{ variable: "token", label: "Authorization" }], values: { token: " secret-token " }, onePasswordItemId: "", singleInput: true, }), ).toEqual({ values: { token: "secret-token" } }); }); it("creates a 1Password external origin for single-input methods", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [{ variable: "token", label: "Authorization" }], values: {}, onePasswordItemId: " op://Private/Vercel/token ", singleInput: true, }), ).toEqual({ from: { provider: ProviderKey.make("onepassword"), id: ProviderItemId.make("op://Private/Vercel/token"), }, }); }); it("does not allow 1Password selection for multi-input methods yet", () => { expect( createCredentialPayloadOrigin({ origin: "onepassword", inputs: [ { variable: "apiKey", label: "API key" }, { variable: "appKey", label: "Application key" }, ], values: {}, onePasswordItemId: "op://Private/Datadog/api-key", singleInput: false, }), ).toBeNull(); }); }); describe("runCimdConnect", () => { it("creates a public metadata-document OAuth client and starts OAuth", async () => { let createArgs: CimdCreateArgs | null = null; let startArgs: CimdStartArgs | null = null; const outcome = await runCimdConnect( { reserve: (): OAuthPopupReservation => RESERVED, release: (): void => {}, createClient: (args: CimdCreateArgs): Promise<OAuthClientSlug | null> => { createArgs = args; return Promise.resolve(args.slug); }, start: (args: CimdStartArgs): void => { startArgs = args; }, }, { owner: "user", integrationName: "PostHog API", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata/acme.json", existingClients: [], }, ); expect(outcome.kind).toBe("started"); expect(createArgs).toMatchObject({ owner: "user", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", grant: "authorization_code", clientId: "https://executor.example/api/oauth/client-id-metadata/acme.json", clientSecret: "", }); expect(String(createArgs!.slug)).toBe("posthog-api-cimd"); expect(String(startArgs!.client)).toBe("posthog-api-cimd"); expect(startArgs!.owner).toBe("user"); }); it("reuses an existing matching metadata-document client", async () => { const existingSlug = OAuthClientSlug.make("posthog-api-cimd"); let created = false; let startArgs: CimdStartArgs | null = null; const outcome = await runCimdConnect( { reserve: (): OAuthPopupReservation => RESERVED, release: (): void => {}, createClient: (): Promise<OAuthClientSlug | null> => { created = true; return Promise.resolve(OAuthClientSlug.make("new-client")); }, start: (args: CimdStartArgs): void => { startArgs = args; }, }, { owner: "user", integrationName: "PostHog API", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [ { owner: "user", slug: existingSlug, grant: "authorization_code", authorizationUrl: "https://us.posthog.com/oauth/authorize/", tokenUrl: "https://us.posthog.com/oauth/token/", resource: "https://us.posthog.com", clientId: "https://executor.example/api/oauth/client-id-metadata.json", }, ], }, ); expect(outcome).toEqual({ kind: "started", client: existingSlug, reused: true }); expect(created).toBe(false); expect(startArgs).toEqual({ client: existingSlug, owner: "user", reservation: RESERVED }); }); }); describe("runAutomaticOAuthConnect", () => { it("prefers advertised CIMD over DCR and keeps the original popup reservation", async () => { const popup = popupSpy(); const calls: string[] = []; let createArgs: CimdCreateArgs | null = null; let startArgs: StartArgs | null = null; const outcome = await runAutomaticOAuthConnect( { ...popup, isActive: (): boolean => true, probe: (): Promise<ProbeResult> => { calls.push("probe"); return Promise.resolve({ authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "https://auth.example.com/token", resource: "https://mcp.example.com/mcp", registrationEndpoint: "https://auth.example.com/register", clientIdMetadataDocumentSupported: true, }); }, createCimdClient: (args: CimdCreateArgs): Promise<OAuthClientSlug> => { calls.push("create-cimd"); createArgs = args; return Promise.resolve(args.slug); }, register: (): Promise<OAuthClientSlug> => { calls.push("register-dcr"); return Promise.resolve(OAuthClientSlug.make("unexpected-dcr-client")); }, start: (args: StartArgs): void => { calls.push("start"); startArgs = args; }, }, { discoveryUrl: "https://mcp.example.com/mcp", resourceFallback: "https://mcp.example.com/mcp", owner: "user", integration: TEST_INTEGRATION, cimd: { integrationName: "Test MCP", clientIdMetadataDocumentUrl: "https://executor.example/api/oauth/client-id-metadata.json", existingClients: [], }, }, ); expect(outcome).toEqual({ kind: "started", flow: "cimd" }); expect(calls).toEqual(["probe", "create-cimd", "start"]); expect(createArgs).toMatchObject({ clientId: "https://executor.example/api/oauth/client-id-metadata.json", clientSecret: "",