chore(validation): decompose providers/validation.ts into validation/* leaves (→ 442) (#8546)

* chore(validation): extract web-cookie, kiro, specialty-inline validators into validation/* leaves

* docs(changelog): add fragment for this PR
This commit is contained in:
MumuTW
2026-07-26 14:52:23 +08:00
committed by GitHub
parent f0b08f95c3
commit 074fd6de88
8 changed files with 875 additions and 568 deletions

View File

@@ -0,0 +1 @@
- chore(validation): decompose `src/lib/providers/validation.ts` (→ 442 lines) by extracting the web-cookie, kiro and specialty inline validators into `validation/*` leaves — behavior-preserving move; the specialty validators that captured `isLocal` from the enclosing closure now take it as an explicit parameter, with the host dispatcher passing it at each call site

View File

@@ -10,13 +10,8 @@ import {
providerAllowsOptionalApiKey,
WEB_COOKIE_PROVIDERS,
} from "@/shared/constants/providers";
import { SAFE_OUTBOUND_FETCH_PRESETS, safeOutboundFetch } from "@/shared/network/safeOutboundFetch";
import { getProviderOutboundGuard } from "@/shared/network/outboundUrlGuardPolicy";
import { resolveNvidiaValidationModel } from "@/lib/providers/nvidiaValidationModel";
import { MODAL_DEFAULT_VALIDATION_MODEL_ID } from "@/shared/constants/modal";
import { validateQoderCliPat } from "@omniroute/open-sse/services/qoderCli.ts";
import { validateImageProviderApiKey } from "@/lib/providers/imageValidation";
import { KiroService } from "@/lib/oauth/services/kiro";
import { usesCcWireImage } from "@omniroute/open-sse/services/ccWireImageBuiltins.ts";
import {
isAlibabaRegionalProvider,
@@ -31,14 +26,7 @@ import {
addModelsSuffix,
resolveBaseUrl,
} from "./validation/urlHelpers";
import { STANDARD_USER_AGENT, directHttpsRequest, buildBearerHeaders } from "./validation/headers";
import {
validationRead,
validationWrite,
toValidationErrorResult,
toWebCookieValidationErrorResult,
WEB_COOKIE_PROVIDERS_WITHOUT_MODELS_API,
} from "./validation/transport";
import { toValidationErrorResult } from "./validation/transport";
import {
validateDeepSeekWebProvider,
validateQwenWebProvider,
@@ -109,6 +97,25 @@ import {
validateAnthropicCompatibleProvider,
validateClaudeCodeCompatibleProvider,
} from "./validation/anthropicFormat";
import {
validateWebCookieProvider,
bytezValidationResultFromStatus,
validateBytezProvider,
} from "./validation/webCookie";
import {
validateV0VercelProvider,
validateAuggieProvider,
validateQoderProvider,
validateKiroProvider,
validateGitlabProvider,
validateVertexProvider,
validateVertexPartnerProvider,
validateLongcatProvider,
validateNvidiaProvider,
validateZaiProvider,
validateXiaomiMimoProvider,
buildGitlawbValidators,
} from "./validation/specialtyInline";
// validateCommandCodeProvider + validateClaudeCodeCompatibleProvider have external importers
// (provider-nodes/validate route + tests) — re-export to preserve the historical public surface.
export { validateCommandCodeProvider, validateClaudeCodeCompatibleProvider };
@@ -117,212 +124,13 @@ export { validateCommandCodeProvider, validateClaudeCodeCompatibleProvider };
// here to preserve the historical public surface (tests + route handlers import them via this module).
export { isRetryableProxyTarget, isSecurityBlockError } from "./validation/transport";
/**
* Validates web-cookie providers by performing a ping request to check if the session is still valid.
* Returns SESSION_EXPIRED error code if the upstream returns 401/403.
*/
export async function validateWebCookieProvider({
provider,
apiKey,
providerSpecificData: _providerSpecificData = {},
}: {
provider: string;
apiKey?: string;
providerSpecificData?: Record<string, unknown>;
}) {
try {
const entry = getRegistryEntry(provider);
const cookieProvider = WEB_COOKIE_PROVIDERS[provider as keyof typeof WEB_COOKIE_PROVIDERS];
if (!entry && !cookieProvider) {
return { valid: false, error: "Provider not found in registry", unsupported: true };
}
// validateWebCookieProvider + bytezValidationResultFromStatus have external importers (tests +
// the web-cookie fallback suites) — re-export to preserve the historical public surface.
export { validateWebCookieProvider, bytezValidationResultFromStatus };
// For web-cookie providers, apiKey contains the cookie string
const cookie = (apiKey || "").trim();
if (!cookie) {
return { valid: false, error: "Cookie required for web-cookie provider", unsupported: false };
}
if (!entry) {
// Providers listed in WEB_COOKIE_PROVIDERS without a providerRegistry entry (e.g.
// gemini-business, poe-web, venice-web, v0-vercel-web) only expose a
// marketing website URL, not a real API host. Probing `${website}/models`
// does not reliably signal session validity for these —
// live verification showed most return redirects or SPA 200s regardless of
// cookie validity, which would silently report an expired/garbage cookie as
// "OK" (worse than an honest "not supported"). Until each of these providers
// has a verified, side-effect-free auth probe against its real API host, report
// unsupported instead of a false positive.
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
// Attempt a minimal request to check if the session is valid
// Use /models endpoint or a minimal completion request depending on the provider
const baseUrl = normalizeBaseUrl(entry.baseUrl || "");
// Defense-in-depth: only an http(s) baseUrl without a query string is safe to
// probe by blindly appending `/models`. A ws(s):// baseUrl (e.g. copilot-web) is
// already rejected by the outbound URL guard downstream, but reject it explicitly
// here for the honest "unsupported" result instead of a confusing security-block
// message — this also covers a future http(s) baseUrl carrying a query string,
// which the guard does not currently block (#7857 acceptance criteria).
if (!/^https?:\/\//i.test(baseUrl) || baseUrl.includes("?")) {
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
const testUrl = `${baseUrl}/models`;
const res = await validationRead(
testUrl,
{
method: "GET",
headers: {
"User-Agent": STANDARD_USER_AGENT,
Cookie: cookie,
},
},
isLocalProvider(provider)
);
if (res.status === 401 || res.status === 403) {
return {
valid: false,
error: "SESSION_EXPIRED",
errorCode: "AUTH_007",
unsupported: false,
};
}
// #7857: for providers whose baseUrl is a conversation/completion endpoint rather
// than a real API root, the /models path never existed upstream — a redirect,
// login-HTML 200, 404, 405, or 429 from it is not a meaningful auth signal and is
// indistinguishable from a genuinely valid session. Report the same honest
// "unsupported" result the !entry branch above already gives its no-registry
// siblings, instead of a false `valid: true`.
if (WEB_COOKIE_PROVIDERS_WITHOUT_MODELS_API.has(provider)) {
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
// Any other response (200, 404, 405, 429, ...) means the cookie was accepted —
// a 401/403 from the /models probe is the only definitive "session expired" signal
// for web-cookie auth, so a non-auth status is treated as a valid session.
return { valid: true, error: null, unsupported: false };
} catch (error: unknown) {
return toWebCookieValidationErrorResult(provider, error);
}
}
// #5422: Bytez key validation cannot use a chat probe. A Bytez account only serves models
// that have been added to its catalog, so even Bytez's own documented model ids return 404
// ("Model does not exist or has yet to be added to the Bytez catalog") for a fresh/free key —
// the generic OpenAI-like chat probe misreads that 404 as "endpoint not supported". Validate
// against the model-independent, auth-only tasks endpoint instead (verified live):
// GET …/models/v2/list/tasks → 200 (valid key) | 401 { error: "Unauthorized" } (invalid).
// The pure status→result mapping is factored out so it is unit-testable without network.
export function bytezValidationResultFromStatus(status: number): {
valid: boolean;
error: string | null;
} {
if (status === 200) {
return { valid: true, error: null };
}
if (status === 401 || status === 403) {
return { valid: false, error: "Invalid API key" };
}
return { valid: false, error: `Validation failed: ${status}` };
}
export async function validateBytezProvider({ apiKey, providerSpecificData = {} }: any) {
try {
const res = await validationRead("https://api.bytez.com/models/v2/list/tasks", {
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
});
return bytezValidationResultFromStatus(res.status);
} catch (error: unknown) {
return toValidationErrorResult(error);
}
}
async function validateKiroApiKeyRuntimeProbe({
apiKey,
region,
profileArn,
}: {
apiKey: string;
region: string;
profileArn?: string | null;
}) {
const endpoint =
region === "us-east-1"
? "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse"
: `https://q.${region}.amazonaws.com/generateAssistantResponse`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 15_000);
try {
const body = {
...(profileArn ? { profileArn } : {}),
conversationState: {
chatTriggerType: "MANUAL",
conversationId: crypto.randomUUID(),
currentMessage: {
userInputMessage: {
content: "ping",
modelId: "auto",
origin: "AI_EDITOR",
},
},
history: [],
},
inferenceConfig: {
maxTokens: 1,
},
};
const res = await fetch(endpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
tokentype: "API_KEY",
"Content-Type": "application/x-amz-json-1.0",
"X-Amz-Target": "AmazonCodeWhispererStreamingService.GenerateAssistantResponse",
Accept: "application/vnd.amazon.eventstream",
"Amz-Sdk-Request": "attempt=1; max=3",
"Amz-Sdk-Invocation-Id": crypto.randomUUID(),
},
body: JSON.stringify(body),
signal: controller.signal,
});
await res.body?.cancel().catch(() => undefined);
if (res.ok) {
return { valid: true, error: null, method: "kiro_generate_assistant_response" };
}
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid Kiro API key or AWS region" };
}
if (res.status === 400 || res.status === 422 || res.status === 429) {
return { valid: true, error: null, method: `kiro_generate_assistant_response_${res.status}` };
}
return { valid: false, error: `Kiro validation failed: ${res.status}` };
} finally {
clearTimeout(timeout);
}
}
// validateWebCookieProvider, bytezValidationResultFromStatus, validateBytezProvider, and
// validateKiroApiKeyRuntimeProbe now live in ./validation/webCookie and ./validation/kiro.
// They are re-exported above to preserve the historical public surface.
export async function validateProviderApiKey({ provider, apiKey, providerSpecificData = {} }: any) {
const requiresApiKey = !providerAllowsOptionalApiKey(provider);
@@ -355,161 +163,23 @@ export async function validateProviderApiKey({ provider, apiKey, providerSpecifi
}
}
/**
* Build Opengateway-style validators (xiaomi-mimo compatible).
* These providers share a POST /chat/completions auth check pattern and differ
* only in default baseUrl and test model name.
*/
function buildOpengatewayValidator(defaultBaseUrl: string, model: string) {
return async ({ apiKey, providerSpecificData }: any) => {
try {
const baseUrl = normalizeBaseUrl(providerSpecificData?.baseUrl || defaultBaseUrl);
const chatUrl = `${baseUrl.replace(/\/chat\/completions$/, "")}/chat/completions`;
const res = await validationWrite(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
};
}
// Same as buildOpengatewayValidator but returns an object spreadable into SPECIALTY_VALIDATORS.
// isLocal is captured via closure from the outer function scope.
function buildGitlawbValidators(
configs: [string, string, string][]
): Record<string, ReturnType<typeof buildOpengatewayValidator>> {
return Object.fromEntries(
configs.map(([id, baseUrl, model]) => [id, buildOpengatewayValidator(baseUrl, model)])
);
}
// buildOpengatewayValidator + buildGitlawbValidators now live in ./validation/specialtyInline
// (god-file decomposition). The host still owns the SPECIALTY_VALIDATORS map below; only the
// validator bodies were extracted as leaf functions taking `isLocal` where the original
// closure captured it.
// ── Specialty provider validation ──
const SPECIALTY_VALIDATORS = {
"v0-vercel": async ({ apiKey, providerSpecificData }: any) => {
try {
const configuredBaseUrl =
typeof providerSpecificData?.baseUrl === "string" && providerSpecificData.baseUrl.trim()
? providerSpecificData.baseUrl.trim()
: "https://api.v0.dev";
const root = normalizeBaseUrl(configuredBaseUrl)
.replace(/\/v1\/chat\/completions$/, "")
.replace(/\/v1$/, "");
const res = await validationRead(
`${root}/v1/chats?limit=1`,
{
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
},
isLocal
);
if (res.ok) {
return { valid: true, error: null, method: "v0_platform_chats_list" };
}
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
return { valid: false, error: `v0 validation failed: ${res.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
"v0-vercel": ({ apiKey, providerSpecificData }: any) =>
validateV0VercelProvider({ apiKey, providerSpecificData, isLocal }),
jules: validateJulesProvider,
// "devin" is the Cognition cloud-agent provider (distinct from the "devin-cli"
// LLM/ACP provider, which is already registered in providerRegistry). Wired here
// for parity with the "jules" cloud-agent entry above — see #6142.
devin: validateDevinCloudAgentProvider,
// auggie is a fully local, credential-less CLI passthrough — there is no API
// key to check upstream. The only meaningful validation is confirming the
// `auggie` binary is installed and runnable on this machine.
auggie: async () => {
const { checkAuggieCliVersion } = await import("@omniroute/open-sse/executors/auggie.ts");
const result = await checkAuggieCliVersion();
if (!result.ok) {
return {
valid: false,
error: result.error || "Auggie CLI not found. Install it and run `auggie login`.",
unsupported: false,
};
}
return { valid: true, error: null, unsupported: false, method: result.version };
},
qoder: async ({ apiKey, providerSpecificData }: any) => {
// Bifurcate validation: PAT tokens use Cosy auth against api1.qoder.sh;
// regular API keys validate against dashscope (OpenAI-compatible endpoint).
const key = (apiKey || "").trim();
if (key.startsWith("pt-")) {
return validateQoderCliPat({ apiKey: key, providerSpecificData });
}
// Non-PAT token → validate against dashscope (Alibaba Cloud).
// The executor routes these tokens to dashscope.aliyuncs.com, so the
// validation must test against dashscope, NOT the Cosy PAT endpoint.
try {
const dashscopeUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/models";
const res = await validationRead(
dashscopeUrl,
{
headers: {
Authorization: `Bearer ${key}`,
},
},
false
);
if (res.ok) return { valid: true, error: null };
if (res.status === 401 || res.status === 403) {
return {
valid: false,
error:
"Invalid Qoder API key. Make sure you're using a valid API key from Qoder / Alibaba Cloud Dashscope.",
};
}
// 4xx/5xx other than auth — treat as valid bypass to prevent false
// negatives from transient dashscope issues (consistent with PAT path).
return { valid: true, error: null };
} catch (err: unknown) {
return toValidationErrorResult(err);
}
},
kiro: async ({ apiKey, providerSpecificData }: any) => {
try {
const region = providerSpecificData?.region || "us-east-1";
const credential = await new KiroService().validateApiKey(apiKey, region);
if (!credential.profileArn) {
return await validateKiroApiKeyRuntimeProbe({
apiKey: credential.accessToken,
region: credential.region,
profileArn: providerSpecificData?.profileArn,
});
}
return {
valid: true,
error: null,
method: "kiro_list_available_profiles",
};
} catch (error: any) {
return toValidationErrorResult(error);
}
},
auggie: validateAuggieProvider,
qoder: validateQoderProvider,
kiro: validateKiroProvider,
"command-code": validateCommandCodeProvider,
huggingface: validateHuggingFaceProvider,
// #5422: auth-only probe — Bytez 404s on every chat model until the account adds it to
@@ -595,212 +265,26 @@ export async function validateProviderApiKey({ provider, apiKey, providerSpecifi
modelId: rerankProvider?.models?.[0]?.id || "jina-reranker-v3",
});
},
gitlab: async ({ apiKey, providerSpecificData }: any) => {
try {
const configuredBaseUrl =
typeof providerSpecificData?.baseUrl === "string"
? providerSpecificData.baseUrl.trim()
: "";
const root = (configuredBaseUrl || "https://gitlab.com").replace(/\/$/, "");
const res = await validationWrite(
`${root}/api/v4/code_suggestions/direct_access`,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: "{}",
},
isLocal
);
if (res.status === 401) {
return { valid: false, error: "Invalid API key" };
}
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
vertex: async ({ apiKey }: any) => {
try {
const { parseSAFromApiKey, getAccessToken, isExpressApiKey } =
await import("@omniroute/open-sse/executors/vertex.ts");
// Express-mode API keys are opaque strings sent directly as the ?key= query param — there is
// no JWT to mint, so accept any non-empty Express key (the live chat/media call validates it).
if (isExpressApiKey(apiKey)) {
return { valid: true, error: null };
}
const sa = parseSAFromApiKey(apiKey);
// Validates credentials by successfully successfully exchanging them for a JWT from Google Identity
await getAccessToken(sa);
return { valid: true, error: null };
} catch (error: any) {
return { valid: false, error: "Invalid Service Account JSON: " + error.message };
}
},
"vertex-partner": async ({ apiKey }: any) => {
try {
const { parseSAFromApiKey, getAccessToken, isExpressApiKey } =
await import("@omniroute/open-sse/executors/vertex.ts");
if (isExpressApiKey(apiKey)) {
return { valid: true, error: null };
}
const sa = parseSAFromApiKey(apiKey);
await getAccessToken(sa);
return { valid: true, error: null };
} catch (error: any) {
return { valid: false, error: "Invalid Service Account JSON: " + error.message };
}
},
// LongCat AI — does not expose /v1/models; validate via chat completions directly (#592)
longcat: async ({ apiKey, providerSpecificData }: any) => {
try {
const res = await validationWrite(
"https://api.longcat.chat/openai/v1/chat/completions",
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: "LongCat-2.0",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
// NVIDIA NIM (#2463) — bypass the /models probe in favor of a direct
// chat/completions probe. NVIDIA NIM's /models endpoint returns model
// catalogs that vary by region and key-tier, and some keys 404 on it,
// which the generic flow misreads. The chat probe is also a stronger
// sanity check for streaming/key correctness.
nvidia: async ({ apiKey, providerSpecificData }: any) => {
try {
const baseUrlRaw =
providerSpecificData?.baseUrl || "https://integrate.api.nvidia.com/v1/chat/completions";
const normalized = normalizeBaseUrl(baseUrlRaw);
const chatBase = normalized.replace(/\/models$/, "");
const chatUrl = normalized.endsWith("/chat/completions")
? normalized
: `${chatBase}/chat/completions`;
// #3116: probe a universally-available model rather than models[0]
// (z-ai/glm-5.1), which requires the "Public API Endpoints" account permission
// and can hang/be DEGRADED — making a *valid* key fail with "Upstream Error".
const modelId = resolveNvidiaValidationModel(providerSpecificData);
// #3226: use raw https (bypass the proxy/TLS-patched fetch) — the undici
// dispatcher stalls against NVIDIA's endpoint, causing a 504 timeout.
const res = await directHttpsRequest(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: modelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
20000
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
// Z.AI (glm) — bypass the proxy/TLS-patched fetch for the same reason as nvidia
// above (#3905): the undici dispatcher stalls against api.z.ai after the provider
// returns 502 "job timed out" responses, because z.ai silently drops idle
// keep-alive sockets without sending TCP RST. Using directHttpsRequest (native
// Node.js HTTPS, no undici pool) avoids the zombie-socket hang on validation.
// Z.AI uses the Anthropic wire format with x-api-key auth, not Bearer.
zai: async ({ apiKey, providerSpecificData }: any) => {
try {
// providerSpecificData.baseUrl allows test overrides to point at a local
// HTTP server; production always uses the fixed api.z.ai endpoint.
const messagesUrl = providerSpecificData?.baseUrl
? `${normalizeBaseUrl(providerSpecificData.baseUrl).split("?")[0]}?beta=true`
: "https://api.z.ai/api/anthropic/v1/messages?beta=true";
const res = await directHttpsRequest(
messagesUrl,
{
method: "POST",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "glm-5.1",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
20000
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (res.status === 404 || res.status === 405) {
return { valid: false, error: "Provider validation endpoint not supported" };
}
if (res.status >= 500 && res.status !== 502) {
return { valid: false, error: `Provider unavailable (${res.status})` };
}
// Any non-auth response (200, 400, 422, 429, 502) means auth passed;
// 502 "job timed out" is z.ai's own server-side queue limit, not an auth error.
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
// Xiaomi MiMo — Token Plan keys (tp-*) only work on regional endpoints
// (e.g. token-plan-sgp, token-plan-ams), not api.xiaomimimo.com.
// /v1/models works but validate via chat/completions for stronger auth check.
"xiaomi-mimo": async ({ apiKey, providerSpecificData }: any) => {
try {
const baseUrl = normalizeBaseUrl(
providerSpecificData?.baseUrl || "https://api.xiaomimimo.com/v1"
);
const chatUrl = `${baseUrl.replace(/\/chat\/completions$/, "")}/chat/completions`;
const res = await validationWrite(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: "mimo-v2.5-pro",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
},
gitlab: ({ apiKey, providerSpecificData }: any) =>
validateGitlabProvider({ apiKey, providerSpecificData, isLocal }),
vertex: validateVertexProvider,
"vertex-partner": validateVertexPartnerProvider,
longcat: ({ apiKey, providerSpecificData }: any) =>
validateLongcatProvider({ apiKey, providerSpecificData, isLocal }),
nvidia: validateNvidiaProvider,
zai: validateZaiProvider,
"xiaomi-mimo": ({ apiKey, providerSpecificData }: any) =>
validateXiaomiMimoProvider({ apiKey, providerSpecificData, isLocal }),
// Gitlawb Opengateway — Xiaomi MiMo compatible, same /models endpoint limitation.
// Bypass /models probe in favor of chat/completions, matching xiaomi-mimo's pattern.
// Uses a factory to share validation logic across Opengateway provider variants.
...buildGitlawbValidators([
["gitlawb", "https://opengateway.gitlawb.com/v1/xiaomi-mimo", "mimo-v2.5-pro"],
["gitlawb-gmi", "https://opengateway.gitlawb.com/v1/gmi-cloud", "XiaomiMiMo/MiMo-V2.5-Pro"],
]),
...buildGitlawbValidators(
[
["gitlawb", "https://opengateway.gitlawb.com/v1/xiaomi-mimo", "mimo-v2.5-pro"],
["gitlawb-gmi", "https://opengateway.gitlawb.com/v1/gmi-cloud", "XiaomiMiMo/MiMo-V2.5-Pro"],
],
isLocal
),
// Search providers — use factored validator
...Object.fromEntries(
Object.entries(SEARCH_VALIDATOR_CONFIGS).map(([id, configFn]) => [

View File

@@ -0,0 +1,71 @@
// Kiro runtime probe — falls back to a generateAssistantResponse call when an API key
// cannot list profiles. Extracted from validation.ts (god-file decomposition) — top-level
// function with no dispatcher-state captures; behavior is byte-identical to the original
// inline def.
export async function validateKiroApiKeyRuntimeProbe({
apiKey,
region,
profileArn,
}: {
apiKey: string;
region: string;
profileArn?: string | null;
}) {
const endpoint =
region === "us-east-1"
? "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse"
: `https://q.${region}.amazonaws.com/generateAssistantResponse`;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 15_000);
try {
const body = {
...(profileArn ? { profileArn } : {}),
conversationState: {
chatTriggerType: "MANUAL",
conversationId: crypto.randomUUID(),
currentMessage: {
userInputMessage: {
content: "ping",
modelId: "auto",
origin: "AI_EDITOR",
},
},
history: [],
},
inferenceConfig: {
maxTokens: 1,
},
};
const res = await fetch(endpoint, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
tokentype: "API_KEY",
"Content-Type": "application/x-amz-json-1.0",
"X-Amz-Target": "AmazonCodeWhispererStreamingService.GenerateAssistantResponse",
Accept: "application/vnd.amazon.eventstream",
"Amz-Sdk-Request": "attempt=1; max=3",
"Amz-Sdk-Invocation-Id": crypto.randomUUID(),
},
body: JSON.stringify(body),
signal: controller.signal,
});
await res.body?.cancel().catch(() => undefined);
if (res.ok) {
return { valid: true, error: null, method: "kiro_generate_assistant_response" };
}
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid Kiro API key or AWS region" };
}
if (res.status === 400 || res.status === 422 || res.status === 429) {
return { valid: true, error: null, method: `kiro_generate_assistant_response_${res.status}` };
}
return { valid: false, error: `Kiro validation failed: ${res.status}` };
} finally {
clearTimeout(timeout);
}
}

View File

@@ -0,0 +1,378 @@
// Inline specialty provider validators that previously lived as closures inside the
// SPECIALTY_VALIDATORS map in validation.ts. Extracted (god-file decomposition) as top-level
// functions taking `isLocal` where the original closure captured it; behavior is byte-identical
// to the original inline defs. The host dispatcher still owns the SPECIALTY_VALIDATORS map
// construction + dispatch — these are just the leaf validator bodies.
import { validateQoderCliPat } from "@omniroute/open-sse/services/qoderCli.ts";
import { KiroService } from "@/lib/oauth/services/kiro";
import { resolveNvidiaValidationModel } from "@/lib/providers/nvidiaValidationModel";
import { normalizeBaseUrl } from "./urlHelpers";
import { buildBearerHeaders, directHttpsRequest } from "./headers";
import { toValidationErrorResult, validationRead, validationWrite } from "./transport";
import { validateKiroApiKeyRuntimeProbe } from "./kiro";
export async function validateV0VercelProvider({ apiKey, providerSpecificData, isLocal }: any) {
try {
const configuredBaseUrl =
typeof providerSpecificData?.baseUrl === "string" && providerSpecificData.baseUrl.trim()
? providerSpecificData.baseUrl.trim()
: "https://api.v0.dev";
const root = normalizeBaseUrl(configuredBaseUrl)
.replace(/\/v1\/chat\/completions$/, "")
.replace(/\/v1$/, "");
const res = await validationRead(
`${root}/v1/chats?limit=1`,
{
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
},
isLocal
);
if (res.ok) {
return { valid: true, error: null, method: "v0_platform_chats_list" };
}
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
return { valid: false, error: `v0 validation failed: ${res.status}` };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
// auggie is a fully local, credential-less CLI passthrough — there is no API
// key to check upstream. The only meaningful validation is confirming the
// `auggie` binary is installed and runnable on this machine.
export async function validateAuggieProvider() {
const { checkAuggieCliVersion } = await import("@omniroute/open-sse/executors/auggie.ts");
const result = await checkAuggieCliVersion();
if (!result.ok) {
return {
valid: false,
error: result.error || "Auggie CLI not found. Install it and run `auggie login`.",
unsupported: false,
};
}
return { valid: true, error: null, unsupported: false, method: result.version };
}
export async function validateQoderProvider({ apiKey, providerSpecificData }: any) {
// Bifurcate validation: PAT tokens use Cosy auth against api1.qoder.sh;
// regular API keys validate against dashscope (OpenAI-compatible endpoint).
const key = (apiKey || "").trim();
if (key.startsWith("pt-")) {
return validateQoderCliPat({ apiKey: key, providerSpecificData });
}
// Non-PAT token → validate against dashscope (Alibaba Cloud).
// The executor routes these tokens to dashscope.aliyuncs.com, so the
// validation must test against dashscope, NOT the Cosy PAT endpoint.
try {
const dashscopeUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/models";
const res = await validationRead(
dashscopeUrl,
{
headers: {
Authorization: `Bearer ${key}`,
},
},
false
);
if (res.ok) return { valid: true, error: null };
if (res.status === 401 || res.status === 403) {
return {
valid: false,
error:
"Invalid Qoder API key. Make sure you're using a valid API key from Qoder / Alibaba Cloud Dashscope.",
};
}
// 4xx/5xx other than auth — treat as valid bypass to prevent false
// negatives from transient dashscope issues (consistent with PAT path).
return { valid: true, error: null };
} catch (err: unknown) {
return toValidationErrorResult(err);
}
}
export async function validateKiroProvider({ apiKey, providerSpecificData }: any) {
try {
const region = providerSpecificData?.region || "us-east-1";
const credential = await new KiroService().validateApiKey(apiKey, region);
if (!credential.profileArn) {
return await validateKiroApiKeyRuntimeProbe({
apiKey: credential.accessToken,
region: credential.region,
profileArn: providerSpecificData?.profileArn,
});
}
return {
valid: true,
error: null,
method: "kiro_list_available_profiles",
};
} catch (error: any) {
return toValidationErrorResult(error);
}
}
export async function validateGitlabProvider({ apiKey, providerSpecificData, isLocal }: any) {
try {
const configuredBaseUrl =
typeof providerSpecificData?.baseUrl === "string" ? providerSpecificData.baseUrl.trim() : "";
const root = (configuredBaseUrl || "https://gitlab.com").replace(/\/$/, "");
const res = await validationWrite(
`${root}/api/v4/code_suggestions/direct_access`,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: "{}",
},
isLocal
);
if (res.status === 401) {
return { valid: false, error: "Invalid API key" };
}
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
export async function validateVertexProvider({ apiKey }: any) {
try {
const { parseSAFromApiKey, getAccessToken, isExpressApiKey } =
await import("@omniroute/open-sse/executors/vertex.ts");
// Express-mode API keys are opaque strings sent directly as the ?key= query param — there is
// no JWT to mint, so accept any non-empty Express key (the live chat/media call validates it).
if (isExpressApiKey(apiKey)) {
return { valid: true, error: null };
}
const sa = parseSAFromApiKey(apiKey);
// Validates credentials by successfully successfully exchanging them for a JWT from Google Identity
await getAccessToken(sa);
return { valid: true, error: null };
} catch (error: any) {
return { valid: false, error: "Invalid Service Account JSON: " + error.message };
}
}
export async function validateVertexPartnerProvider({ apiKey }: any) {
try {
const { parseSAFromApiKey, getAccessToken, isExpressApiKey } =
await import("@omniroute/open-sse/executors/vertex.ts");
if (isExpressApiKey(apiKey)) {
return { valid: true, error: null };
}
const sa = parseSAFromApiKey(apiKey);
await getAccessToken(sa);
return { valid: true, error: null };
} catch (error: any) {
return { valid: false, error: "Invalid Service Account JSON: " + error.message };
}
}
// LongCat AI — does not expose /v1/models; validate via chat completions directly (#592)
export async function validateLongcatProvider({ apiKey, providerSpecificData, isLocal }: any) {
try {
const res = await validationWrite(
"https://api.longcat.chat/openai/v1/chat/completions",
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: "LongCat-2.0",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
// NVIDIA NIM (#2463) — bypass the /models probe in favor of a direct
// chat/completions probe. NVIDIA NIM's /models endpoint returns model
// catalogs that vary by region and key-tier, and some keys 404 on it,
// which the generic flow misreads. The chat probe is also a stronger
// sanity check for streaming/key correctness.
export async function validateNvidiaProvider({ apiKey, providerSpecificData }: any) {
try {
const baseUrlRaw =
providerSpecificData?.baseUrl || "https://integrate.api.nvidia.com/v1/chat/completions";
const normalized = normalizeBaseUrl(baseUrlRaw);
const chatBase = normalized.replace(/\/models$/, "");
const chatUrl = normalized.endsWith("/chat/completions")
? normalized
: `${chatBase}/chat/completions`;
// #3116: probe a universally-available model rather than models[0]
// (z-ai/glm-5.1), which requires the "Public API Endpoints" account permission
// and can hang/be DEGRADED — making a *valid* key fail with "Upstream Error".
const modelId = resolveNvidiaValidationModel(providerSpecificData);
// #3226: use raw https (bypass the proxy/TLS-patched fetch) — the undici
// dispatcher stalls against NVIDIA's endpoint, causing a 504 timeout.
const res = await directHttpsRequest(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: modelId,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
20000
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
// Z.AI (glm) — bypass the proxy/TLS-patched fetch for the same reason as nvidia
// above (#3905): the undici dispatcher stalls against api.z.ai after the provider
// returns 502 "job timed out" responses, because z.ai silently drops idle
// keep-alive sockets without sending TCP RST. Using directHttpsRequest (native
// Node.js HTTPS, no undici pool) avoids the zombie-socket hang on validation.
// Z.AI uses the Anthropic wire format with x-api-key auth, not Bearer.
export async function validateZaiProvider({ apiKey, providerSpecificData }: any) {
try {
// providerSpecificData.baseUrl allows test overrides to point at a local
// HTTP server; production always uses the fixed api.z.ai endpoint.
const messagesUrl = providerSpecificData?.baseUrl
? `${normalizeBaseUrl(providerSpecificData.baseUrl).split("?")[0]}?beta=true`
: "https://api.z.ai/api/anthropic/v1/messages?beta=true";
const res = await directHttpsRequest(
messagesUrl,
{
method: "POST",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "glm-5.1",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
20000
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
if (res.status === 404 || res.status === 405) {
return { valid: false, error: "Provider validation endpoint not supported" };
}
if (res.status >= 500 && res.status !== 502) {
return { valid: false, error: `Provider unavailable (${res.status})` };
}
// Any non-auth response (200, 400, 422, 429, 502) means auth passed;
// 502 "job timed out" is z.ai's own server-side queue limit, not an auth error.
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
// Xiaomi MiMo — Token Plan keys (tp-*) only work on regional endpoints
// (e.g. token-plan-sgp, token-plan-ams), not api.xiaomimimo.com.
// /v1/models works but validate via chat/completions for stronger auth check.
export async function validateXiaomiMimoProvider({ apiKey, providerSpecificData, isLocal }: any) {
try {
const baseUrl = normalizeBaseUrl(
providerSpecificData?.baseUrl || "https://api.xiaomimimo.com/v1"
);
const chatUrl = `${baseUrl.replace(/\/chat\/completions$/, "")}/chat/completions`;
const res = await validationWrite(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model: "mimo-v2.5-pro",
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
}
/**
* Build Opengateway-style validators (xiaomi-mimo compatible).
* These providers share a POST /chat/completions auth check pattern and differ
* only in default baseUrl and test model name.
*/
export function buildOpengatewayValidator(defaultBaseUrl: string, model: string) {
return async ({ apiKey, providerSpecificData, isLocal }: any) => {
try {
const baseUrl = normalizeBaseUrl(providerSpecificData?.baseUrl || defaultBaseUrl);
const chatUrl = `${baseUrl.replace(/\/chat\/completions$/, "")}/chat/completions`;
const res = await validationWrite(
chatUrl,
{
method: "POST",
headers: buildBearerHeaders(apiKey, providerSpecificData),
body: JSON.stringify({
model,
messages: [{ role: "user", content: "test" }],
max_tokens: 1,
}),
},
isLocal
);
if (res.status === 401 || res.status === 403) {
return { valid: false, error: "Invalid API key" };
}
// Any non-auth response (200, 400, 422, 429) means auth passed
return { valid: true, error: null };
} catch (error: any) {
return toValidationErrorResult(error);
}
};
}
// Same as buildOpengatewayValidator but returns an object spreadable into SPECIALTY_VALIDATORS.
// isLocal is captured via closure from the outer function scope.
export function buildGitlawbValidators(
configs: [string, string, string][],
isLocal: boolean
): Record<string, ReturnType<typeof buildOpengatewayValidator>> {
return Object.fromEntries(
configs.map(([id, baseUrl, model]) => [
id,
(({ apiKey, providerSpecificData }: any) =>
buildOpengatewayValidator(
baseUrl,
model
)({ apiKey, providerSpecificData, isLocal })) as ReturnType<
typeof buildOpengatewayValidator
>,
])
);
}

View File

@@ -0,0 +1,152 @@
// Web-cookie session-ping validator + Bytez auth-only probe. Extracted from validation.ts
// (god-file decomposition) — top-level functions with no dispatcher-state captures; behavior is
// byte-identical to the original inline defs.
import { WEB_COOKIE_PROVIDERS, isLocalProvider } from "@/shared/constants/providers";
import { getRegistryEntry } from "@omniroute/open-sse/config/providerRegistry.ts";
import { normalizeBaseUrl } from "./urlHelpers";
import { STANDARD_USER_AGENT, buildBearerHeaders } from "./headers";
import {
validationRead,
toValidationErrorResult,
toWebCookieValidationErrorResult,
WEB_COOKIE_PROVIDERS_WITHOUT_MODELS_API,
} from "./transport";
/**
* Validates web-cookie providers by performing a ping request to check if the session is still valid.
* Returns SESSION_EXPIRED error code if the upstream returns 401/403.
*/
export async function validateWebCookieProvider({
provider,
apiKey,
providerSpecificData: _providerSpecificData = {},
}: {
provider: string;
apiKey?: string;
providerSpecificData?: Record<string, unknown>;
}) {
try {
const entry = getRegistryEntry(provider);
const cookieProvider = WEB_COOKIE_PROVIDERS[provider as keyof typeof WEB_COOKIE_PROVIDERS];
if (!entry && !cookieProvider) {
return { valid: false, error: "Provider not found in registry", unsupported: true };
}
// For web-cookie providers, apiKey contains the cookie string
const cookie = (apiKey || "").trim();
if (!cookie) {
return { valid: false, error: "Cookie required for web-cookie provider", unsupported: false };
}
if (!entry) {
// Providers listed in WEB_COOKIE_PROVIDERS without a providerRegistry entry (e.g.
// gemini-business, poe-web, venice-web, v0-vercel-web) only expose a
// marketing website URL, not a real API host. Probing `${website}/models`
// does not reliably signal session validity for these —
// live verification showed most return redirects or SPA 200s regardless of
// cookie validity, which would silently report an expired/garbage cookie as
// "OK" (worse than an honest "not supported"). Until each of these providers
// has a verified, side-effect-free auth probe against its real API host, report
// unsupported instead of a false positive.
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
// Attempt a minimal request to check if the session is valid
// Use /models endpoint or a minimal completion request depending on the provider
const baseUrl = normalizeBaseUrl(entry.baseUrl || "");
// Defense-in-depth: only an http(s) baseUrl without a query string is safe to
// probe by blindly appending `/models`. A ws(s):// baseUrl (e.g. copilot-web) is
// already rejected by the outbound URL guard downstream, but reject it explicitly
// here for the honest "unsupported" result instead of a confusing security-block
// message — this also covers a future http(s) baseUrl carrying a query string,
// which the guard does not currently block (#7857 acceptance criteria).
if (!/^https?:\/\//i.test(baseUrl) || baseUrl.includes("?")) {
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
const testUrl = `${baseUrl}/models`;
const res = await validationRead(
testUrl,
{
method: "GET",
headers: {
"User-Agent": STANDARD_USER_AGENT,
Cookie: cookie,
},
},
isLocalProvider(provider)
);
if (res.status === 401 || res.status === 403) {
return {
valid: false,
error: "SESSION_EXPIRED",
errorCode: "AUTH_007",
unsupported: false,
};
}
// #7857: for providers whose baseUrl is a conversation/completion endpoint rather
// than a real API root, the /models path never existed upstream — a redirect,
// login-HTML 200, 404, 405, or 429 from it is not a meaningful auth signal and is
// indistinguishable from a genuinely valid session. Report the same honest
// "unsupported" result the !entry branch above already gives its no-registry
// siblings, instead of a false `valid: true`.
if (WEB_COOKIE_PROVIDERS_WITHOUT_MODELS_API.has(provider)) {
return {
valid: false,
error: "Provider validation not supported",
unsupported: true,
};
}
// Any other response (200, 404, 405, 429, ...) means the cookie was accepted —
// a 401/403 from the /models probe is the only definitive "session expired" signal
// for web-cookie auth, so a non-auth status is treated as a valid session.
return { valid: true, error: null, unsupported: false };
} catch (error: unknown) {
return toWebCookieValidationErrorResult(provider, error);
}
}
// #5422: Bytez key validation cannot use a chat probe. A Bytez account only serves models
// that have been added to its catalog, so even Bytez's own documented model ids return 404
// ("Model does not exist or has yet to be added to the Bytez catalog") for a fresh/free key —
// the generic OpenAI-like chat probe misreads that 404 as "endpoint not supported". Validate
// against the model-independent, auth-only tasks endpoint instead (verified live):
// GET …/models/v2/list/tasks → 200 (valid key) | 401 { error: "Unauthorized" } (invalid).
// The pure status→result mapping is factored out so it is unit-testable without network.
export function bytezValidationResultFromStatus(status: number): {
valid: boolean;
error: string | null;
} {
if (status === 200) {
return { valid: true, error: null };
}
if (status === 401 || status === 403) {
return { valid: false, error: "Invalid API key" };
}
return { valid: false, error: `Validation failed: ${status}` };
}
export async function validateBytezProvider({ apiKey, providerSpecificData = {} }: any) {
try {
const res = await validationRead("https://api.bytez.com/models/v2/list/tasks", {
method: "GET",
headers: buildBearerHeaders(apiKey, providerSpecificData),
});
return bytezValidationResultFromStatus(res.status);
} catch (error: unknown) {
return toValidationErrorResult(error);
}
}

View File

@@ -0,0 +1,100 @@
// Characterization of the validation.ts kiro runtime-probe split (god-file decomposition):
// validateKiroApiKeyRuntimeProbe moved into validation/kiro.ts as a top-level function (it was
// previously a module-private helper inside validation.ts). Behavior-preserving move — the lock
// here is module surface; the runtime behavior stays covered by the provider-validation-specialty
// kiro suites.
import { test } from "node:test";
import assert from "node:assert/strict";
const M = await import("../../src/lib/providers/validation/kiro.ts");
const HOST = await import("../../src/lib/providers/validation.ts");
test("kiro leaf exposes validateKiroApiKeyRuntimeProbe", () => {
assert.equal(typeof M.validateKiroApiKeyRuntimeProbe, "function");
});
test("host dispatcher surface stays intact after the move", () => {
assert.equal(typeof (HOST as Record<string, unknown>).validateProviderApiKey, "function");
});
test("validateKiroApiKeyRuntimeProbe: 200 returns valid with method tag", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = (async () =>
new Response(new ReadableStream(), { status: 200 })) as typeof fetch;
try {
const result = await M.validateKiroApiKeyRuntimeProbe({
apiKey: "ksk-valid",
region: "us-east-1",
});
assert.equal(result.valid, true);
assert.equal(result.error, null);
assert.equal(result.method, "kiro_generate_assistant_response");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateKiroApiKeyRuntimeProbe: 401/403 → invalid Kiro key/region", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = (async () =>
new Response(JSON.stringify({ message: "denied" }), { status: 403 })) as typeof fetch;
try {
const result = await M.validateKiroApiKeyRuntimeProbe({
apiKey: "ksk-bad",
region: "eu-west-1",
});
assert.equal(result.valid, false);
assert.equal(result.error, "Invalid Kiro API key or AWS region");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateKiroApiKeyRuntimeProbe: 400/422/429 treated as valid (auth passed)", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = (async () => new Response("{}", { status: 429 })) as typeof fetch;
try {
const result = await M.validateKiroApiKeyRuntimeProbe({
apiKey: "ksk-rate-limited",
region: "us-east-1",
});
assert.equal(result.valid, true);
assert.equal(result.error, null);
assert.match(result.method || "", /kiro_generate_assistant_response_429/);
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateKiroApiKeyRuntimeProbe: us-east-1 targets the codewhisperer endpoint", async () => {
const originalFetch = globalThis.fetch;
let calledUrl = "";
globalThis.fetch = (async (url: URL | string) => {
calledUrl = String(url);
return new Response(new ReadableStream(), { status: 200 });
}) as typeof fetch;
try {
await M.validateKiroApiKeyRuntimeProbe({ apiKey: "k", region: "us-east-1" });
assert.equal(
calledUrl,
"https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse"
);
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateKiroApiKeyRuntimeProbe: non-us-east-1 targets the regional q endpoint", async () => {
const originalFetch = globalThis.fetch;
let calledUrl = "";
globalThis.fetch = (async (url: URL | string) => {
calledUrl = String(url);
return new Response(new ReadableStream(), { status: 200 });
}) as typeof fetch;
try {
await M.validateKiroApiKeyRuntimeProbe({ apiKey: "k", region: "eu-west-1" });
assert.equal(calledUrl, "https://q.eu-west-1.amazonaws.com/generateAssistantResponse");
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,69 @@
// Characterization of the validation.ts specialty-inline split (god-file decomposition): the
// inline SPECIALTY_VALIDATORS closures (v0-vercel, auggie, qoder, kiro wrapper, gitlab, vertex,
// vertex-partner, longcat, nvidia, zai, xiaomi-mimo, gitlawb factory) moved into
// validation/specialtyInline.ts as top-level functions taking `isLocal` where the original
// closure captured it. Behavior-preserving move — the locks here are module surface; the runtime
// behavior stays covered by provider-validation-specialty / provider-validation-azure-vertex /
// nvidia-validation-* / zai-validator / xiaomi-mimo-provider suites.
import { test } from "node:test";
import assert from "node:assert/strict";
const M = await import("../../src/lib/providers/validation/specialtyInline.ts");
const HOST = await import("../../src/lib/providers/validation.ts");
test("specialtyInline exposes the extracted leaf validators", () => {
for (const name of [
"validateV0VercelProvider",
"validateAuggieProvider",
"validateQoderProvider",
"validateKiroProvider",
"validateGitlabProvider",
"validateVertexProvider",
"validateVertexPartnerProvider",
"validateLongcatProvider",
"validateNvidiaProvider",
"validateZaiProvider",
"validateXiaomiMimoProvider",
"buildOpengatewayValidator",
"buildGitlawbValidators",
]) {
assert.equal(typeof (M as Record<string, unknown>)[name], "function", `missing ${name}`);
}
});
test("host dispatcher surface stays intact after the move", () => {
assert.equal(typeof (HOST as Record<string, unknown>).validateProviderApiKey, "function");
});
test("buildGitlawbValidators returns one entry per config id", () => {
const map = M.buildGitlawbValidators(
[
["gitlawb", "https://opengateway.gitlawb.com/v1/xiaomi-mimo", "mimo-v2.5-pro"],
["gitlawb-gmi", "https://opengateway.gitlawb.com/v1/gmi-cloud", "XiaomiMiMo/MiMo-V2.5-Pro"],
],
false
);
assert.deepEqual(Object.keys(map).sort(), ["gitlawb", "gitlawb-gmi"]);
assert.equal(typeof map.gitlawb, "function");
assert.equal(typeof map["gitlawb-gmi"], "function");
});
test("validateVertexProvider: Express-mode key is accepted without JWT mint", async () => {
const result = await M.validateVertexProvider({ apiKey: "opaque-express-key" });
assert.equal(result.valid, true);
assert.equal(result.error, null);
});
test("validateVertexPartnerProvider: Express-mode key is accepted without JWT mint", async () => {
const result = await M.validateVertexPartnerProvider({ apiKey: "opaque-express-key" });
assert.equal(result.valid, true);
assert.equal(result.error, null);
});
test("validateVertexProvider: malformed Service Account JSON is rejected", async () => {
const result = await M.validateVertexProvider({
apiKey: '{"type":"service_account","project_id":"p"}',
});
assert.equal(result.valid, false);
assert.match(result.error || "", /Invalid Service Account JSON/i);
});

View File

@@ -0,0 +1,52 @@
// Characterization of the validation.ts web-cookie + bytez split (god-file decomposition):
// validateWebCookieProvider, bytezValidationResultFromStatus, and validateBytezProvider moved
// into validation/webCookie.ts. Behavior-preserving move — the locks here are module surface +
// the pure status→result mapping; the runtime behavior stays covered by the
// provider-validation-web-cookie-auth007 / web-cookie-validation-fallback / bytez-validation-5422
// suites.
import { test } from "node:test";
import assert from "node:assert/strict";
const M = await import("../../src/lib/providers/validation/webCookie.ts");
const HOST = await import("../../src/lib/providers/validation.ts");
test("webCookie exposes validateWebCookieProvider, bytezValidationResultFromStatus, validateBytezProvider", () => {
for (const name of [
"validateWebCookieProvider",
"bytezValidationResultFromStatus",
"validateBytezProvider",
]) {
assert.equal(typeof (M as Record<string, unknown>)[name], "function", `missing ${name}`);
}
});
test("host re-exports validateWebCookieProvider + bytezValidationResultFromStatus (historical public surface)", () => {
assert.equal(
(HOST as Record<string, unknown>).validateWebCookieProvider,
(M as Record<string, unknown>).validateWebCookieProvider
);
assert.equal(
(HOST as Record<string, unknown>).bytezValidationResultFromStatus,
(M as Record<string, unknown>).bytezValidationResultFromStatus
);
});
test("bytezValidationResultFromStatus: 200 valid, 401/403 invalid key, other generic failure", () => {
assert.deepEqual(M.bytezValidationResultFromStatus(200), { valid: true, error: null });
assert.deepEqual(M.bytezValidationResultFromStatus(401), {
valid: false,
error: "Invalid API key",
});
assert.deepEqual(M.bytezValidationResultFromStatus(403), {
valid: false,
error: "Invalid API key",
});
assert.deepEqual(M.bytezValidationResultFromStatus(500), {
valid: false,
error: "Validation failed: 500",
});
});
test("host dispatcher surface stays intact after the move", () => {
assert.equal(typeof (HOST as Record<string, unknown>).validateProviderApiKey, "function");
});