| 1 | // @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - Exercise the real local callback receiver without contacting OpenAI. |
| 2 | import { expect, it } from "@effect/vitest"; |
| 3 | import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts"; |
| 4 | import * as Deferred from "effect/Deferred"; |
| 5 | import * as Effect from "effect/Effect"; |
| 6 | import * as Fiber from "effect/Fiber"; |
| 7 | import * as Stream from "effect/Stream"; |
| 8 | import * as NodeHttp from "node:http"; |
| 9 | import { subscribeCodexAuthCallback } from "./CodexAuthCallback.ts"; |
| 10 | |
| 11 | async function input() { |
| 12 | const server = NodeHttp.createServer(); |
| 13 | await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve)); |
| 14 | const address = server.address(); |
| 15 | if (!address || typeof address === "string") throw new Error("address"); |
| 16 | await new Promise<void>((resolve) => server.close(() => resolve())); |
| 17 | const authorizationUrl = new URL("https://auth.openai.com/api/accounts/authorize"); |
| 18 | authorizationUrl.search = new URLSearchParams({ |
| 19 | client_id: "dynamic_agent_client", |
| 20 | response_type: "code", |
| 21 | redirect_uri: `http://127.0.0.1:${address.port}/auth/callback`, |
| 22 | state: "a".repeat(43), |
| 23 | code_challenge_method: "S256", |
| 24 | code_challenge: "b".repeat(43), |
| 25 | }).toString(); |
| 26 | return { |
| 27 | authorizationUrl: authorizationUrl.toString(), |
| 28 | returnUrl: "http://localhost:7001/welcome#agents:remote-nuc", |
| 29 | environmentId: EnvironmentId.make("remote-nuc"), |
| 30 | instanceId: ProviderInstanceId.make("work"), |
| 31 | flowId: "remote-flow", |
| 32 | }; |
| 33 | } |
| 34 | function callback(authorizationUrl: string) { |
| 35 | const request = new URL(authorizationUrl); |
| 36 | const url = new URL(request.searchParams.get("redirect_uri")!); |
| 37 | url.search = new URLSearchParams({ |
| 38 | state: request.searchParams.get("state")!, |
| 39 | code: "test-code", |
| 40 | client_id: "oaiapp_test", |
| 41 | }).toString(); |
| 42 | return url; |
| 43 | } |
| 44 | |
| 45 | it.effect("a local primary environment receives sign-in for a remote secondary environment", () => |
| 46 | Effect.gen(function* () { |
| 47 | const request = yield* Effect.promise(input); |
| 48 | const ready = yield* Deferred.make<void>(); |
| 49 | const states: string[] = []; |
| 50 | let receivedCallbackUrl: string | undefined; |
| 51 | const receiver = yield* subscribeCodexAuthCallback(request).pipe( |
| 52 | Stream.runForEach((state) => |
| 53 | Effect.gen(function* () { |
| 54 | states.push(state.phase); |
| 55 | if (state.phase === "finished") receivedCallbackUrl = state.callbackUrl; |
| 56 | if (state.phase === "ready") yield* Deferred.succeed(ready, undefined); |
| 57 | }), |
| 58 | ), |
| 59 | Effect.forkScoped, |
| 60 | ); |
| 61 | yield* Deferred.await(ready); |
| 62 | const expected = callback(request.authorizationUrl); |
| 63 | const foreign = new URL(expected); |
| 64 | foreign.searchParams.set("state", "foreign"); |
| 65 | expect((yield* Effect.promise(() => fetch(foreign))).status).toBe(400); |
| 66 | const response = yield* Effect.promise(() => fetch(expected, { redirect: "manual" })); |
| 67 | expect(response.status).toBe(303); |
| 68 | expect(response.headers.get("cache-control")).toBe("no-store"); |
| 69 | expect(response.headers.get("location")).toBe(request.returnUrl); |
| 70 | yield* Fiber.join(receiver); |
| 71 | expect(receivedCallbackUrl).toBe(expected.toString()); |
| 72 | expect(states).toEqual(["ready", "finished"]); |
| 73 | }).pipe(Effect.scoped), |
| 74 | ); |
| 75 | |
| 76 | it.effect("disconnecting the receiving client releases the exact callback port for retry", () => |
| 77 | Effect.gen(function* () { |
| 78 | const request = yield* Effect.promise(input); |
| 79 | const ready = yield* Deferred.make<void>(); |
| 80 | const receiver = yield* subscribeCodexAuthCallback(request).pipe( |
| 81 | Stream.runForEach(() => Deferred.succeed(ready, undefined)), |
| 82 | Effect.forkScoped, |
| 83 | ); |
| 84 | yield* Deferred.await(ready); |
| 85 | yield* Fiber.interrupt(receiver); |
| 86 | yield* subscribeCodexAuthCallback(request).pipe( |
| 87 | Stream.runForEach((state) => |
| 88 | state.phase === "ready" |
| 89 | ? Effect.promise(() => fetch(callback(request.authorizationUrl), { redirect: "manual" })) |
| 90 | : Effect.void, |
| 91 | ), |
| 92 | ); |
| 93 | }).pipe(Effect.scoped), |
| 94 | ); |
| 95 | |
| 96 | it.effect("the local server refuses nonlocal return destinations", () => |
| 97 | Effect.gen(function* () { |
| 98 | const request = yield* Effect.promise(input); |
| 99 | const result = yield* subscribeCodexAuthCallback({ |
| 100 | ...request, |
| 101 | returnUrl: "https://app.t3.codes/welcome", |
| 102 | }).pipe(Stream.runDrain, Effect.result); |
| 103 | expect(result._tag).toBe("Failure"); |
| 104 | }), |
| 105 | ); |