import { createHash } from "node:crypto"; import type { OcxProviderConfig, ProviderTlsProfile } from "../types"; import { resolvePublicAddresses } from "./destination-policy"; import { registerOptionalShutdownHook } from "./optional-shutdown-hooks"; import { proxyForUrl } from "./proxy-env"; import { redactErrorMessage } from "./redact"; export const ANTIGRAVITY_TLS_HOSTS = new Set([ "daily-cloudcode-pa.googleapis.com", "cloudcode-pa.googleapis.com", ]); export type ProviderTlsProfileStatus = "disabled" | "active" | "fallback"; interface WreqTransport { close(): Promise; } interface WreqModule { createTransport(options: { browser: "chrome_142"; os: "windows" | "macos" | "linux"; proxy?: string; resolve?: Record; }): Promise; fetch(input: string | URL | Request, init?: Record): Promise; } interface InitializedTransport { module: WreqModule; transport: WreqTransport; } type ProviderTlsContract = Pick; type AntigravityOAuthDestinationContract = Pick & Partial>; export interface ProviderTlsRuntimeForTest { importWreq: () => Promise; resolveDestination?: typeof resolvePublicAddresses; } const defaultRuntime: ProviderTlsRuntimeForTest = { importWreq: async () => await import("wreq-js") as unknown as WreqModule, }; let runtime = defaultRuntime; const statusByProvider = new Map(); const transports = new Map>(); const requestTransports = new Set(); let modulePromise: Promise | undefined; let shutdownDetach: (() => void) | undefined; let fallbackWarned = false; function providerTlsContractFingerprint(providerName: string, provider: ProviderTlsContract): string { return createHash("sha256").update(JSON.stringify([ providerName, provider.adapter, provider.authMode, provider.googleMode, provider.baseUrl, provider.tlsProfile, ])).digest("hex"); } function setStatus(providerName: string, provider: ProviderTlsContract, status: ProviderTlsProfileStatus): void { statusByProvider.set(providerName, { status, fingerprint: providerTlsContractFingerprint(providerName, provider) }); } const SAFE_NATIVE_ERROR_NAMES = new Set(["AbortError", "TimeoutError"]); const SAFE_NATIVE_ERROR_CODES = new Set([ "ABORT_ERR", "ECONNREFUSED", "ECONNRESET", "EAI_AGAIN", "ENETUNREACH", "ENOTFOUND", "ETIMEDOUT", "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_SOCKET", ]); function safeProviderTlsError(error: unknown): Error { const raw = error instanceof Error ? error.message : String(error); const safe = new Error(redactErrorMessage(raw)); if (!error || typeof error !== "object") return safe; const native = error as { name?: unknown; code?: unknown }; if (typeof native.name === "string" && SAFE_NATIVE_ERROR_NAMES.has(native.name)) { safe.name = native.name; } if (typeof native.code === "string" && SAFE_NATIVE_ERROR_CODES.has(native.code)) { Object.defineProperty(safe, "code", { configurable: true, enumerable: false, value: native.code, writable: false, }); } return safe; } function warnFallbackOnce(): void { if (fallbackWarned) return; fallbackWarned = true; console.warn("[opencodex] Antigravity TLS profile request blocked: native transport initialization failed"); } function emulationOs(): "windows" | "macos" | "linux" { if (process.platform === "win32") return "windows"; if (process.platform === "darwin") return "macos"; if (process.platform === "linux") return "linux"; throw new Error("unsupported host operating system for Antigravity TLS profile"); } function profileIsSupported(providerName: string, provider: Pick): boolean { return providerName === "google-antigravity" && provider.adapter === "google" && provider.authMode === "oauth" && provider.googleMode === "cloud-code-assist" && isCanonicalAntigravityUrl(provider.baseUrl) && provider.tlsProfile === "antigravity-browser"; } export function providerTlsProfileConfigError( providerName: string, provider: Pick, ): string | null { if (provider.tlsProfile === undefined) return null; if (provider.tlsProfile !== "antigravity-browser") { return "tlsProfile must be antigravity-browser"; } if (providerName !== "google-antigravity") return "tlsProfile antigravity-browser is valid only for google-antigravity"; if (provider.adapter !== "google" || provider.authMode !== "oauth") { return "tlsProfile antigravity-browser requires Google OAuth authentication"; } if (provider.googleMode !== "cloud-code-assist") { return "tlsProfile antigravity-browser requires Google Cloud Code Assist mode"; } if (!isCanonicalAntigravityUrl(provider.baseUrl)) { return "tlsProfile antigravity-browser requires a canonical Antigravity HTTPS destination"; } return null; } export function isCanonicalAntigravityUrl(input: string | URL): boolean { try { const url = new URL(input); return url.protocol === "https:" && (url.port === "" || url.port === "443") && url.username === "" && url.password === "" && ANTIGRAVITY_TLS_HOSTS.has(url.hostname.toLowerCase()); } catch { return false; } } export function isLoopbackAntigravityUrl(input: string | URL): boolean { try { const url = new URL(input); const host = url.hostname.toLowerCase(); // Loopback allowlist for tests: 127.0.0.1, localhost, ::1, 0.0.0.0. // Accept http or https so mock servers (http://127.0.0.1:port) pass the canonical gate // while still keeping the production hardening (attacker hosts remain rejected). if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1" && host !== "0.0.0.0" && host !== "[::1]") { return false; } return url.username === "" && url.password === ""; } catch { return false; } } export function isAntigravityOAuthProvider( providerName: string, provider: Pick, ): boolean { return providerName === "google-antigravity" && (provider.authMode === undefined || provider.authMode === "oauth"); } /** Same-name Antigravity rows are OAuth destinations even when legacy config omitted authMode. */ export function antigravityOAuthDestinationConfigError( providerName: string, provider: AntigravityOAuthDestinationContract, ): string | null { if (providerName !== "google-antigravity") return null; if (provider.googleMode !== undefined && provider.googleMode !== "cloud-code-assist") { return "requires Google Cloud Code Assist mode for OAuth"; } if (!isCanonicalAntigravityUrl(provider.baseUrl) && !isLoopbackAntigravityUrl(provider.baseUrl)) { return "requires a canonical Antigravity HTTPS destination for OAuth"; } return null; } export function getProviderTlsProfileStatus(providerName: string, provider: ProviderTlsContract): ProviderTlsProfileStatus { const current = statusByProvider.get(providerName); return current?.fingerprint === providerTlsContractFingerprint(providerName, provider) ? current.status : "disabled"; } export function clearProviderTlsProfileStatus(providerName: string): void { statusByProvider.delete(providerName); } function registerShutdownHook(): void { if (shutdownDetach) return; shutdownDetach = registerOptionalShutdownHook("provider-tls-profile", () => { const pending = [...transports.values()]; transports.clear(); const scoped = [...requestTransports]; requestTransports.clear(); shutdownDetach = undefined; for (const transport of pending) { void transport.then(value => value?.transport.close()).catch(() => undefined); } for (const transport of scoped) void transport.close().catch(() => undefined); }); } function transportKey(proxy: string | undefined): string { return `${process.platform}:${proxy ?? "direct"}`; } async function getTransport(proxy: string | undefined): Promise { const key = transportKey(proxy); const existing = transports.get(key); if (existing) return existing; const pending = (async () => { let transport: WreqTransport | undefined; try { const module = await getWreqModule(); if (!module) return undefined; transport = await module.createTransport({ browser: "chrome_142", os: emulationOs(), ...(proxy ? { proxy } : {}), }); registerShutdownHook(); return { module, transport }; } catch { if (transport) await transport.close().catch(() => undefined); return undefined; } })(); transports.set(key, pending); return pending; } function getWreqModule(): Promise { modulePromise ??= runtime.importWreq().catch(() => undefined); return modulePromise; } async function getPinnedRequestTransport( hostname: string, addresses: string[], ): Promise { let transport: WreqTransport | undefined; try { const module = await getWreqModule(); if (!module) return undefined; transport = await module.createTransport({ browser: "chrome_142", os: emulationOs(), resolve: { [hostname]: addresses }, }); requestTransports.add(transport); registerShutdownHook(); return { module, transport }; } catch { if (transport) await transport.close().catch(() => undefined); return undefined; } } function closeTransportWithResponse(response: Response, transport: WreqTransport): Response { const close = () => { if (!requestTransports.delete(transport)) return; void transport.close().catch(() => undefined); }; if (!response.body) { close(); return response; } const reader = response.body.getReader(); const body = new ReadableStream({ async pull(controller) { try { const chunk = await reader.read(); if (chunk.done) { close(); controller.close(); } else { controller.enqueue(chunk.value); } } catch (error) { close(); controller.error(error); } }, async cancel(reason) { try { await reader.cancel(reason); } finally { close(); } }, }); return new Response(body, { status: response.status, statusText: response.statusText, headers: response.headers, }); } export function providerTlsFetch( providerName: string, provider: Pick, bunFetch: typeof globalThis.fetch, ): typeof globalThis.fetch { const antigravityError = antigravityOAuthDestinationConfigError(providerName, provider); if (antigravityError) { return (async () => { throw new Error(`provider ${providerName} ${antigravityError}`); }) as unknown as typeof globalThis.fetch; } if (provider.tlsProfile === undefined) { setStatus(providerName, provider, "disabled"); return bunFetch; } if (!profileIsSupported(providerName, provider)) { setStatus(providerName, provider, "fallback"); warnFallbackOnce(); return (async () => { throw safeProviderTlsError(new Error("configured native transport profile is not valid for this provider")); }) as unknown as typeof globalThis.fetch; } return (async (input: string | URL | Request, init?: RequestInit): Promise => { const url = typeof input === "string" || input instanceof URL ? input : input.url; if (!isCanonicalAntigravityUrl(url)) { throw safeProviderTlsError(new Error("configured native transport profile refused a noncanonical destination")); } const proxy = proxyForUrl(url); // A direct profiled request must pass the same public-destination gate as the // ordinary provider executor before wreq can send its bearer-bearing request. // Proxied requests deliberately leave peer selection to the configured proxy, // matching providerOutbound's proxy boundary (and its inability to pin a peer). const parsed = new URL(String(url)); const resolved = !proxy ? await (runtime.resolveDestination ?? resolvePublicAddresses)(String(url), { context: "Antigravity profile URL", allowPrivateNetwork: false, }) : undefined; const initialized = resolved ? await getPinnedRequestTransport(parsed.hostname, resolved.addresses.map(address => address.address)) : await getTransport(proxy); if (!initialized) { setStatus(providerName, provider, "fallback"); warnFallbackOnce(); throw safeProviderTlsError(new Error("native transport initialization failed")); } setStatus(providerName, provider, "active"); const wreqInit = { ...init, transport: initialized.transport, disableDefaultHeaders: true, cookieMode: "ephemeral" as const, redirect: "manual" as const, }; try { const response = await initialized.module.fetch(input, wreqInit) as Response; return resolved ? closeTransportWithResponse(response, initialized.transport) : response; } catch (error) { if (resolved && requestTransports.delete(initialized.transport)) { void initialized.transport.close().catch(() => undefined); } // Native errors are post-dispatch failures. Redact at this boundary and // never replay through Bun, since generation may already have started. throw safeProviderTlsError(error); } }) as typeof globalThis.fetch; } export function setProviderTlsRuntimeForTest(next: ProviderTlsRuntimeForTest | undefined): void { if (next === undefined) { runtime = defaultRuntime; modulePromise = undefined; return; } // Test callers normally replace only the native module. Keep those tests // deterministic in offline sandboxes while allowing explicit DNS policy // regressions to inject a rejecting resolver. runtime = { ...defaultRuntime, resolveDestination: async (url: string) => ({ hostname: new URL(url).hostname, addresses: [{ address: "142.250.1.1", family: 4 }], privateNetwork: false, }), ...next, }; modulePromise = undefined; } export function resetProviderTlsProfileForTests(): void { for (const pending of transports.values()) void pending.then(value => value?.transport.close()).catch(() => undefined); transports.clear(); for (const transport of requestTransports) void transport.close().catch(() => undefined); requestTransports.clear(); modulePromise = undefined; shutdownDetach?.(); shutdownDetach = undefined; statusByProvider.clear(); fallbackWarned = false; runtime = defaultRuntime; } export type { ProviderTlsProfile };