import { expect, layer } from "@effect/vitest"; import { Effect, Layer } from "effect"; import { SecretId } from "./ids"; import { SetSecretInput } from "./secrets"; import { makeTestWorkspaceLayer, memorySecretsPlugin, OAuthTestServer, TestWorkspace, } from "./testing"; const plugins = [memorySecretsPlugin()] as const; const TestLayer = Layer.mergeAll(makeTestWorkspaceLayer({ plugins }), OAuthTestServer.layer()); layer(TestLayer, { timeout: "15 seconds" })("testing fixtures", (it) => { it.effect("TestWorkspace exposes the real executor with an explicit scope stack", () => Effect.gen(function* () { const workspace = yield* TestWorkspace.current(); expect(workspace.scopes.map((scope) => String(scope.id))).toEqual(["test-scope"]); expect(workspace.executor.scopes.map((scope) => String(scope.id))).toEqual(["test-scope"]); expect(yield* workspace.executor.secrets.providers()).toEqual(["memory"]); }), ); it.effect("OAuthTestServer completes a real authorization-code OAuth flow", () => Effect.gen(function* () { const workspace = yield* TestWorkspace.current(); const oauth = yield* OAuthTestServer; const scope = workspace.scopes[0]!; yield* workspace.executor.secrets.set( SetSecretInput.make({ id: SecretId.make("oauth-client-id"), scope: scope.id, name: "OAuth Client ID", value: "test-client", }), ); yield* workspace.executor.secrets.set( SetSecretInput.make({ id: SecretId.make("oauth-client-secret"), scope: scope.id, name: "OAuth Client Secret", value: "test-secret", }), ); const started = yield* workspace.executor.oauth.start({ endpoint: oauth.resourceUrl, connectionId: "test-oauth-authorization-code", tokenScope: String(scope.id), redirectUrl: "http://127.0.0.1/callback", pluginId: "test", identityLabel: "OAuth Test", strategy: { kind: "authorization-code", authorizationEndpoint: oauth.authorizationEndpoint, tokenEndpoint: oauth.tokenEndpoint, clientIdSecretId: "oauth-client-id", clientSecretSecretId: "oauth-client-secret", scopes: ["read"], }, }); expect(started.authorizationUrl).not.toBeNull(); const authorizationUrl = started.authorizationUrl ?? ""; const callback = yield* oauth.completeAuthorizationCodeFlow({ authorizationUrl }); const completed = yield* workspace.executor.oauth.complete({ state: callback.state, code: callback.code, tokenScope: String(scope.id), }); expect(completed.connectionId).toBe("test-oauth-authorization-code"); const accessToken = yield* workspace.executor.connections.accessToken(completed.connectionId); expect(yield* oauth.acceptsAccessToken(accessToken)).toBe(true); }), ); it.effect("OAuthTestServer supports MCP-style dynamic client registration", () => Effect.gen(function* () { const workspace = yield* TestWorkspace.current(); const oauth = yield* OAuthTestServer; const scope = workspace.scopes[0]!; const probe = yield* workspace.executor.oauth.probe({ endpoint: oauth.mcpResourceUrl }); expect(probe.supportsDynamicRegistration).toBe(true); expect(probe.isBearerChallengeEndpoint).toBe(true); const started = yield* workspace.executor.oauth.start({ endpoint: oauth.mcpResourceUrl, connectionId: "test-oauth-dynamic-dcr", tokenScope: String(scope.id), redirectUrl: "http://127.0.0.1/callback", pluginId: "test", identityLabel: "MCP OAuth Test", strategy: { kind: "dynamic-dcr", scopes: ["read"] }, }); expect(started.authorizationUrl).not.toBeNull(); const authorizationUrl = started.authorizationUrl ?? ""; const callback = yield* oauth.completeAuthorizationCodeFlow({ authorizationUrl }); const completed = yield* workspace.executor.oauth.complete({ state: callback.state, code: callback.code, tokenScope: String(scope.id), }); expect(completed.connectionId).toBe("test-oauth-dynamic-dcr"); const accessToken = yield* workspace.executor.connections.accessToken(completed.connectionId); expect(yield* oauth.acceptsAccessToken(accessToken)).toBe(true); }), ); it.effect( "OAuthTestServer can mint a bearer token through the full authorization-code flow", () => Effect.gen(function* () { const oauth = yield* OAuthTestServer; const token = yield* oauth.completeAuthorizationCodeTokenFlow({ scopes: ["read"] }); expect(token.tokenType).toBe("Bearer"); expect(token.accessToken).toMatch(/^at_/); expect(yield* oauth.acceptsAccessToken(token.accessToken)).toBe(true); }), ); });