Skip to content

Commit 693347d

Browse files
committed
test(catalog): hand the pinned transport back the stubbed fetch
#697 moved provider model discovery onto the pinned outbound transport, which resolves and pins the peer address instead of reading `globalThis.fetch`. Catalog tests that stub the global therefore escaped their stub and tried real DNS, failing with DestinationDnsResolutionError — 25 failures across four files after the merge. `providerOutboundGet` already supports a caller-owned executor via `provider.fetch`; #697 used it in two spots. Extend that to the rest: a shared `withStubbedProviderFetch` helper attaches an executor that defers to whatever `globalThis.fetch` is installed at call time, so a test may still swap its stub after building the config. This changes test wiring only. Production discovery keeps the pinned transport with no injected executor, which is the security property #697 added. The suite also gets faster — codex-catalog.test.ts drops from ~33s to ~2.5s now that four cases no longer wait on real DNS timeouts.
1 parent 43f4429 commit 693347d

5 files changed

Lines changed: 50 additions & 3 deletions

File tree

tests/codex-catalog.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { afterEach, describe, expect, spyOn, test } from "bun:test";
22
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
33
import { tmpdir } from "node:os";
44
import { join } from "node:path";
5-
import { augmentRoutedModelsWithJawcodeMetadata, augmentRoutedModelsWithRegistryOpenAiApiRows, buildCatalogEntries, buildComboCatalogOmission, catalogModelSlug, clampCatalogModelsToCodexSupport, clampEntryToCodexSupportedEfforts, clampedDefaultEffort, comboCatalogOmissionReason, deriveComboCatalogModel, exactComboCatalogSlugs, filterCatalogVisibleModels, filterSupportedNativeSlugs, gatherRoutedModels, isDatedVariantId, isMediaGenerationModelId, loadBundledCodexCatalog, materializeBundledCodexCatalog, mergeCatalogEntriesForSync, NATIVE_OPENAI_MODELS, normalizeRoutedCatalogEntry, resetCatalogRuntimeStateForTests, resetOpenAiApiCatalogWarningStateForTests, shouldExposeRoutedModel } from "../src/codex/catalog";
5+
import { augmentRoutedModelsWithJawcodeMetadata, augmentRoutedModelsWithRegistryOpenAiApiRows, buildCatalogEntries, buildComboCatalogOmission, catalogModelSlug, clampCatalogModelsToCodexSupport, clampEntryToCodexSupportedEfforts, clampedDefaultEffort, comboCatalogOmissionReason, deriveComboCatalogModel, exactComboCatalogSlugs, filterCatalogVisibleModels, filterSupportedNativeSlugs, gatherRoutedModels as gatherRoutedModelsDirect, isDatedVariantId, isMediaGenerationModelId, loadBundledCodexCatalog, materializeBundledCodexCatalog, mergeCatalogEntriesForSync, NATIVE_OPENAI_MODELS, normalizeRoutedCatalogEntry, resetCatalogRuntimeStateForTests, resetOpenAiApiCatalogWarningStateForTests, shouldExposeRoutedModel } from "../src/codex/catalog";
6+
import { withStubbedProviderFetch } from "./helpers/catalog-provider-fetch";
67
import {
78
CURSOR_STATIC_MODELS,
89
filterCursorConfiguredModelsByLiveDiscovery,
@@ -27,6 +28,14 @@ import { handleManagementAPI } from "../src/server/management-api";
2728

2829
const originalFetch = globalThis.fetch;
2930

31+
/**
32+
* Discovery runs on the pinned outbound transport, which does not read
33+
* `globalThis.fetch`. These tests stub that global, so every config gets the
34+
* caller-owned executor that hands control back to the stub.
35+
*/
36+
const gatherRoutedModels: typeof gatherRoutedModelsDirect = (config, options) =>
37+
gatherRoutedModelsDirect(withStubbedProviderFetch(config), options);
38+
3039
afterEach(() => {
3140
globalThis.fetch = originalFetch;
3241
clearModelCache();
@@ -86,6 +95,7 @@ async function liveModelCountAfterDiscovery(provider: string, models: string[] |
8695
apiKey: "k",
8796
liveModels: true,
8897
models: ["configured-fallback"],
98+
fetch: ((input: RequestInfo | URL) => globalThis.fetch(input)) as typeof fetch,
8999
},
90100
},
91101
} as unknown as Parameters<typeof handleManagementAPI>[2];

tests/google-models-listing.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { afterEach, describe, expect, spyOn, test } from "bun:test";
2-
import { gatherRoutedModels } from "../src/codex/catalog";
2+
import { gatherRoutedModels as gatherRoutedModelsDirect } from "../src/codex/catalog";
33
import { buildModelsRequest } from "../src/oauth";
44
import { clearModelCache, getStaleCached } from "../src/codex/model-cache";
55
import type { OcxConfig, OcxProviderConfig } from "../src/types";
6+
import { withStubbedProviderFetch } from "./helpers/catalog-provider-fetch";
7+
8+
/** Discovery runs on the pinned transport; hand it back the stubbed global. */
9+
const gatherRoutedModels: typeof gatherRoutedModelsDirect = (config, options) =>
10+
gatherRoutedModelsDirect(withStubbedProviderFetch(config), options);
611

712
const originalFetch = globalThis.fetch;
813

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Provider-model discovery now runs on the pinned outbound transport
3+
* (`providerOutboundGet`), which resolves and pins the peer address instead of
4+
* calling `globalThis.fetch`. Catalog tests that stub `globalThis.fetch` would
5+
* otherwise hit real DNS and fail with DestinationDnsResolutionError.
6+
*
7+
* `providerOutboundGet` honors a caller-owned executor via `provider.fetch`, so
8+
* these helpers hand the current `globalThis.fetch` back to the transport. The
9+
* indirection matters: the stub is read at call time, so a test may install or
10+
* replace its stub after building the config.
11+
*/
12+
13+
/** A caller-owned executor that defers to whatever `globalThis.fetch` is installed. */
14+
export const stubbedProviderFetch = ((input: RequestInfo | URL, init?: RequestInit) =>
15+
globalThis.fetch(input, init)) as typeof fetch;
16+
17+
/** Attach {@link stubbedProviderFetch} to every provider in a test config. */
18+
export function withStubbedProviderFetch<T extends { providers?: Record<string, unknown> }>(config: T): T {
19+
for (const provider of Object.values(config.providers ?? {})) {
20+
if (provider && typeof provider === "object" && !("fetch" in provider)) {
21+
(provider as { fetch?: typeof fetch }).fetch = stubbedProviderFetch;
22+
}
23+
}
24+
return config;
25+
}

tests/opencode-cli.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ describe("ocx opencode proxy model catalog", () => {
247247
baseUrl: "https://proxyenv.test/v1",
248248
apiKey: `\${${ENV_KEY}}`,
249249
models: ["static-fallback"],
250+
// Discovery runs on the pinned transport; hand it back the stub above.
251+
fetch: ((input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init)) as typeof fetch,
250252
},
251253
},
252254
} as OcxConfig;

tests/vertex-catalog.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { afterEach, describe, expect, spyOn, test } from "bun:test";
2-
import { gatherRoutedModels } from "../src/codex/catalog";
2+
import { gatherRoutedModels as gatherRoutedModelsDirect } from "../src/codex/catalog";
33
import { clearModelCache, markModelsFetchFailure, setCached } from "../src/codex/model-cache";
44
import type { OcxConfig } from "../src/types";
5+
import { withStubbedProviderFetch } from "./helpers/catalog-provider-fetch";
6+
7+
/** Discovery runs on the pinned transport; hand it back the stubbed global. */
8+
const gatherRoutedModels: typeof gatherRoutedModelsDirect = (config, options) =>
9+
gatherRoutedModelsDirect(withStubbedProviderFetch(config), options);
510

611
const originalFetch = globalThis.fetch;
712
let warn: ReturnType<typeof spyOn> | undefined;

0 commit comments

Comments
 (0)