Showing the changes to packages/codemode-openapi/src/openapi-tools.test.ts (1 of 77 files). Show all
Unified · Split
| @@ -30,6 +30,7 @@ type TestServer = { · 29 unmodified lines | ||
| 30 | 30 | path: string; |
| 31 | 31 | query: string; |
| 32 | 32 | body: string; |
| 33 | + headers: Record<string, string>; | |
| 33 | 34 | }>; |
| 34 | 35 | close: () => Promise<void>; |
| 35 | 36 | }; |
| @@ -53,6 +54,7 @@ const makeEffectServerHandler = ( · 17 unmodified lines | ||
| 53 | 54 | path: `/repos/${path.owner}/${path.repo}`, |
| 54 | 55 | query: include ? `?include=${encodeURIComponent(include)}` : "", |
| 55 | 56 | body: "", |
| 57 | + headers: {}, | |
| 56 | 58 | }); |
| 57 | 59 | |
| 58 | 60 | return { |
| @@ -69,6 +71,7 @@ const makeEffectServerHandler = ( · 10 unmodified lines | ||
| 69 | 71 | path: `/repos/${path.owner}/${path.repo}/issues`, |
| 70 | 72 | query: "", |
| 71 | 73 | body: bodyText, |
| 74 | + headers: {}, | |
| 72 | 75 | }); |
| 73 | 76 | |
| 74 | 77 | return { |
| @@ -207,11 +210,21 @@ const makeTestServer = Effect.acquireRelease( · 132 unmodified lines | ||
| 207 | 210 | catch: (error: unknown) => |
| 208 | 211 | error instanceof Error ? error : new Error(String(error)), |
| 209 | 212 | }).pipe(Effect.orDie), |
| 210 | −); | |
| 213 | + ); | |
| 211 | 214 | |
| 212 | 215 | const ownerParam = HttpApiSchema.param("owner", Schema.String); |
| 213 | 216 | const repoParam = HttpApiSchema.param("repo", Schema.String); |
| 214 | 217 | |
| 218 | +const requestHeadersFromNode = ( | |
| 219 | + request: IncomingMessage, | |
| 220 | +): Record<string, string> => | |
| 221 | + Object.fromEntries( | |
| 222 | + Object.entries(request.headers).flatMap(([key, value]) => | |
| 223 | + value === undefined | |
| 224 | + ? [] | |
| 225 | + : [[key, Array.isArray(value) ? value.join(",") : value]]), | |
| 226 | + ); | |
| 227 | + | |
| 215 | 228 | class GeneratedReposApi extends HttpApiGroup.make("repos") |
| 216 | 229 | .add( |
| 217 | 230 | HttpApiEndpoint.get("getRepo")`/repos/${ownerParam}/${repoParam}` |
| @@ -475,6 +488,117 @@ describe("openapi-tools", () => { · 257 unmodified lines | ||
| 475 | 488 | }), |
| 476 | 489 | ); |
| 477 | 490 | |
| 491 | + it.scoped("applies credential placements for query params, cookies, and body values", () => | |
| 492 | + Effect.gen(function* () { | |
| 493 | + const requests: TestServer["requests"] = []; | |
| 494 | + const server = yield* Effect.acquireRelease( | |
| 495 | + Effect.promise<TestServer>( | |
| 496 | + () => | |
| 497 | + new Promise<TestServer>((resolve, reject) => { | |
| 498 | + const httpServer = createServer((request, response) => { | |
| 499 | + const url = new URL( | |
| 500 | + request.url ?? "/", | |
| 501 | + `http://${request.headers.host ?? "127.0.0.1"}`, | |
| 502 | + ); | |
| 503 | + let body = ""; | |
| 504 | + | |
| 505 | + request.setEncoding("utf8"); | |
| 506 | + request.on("data", (chunk) => { | |
| 507 | + body += chunk; | |
| 508 | + }); | |
| 509 | + request.on("end", () => { | |
| 510 | + requests.push({ | |
| 511 | + method: request.method ?? "GET", | |
| 512 | + path: url.pathname, | |
| 513 | + query: url.search, | |
| 514 | + body, | |
| 515 | + headers: requestHeadersFromNode(request), | |
| 516 | + }); | |
| 517 | + response.statusCode = 200; | |
| 518 | + response.setHeader("content-type", "application/json"); | |
| 519 | + response.end(JSON.stringify({ ok: true })); | |
| 520 | + }); | |
| 521 | + }); | |
| 522 | + | |
| 523 | + httpServer.once("error", reject); | |
| 524 | + httpServer.listen(0, "127.0.0.1", () => { | |
| 525 | + const address = httpServer.address(); | |
| 526 | + if (!address || typeof address === "string") { | |
| 527 | + reject(new Error("failed to resolve test server address")); | |
| 528 | + return; | |
| 529 | + } | |
| 530 | + | |
| 531 | + resolve({ | |
| 532 | + baseUrl: `http://127.0.0.1:${address.port}`, | |
| 533 | + requests, | |
| 534 | + close: async () => { | |
| 535 | + await new Promise<void>((closeResolve, closeReject) => { | |
| 536 | + httpServer.close((error: Error | undefined) => { | |
| 537 | + if (error) { | |
| 538 | + closeReject(error); | |
| 539 | + return; | |
| 540 | + } | |
| 541 | + closeResolve(); | |
| 542 | + }); | |
| 543 | + }); | |
| 544 | + }, | |
| 545 | + }); | |
| 546 | + }); | |
| 547 | + }), | |
| 548 | + ), | |
| 549 | + (resource) => | |
| 550 | + Effect.tryPromise({ | |
| 551 | + try: () => resource.close(), | |
| 552 | + catch: (error: unknown) => | |
| 553 | + error instanceof Error ? error : new Error(String(error)), | |
| 554 | + }).pipe(Effect.orDie), | |
| 555 | + ); | |
| 556 | + const extracted = yield* createOpenApiToolsFromSpec({ | |
| 557 | + sourceName: "demo", | |
| 558 | + openApiSpec: generatedOpenApiSpec, | |
| 559 | + baseUrl: server.baseUrl, | |
| 560 | + namespace: "source.demo", | |
| 561 | + credentialPlacements: { | |
| 562 | + headers: { | |
| 563 | + authorization: "Bearer top-secret", | |
| 564 | + }, | |
| 565 | + queryParams: { | |
| 566 | + api_key: "secret-key", | |
| 567 | + }, | |
| 568 | + cookies: { | |
| 569 | + session: "abc123", | |
| 570 | + }, | |
| 571 | + bodyValues: { | |
| 572 | + "auth.token": "body-secret", | |
| 573 | + }, | |
| 574 | + }, | |
| 575 | + }); | |
| 576 | + | |
| 577 | + const getRepo = resolveToolExecutor(extracted.tools, "source.demo.repos.getRepo"); | |
| 578 | + const createIssue = resolveToolExecutor(extracted.tools, "source.demo.repos.createIssue"); | |
| 579 | + | |
| 580 | + yield* Effect.promise(() => getRepo({ owner: "octocat", repo: "hello-world" })); | |
| 581 | + yield* Effect.promise(() => | |
| 582 | + createIssue({ | |
| 583 | + owner: "octocat", | |
| 584 | + repo: "hello-world", | |
| 585 | + body: { title: "Bug report" }, | |
| 586 | + }), | |
| 587 | + ); | |
| 588 | + | |
| 589 | + expect(server.requests).toHaveLength(2); | |
| 590 | + expect(server.requests[0]?.query).toContain("api_key=secret-key"); | |
| 591 | + expect(server.requests[0]?.headers.authorization).toBe("Bearer top-secret"); | |
| 592 | + expect(server.requests[0]?.headers.cookie).toContain("session=abc123"); | |
| 593 | + expect(JSON.parse(server.requests[1]?.body ?? "{}")).toEqual({ | |
| 594 | + title: "Bug report", | |
| 595 | + auth: { | |
| 596 | + token: "body-secret", | |
| 597 | + }, | |
| 598 | + }); | |
| 599 | + }), | |
| 600 | + ); | |
| 601 | + | |
| 478 | 602 | it.scoped("falls back to path-template args when extracted path parameters are missing", () => |
| 479 | 603 | Effect.gen(function* () { |
| 480 | 604 | const server = yield* makeTestServer; |