From 354b583f76957a9ce7d8b4f24201e9ea59d64113 Mon Sep 17 00:00:00 2001 From: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:09:06 -0300 Subject: [PATCH] style(release): normalize post-freeze Codex paths (#8875) --- open-sse/executors/codex-app-server.ts | 22 +++--- open-sse/executors/codex/appServerClient.ts | 13 +++- open-sse/executors/codex/appServerConfig.ts | 19 ++++- .../[id]/test/codexAppServerHealth.ts | 18 +++-- stryker.conf.json | 2 +- tests/unit/codex-app-server.test.ts | 73 ++++++++++--------- 6 files changed, 87 insertions(+), 60 deletions(-) diff --git a/open-sse/executors/codex-app-server.ts b/open-sse/executors/codex-app-server.ts index abd7ef1fd8..ee43afa31e 100644 --- a/open-sse/executors/codex-app-server.ts +++ b/open-sse/executors/codex-app-server.ts @@ -1,17 +1,15 @@ -import { - bridgeToResponsesSSE, - buildResponseJSON, -} from "../vendor/codex-chatgpt-web/bridge.ts"; +import { bridgeToResponsesSSE, buildResponseJSON } from "../vendor/codex-chatgpt-web/bridge.ts"; import { AsyncEventQueue } from "../vendor/codex-chatgpt-web/event-queue.ts"; import type { AdapterEvent } from "../vendor/codex-chatgpt-web/types.ts"; import { sanitizeErrorMessage } from "../utils/error.ts"; import { PROVIDERS } from "../config/constants.ts"; import { BaseExecutor, type ExecuteInput, type ExecutorExecuteResult } from "./base.ts"; +import { CodexAppServerClient, type CodexAppServerClientOptions } from "./codex/appServerClient.ts"; import { - CodexAppServerClient, - type CodexAppServerClientOptions, -} from "./codex/appServerClient.ts"; -import { resolveAppServerConfig, resolveThreadStartPolicy, type CodexAppServerConfig } from "./codex/appServerConfig.ts"; + resolveAppServerConfig, + resolveThreadStartPolicy, + type CodexAppServerConfig, +} from "./codex/appServerConfig.ts"; import { translateNotification, translateToolCall, @@ -283,9 +281,7 @@ export class CodexAppServerExecutor extends BaseExecutor { // Harness function tools are advertised via thread/start's `dynamicTools`, // which is an EXPERIMENTAL app-server field: opt into experimental API so // codex accepts it (and can emit the item/tool/call ServerRequest). - capabilities: hasTools - ? { experimentalApi: true, requestAttestation: false } - : null, + capabilities: hasTools ? { experimentalApi: true, requestAttestation: false } : null, }); const threadResult = (await client.request("thread/start", { cwd: config.cwd, @@ -339,7 +335,9 @@ export class CodexAppServerExecutor extends BaseExecutor { // request (the stateless-full-history contract every OmniRoute provider uses). client.onToolCall((_id, params, api) => { if (terminated) return; - const toolParams = (params && typeof params === "object" ? params : {}) as DynamicToolCallLike; + const toolParams = ( + params && typeof params === "object" ? params : {} + ) as DynamicToolCallLike; translateToolCall(toolParams, (event) => events.push(event)); // Settle the app-server request so the socket does not stall. The router // does not have the tool output (the harness will produce it next turn), diff --git a/open-sse/executors/codex/appServerClient.ts b/open-sse/executors/codex/appServerClient.ts index e0fd44ae34..093b12be19 100644 --- a/open-sse/executors/codex/appServerClient.ts +++ b/open-sse/executors/codex/appServerClient.ts @@ -53,8 +53,7 @@ const APPROVAL_REQUEST_METHODS = new Set([ ]); const ROUTER_APPROVAL_NOTE = "router: harness-controlled execution"; -const ROUTER_DENIAL_NOTE = - "router: denied by default (set codexAppServerAutoApprove to opt in)"; +const ROUTER_DENIAL_NOTE = "router: denied by default (set codexAppServerAutoApprove to opt in)"; export interface CodexAppServerClientOptions { /** Transport factory. Defaults to the shared wreq-js websocket() when omitted. */ @@ -137,7 +136,11 @@ export class CodexAppServerClient { } /** Send a ClientRequest and resolve when its id-matched response arrives. */ - request(method: string, params: unknown, timeoutMs = this.defaultTimeoutMs): Promise { + request( + method: string, + params: unknown, + timeoutMs = this.defaultTimeoutMs + ): Promise { const id = this.nextId++; return new Promise((resolve, reject) => { if (!this.ws || this.closed) { @@ -216,7 +219,9 @@ export class CodexAppServerClient { this.pending.delete(id); if (msg.error) { const err = msg.error as { code?: unknown; message?: unknown }; - pending.reject(new Error(`${String(err.code ?? "error")}: ${String(err.message ?? "unknown")}`)); + pending.reject( + new Error(`${String(err.code ?? "error")}: ${String(err.message ?? "unknown")}`) + ); } else { pending.resolve(msg.result); } diff --git a/open-sse/executors/codex/appServerConfig.ts b/open-sse/executors/codex/appServerConfig.ts index 772326dab7..55c4217bf8 100644 --- a/open-sse/executors/codex/appServerConfig.ts +++ b/open-sse/executors/codex/appServerConfig.ts @@ -156,7 +156,10 @@ export function isLocalAppServerHost(hostname: string): boolean { * psd-sourced token may go anywhere: whoever wrote the psd already knows it. */ export function resolveAppServerConfig(psd: ProviderSpecificData): CodexAppServerConfig | null { - const urlRes = firstStringWithSource(psd?.codexAppServerUrl, process.env.OMNIROUTE_CODEX_APPSERVER_WS); + const urlRes = firstStringWithSource( + psd?.codexAppServerUrl, + process.env.OMNIROUTE_CODEX_APPSERVER_WS + ); if (!urlRes || !isWebSocketUrl(urlRes.value)) return null; const tokenRes = resolveTokenWithSource(psd); @@ -174,13 +177,21 @@ export function resolveAppServerConfig(psd: ProviderSpecificData): CodexAppServe firstString(psd?.codexAppServerCwd, process.env.OMNIROUTE_CODEX_APPSERVER_CWD) ?? "/tmp"; const approvalPolicy = - firstString(psd?.codexAppServerApprovalPolicy, process.env.OMNIROUTE_CODEX_APPSERVER_APPROVAL) ?? - undefined; + firstString( + psd?.codexAppServerApprovalPolicy, + process.env.OMNIROUTE_CODEX_APPSERVER_APPROVAL + ) ?? undefined; const sandbox = firstString(psd?.codexAppServerSandbox, process.env.OMNIROUTE_CODEX_APPSERVER_SANDBOX) ?? undefined; - return { url, token, cwd, ...(approvalPolicy ? { approvalPolicy } : {}), ...(sandbox ? { sandbox } : {}) }; + return { + url, + token, + cwd, + ...(approvalPolicy ? { approvalPolicy } : {}), + ...(sandbox ? { sandbox } : {}), + }; } /** diff --git a/src/app/api/providers/[id]/test/codexAppServerHealth.ts b/src/app/api/providers/[id]/test/codexAppServerHealth.ts index 8476d9e832..e2a27171d5 100644 --- a/src/app/api/providers/[id]/test/codexAppServerHealth.ts +++ b/src/app/api/providers/[id]/test/codexAppServerHealth.ts @@ -43,7 +43,8 @@ export type CodexAppServerHealth = { export async function testCodexAppServerConnection( connection: any ): Promise { - const psd = (connection?.providerSpecificData as Record | undefined) || undefined; + const psd = + (connection?.providerSpecificData as Record | undefined) || undefined; // Fire the /readyz probe when EITHER (a) the connection opted into the // app-server transport via the per-connection flag (a `codex` provider // connection with codexTransport==="app-server"), OR (b) this is the @@ -56,9 +57,8 @@ export async function testCodexAppServerConnection( // Dynamic import (not a static top-level import) so this executor-config module // stays behind the open-sse boundary the no-restricted-imports lint rule enforces. - const { resolveAppServerConfig } = await import( - "@omniroute/open-sse/executors/codex/appServerConfig.ts" - ); + const { resolveAppServerConfig } = + await import("@omniroute/open-sse/executors/codex/appServerConfig.ts"); const config = resolveAppServerConfig(psd); if (!config) { // Also reached when the credential/URL binding refused (env token + remote @@ -75,7 +75,9 @@ export async function testCodexAppServerConnection( } // ws://host:port → http://host:port/readyz ; wss:// → https://. - const httpBase = config.url.replace(/^ws(s?):\/\//i, (_m, s) => `http${s}://`).replace(/\/+$/, ""); + const httpBase = config.url + .replace(/^ws(s?):\/\//i, (_m, s) => `http${s}://`) + .replace(/\/+$/, ""); const readyzUrl = `${httpBase}/readyz`; const controller = new AbortController(); @@ -109,7 +111,11 @@ export async function testCodexAppServerConnection( import("@omniroute/open-sse/executors/codex/appServerAuthProbe.ts"), import("@omniroute/open-sse/executors/codex.ts"), ]); - authStatus = await probeCodexAppServerAuth(config, getCodexAppServerWebsocketTransport(), 8000); + authStatus = await probeCodexAppServerAuth( + config, + getCodexAppServerWebsocketTransport(), + 8000 + ); } catch (probeErr: any) { // If the auth probe itself fails to load/run, don't fail the whole health // check — the server IS reachable. Treat as unknown-but-reachable (valid). diff --git a/stryker.conf.json b/stryker.conf.json index 321f7f6ec4..9b6381f02f 100644 --- a/stryker.conf.json +++ b/stryker.conf.json @@ -89,7 +89,7 @@ "tests/unit/auth-terminal-status.test.ts", "tests/unit/authz/discovery-routes-local-only.test.ts", "tests/unit/authz/oauth-autoimport-local-only.test.ts", - "tests/unit/quota-exhaustion-cutoff-opencode.test.ts", + "tests/unit/quota-exhaustion-cutoff-opencode.test.ts", "tests/unit/authz/route-guard-local-prefix.test.ts", "tests/unit/authz/route-guard-skills-collect.test.ts", "tests/unit/authz/route-guard-version-get-exemption.test.ts", diff --git a/tests/unit/codex-app-server.test.ts b/tests/unit/codex-app-server.test.ts index 572b0a061c..7d4a176a98 100644 --- a/tests/unit/codex-app-server.test.ts +++ b/tests/unit/codex-app-server.test.ts @@ -98,10 +98,7 @@ function makeExecuteInput(overrides: Partial = {}): ExecuteInput { // ── Gating ────────────────────────────────────────────────────────────────── test("isCodexAppServerRequired: true only when codexTransport==='app-server' + configured", () => { - assert.equal( - isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), - true - ); + assert.equal(isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), true); // wrong transport assert.equal( isCodexAppServerRequired({ @@ -135,10 +132,7 @@ test("isCodexAppServerRequired: false when OMNIROUTE_CODEX_APP_SERVER_ENABLED=fa const prev = process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED; process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED = "false"; try { - assert.equal( - isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), - false - ); + assert.equal(isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), false); } finally { if (prev === undefined) delete process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED; else process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED = prev; @@ -146,7 +140,10 @@ test("isCodexAppServerRequired: false when OMNIROUTE_CODEX_APP_SERVER_ENABLED=fa }); test("resolveAppServerConfig: env fallback + token-file, ws-scheme validation", () => { - assert.equal(resolveAppServerConfig({ codexAppServerUrl: "http://x", codexAppServerToken: "t" }), null); + assert.equal( + resolveAppServerConfig({ codexAppServerUrl: "http://x", codexAppServerToken: "t" }), + null + ); const cfg = resolveAppServerConfig({ ...APP_SERVER_PSD }); assert.deepEqual(cfg, { url: "ws://ts-egress:1456", token: "deadbeef", cwd: "/tmp" }); }); @@ -157,14 +154,8 @@ test("translateNotification: maps deltas, done and error to AdapterEvents", () = const events: AdapterEvent[] = []; const push = (e: AdapterEvent) => events.push(e); - assert.equal( - translateNotification("item/agentMessage/delta", { delta: "Hel" }, push), - false - ); - assert.equal( - translateNotification("item/reasoning/textDelta", { delta: "think" }, push), - false - ); + assert.equal(translateNotification("item/agentMessage/delta", { delta: "Hel" }, push), false); + assert.equal(translateNotification("item/reasoning/textDelta", { delta: "think" }, push), false); // terminal → returns true assert.equal( translateNotification( @@ -186,10 +177,8 @@ test("translateNotification: maps deltas, done and error to AdapterEvents", () = test("translateNotification: error notification maps to error event (terminal)", () => { const events: AdapterEvent[] = []; - const isTerminal = translateNotification( - "error", - { error: { message: "boom" } }, - (e) => events.push(e) + const isTerminal = translateNotification("error", { error: { message: "boom" } }, (e) => + events.push(e) ); assert.equal(isTerminal, true); assert.equal(events[0].type, "error"); @@ -343,7 +332,9 @@ async function runStreamingTurn(): Promise<{ test("CodexAppServerExecutor: streaming turn emits initialize → thread/start → turn/start in order", async () => { const { sent } = await runStreamingTurn(); - const methods = sent.filter((f) => typeof f.method === "string" && f.id != null).map((f) => f.method); + const methods = sent + .filter((f) => typeof f.method === "string" && f.id != null) + .map((f) => f.method); const lifecycle = methods.filter( (m) => m === "initialize" || m === "thread/start" || m === "turn/start" ); @@ -639,7 +630,13 @@ test("CodexAppServerExecutor: async post-turn/start completion does not close th const result = await Promise.race([ executor.execute(makeExecuteInput({ stream: false })), new Promise((_, reject) => - setTimeout(() => reject(new Error("execute() hung: socket closed before async completion (BUG#3 regressed)")), 5000) + setTimeout( + () => + reject( + new Error("execute() hung: socket closed before async completion (BUG#3 regressed)") + ), + 5000 + ) ), ]); const response = "response" in result ? result.response : (result as Response); @@ -648,7 +645,11 @@ test("CodexAppServerExecutor: async post-turn/start completion does not close th status?: string; output?: Array<{ content?: Array<{ text?: string }> }>; }; - assert.equal(body.status, "completed", "the turn completed after the async terminal notification"); + assert.equal( + body.status, + "completed", + "the turn completed after the async terminal notification" + ); const text = body.output?.[0]?.content?.[0]?.text ?? ""; assert.equal(text, "ASYNC-OK", "the model output that arrived AFTER turn/start is present"); }); @@ -693,7 +694,10 @@ const AUTH_CONFIG = { url: "ws://ts-egress:1456", token: "deadbeef", cwd: "/tmp" test("probeCodexAppServerAuth: account with email → authenticated", async () => { const fn = fakeAuthTransport({ - result: { account: { type: "chatgpt", email: "user@example.com", planType: "pro" }, requiresOpenaiAuth: true }, + result: { + account: { type: "chatgpt", email: "user@example.com", planType: "pro" }, + requiresOpenaiAuth: true, + }, }); const status = await probeCodexAppServerAuth(AUTH_CONFIG, fn, 3000); assert.equal(status.state, "authenticated"); @@ -710,7 +714,9 @@ test("probeCodexAppServerAuth: no account → logged_out", async () => { }); test("probeCodexAppServerAuth: auth-error on account/read → logged_out", async () => { - const fn = fakeAuthTransport({ error: { code: -32000, message: "AuthRequiredError: please login" } }); + const fn = fakeAuthTransport({ + error: { code: -32000, message: "AuthRequiredError: please login" }, + }); const status = await probeCodexAppServerAuth(AUTH_CONFIG, fn, 3000); assert.equal(status.state, "logged_out"); }); @@ -836,9 +842,8 @@ test("resolveAppServerConfig: env URL + env token pairs regardless of host", () // ── Health probe: redirect pinning + binding inheritance ──────────────────── test("testCodexAppServerConnection: readyz probe pins redirects (no token leak via 30x)", async () => { - const { testCodexAppServerConnection } = await import( - "../../src/app/api/providers/[id]/test/codexAppServerHealth.ts" - ); + const { testCodexAppServerConnection } = + await import("../../src/app/api/providers/[id]/test/codexAppServerHealth.ts"); const originalFetch = globalThis.fetch; const seen: Array<{ url: string; init?: RequestInit }> = []; globalThis.fetch = (async (url: unknown, init?: RequestInit) => { @@ -864,9 +869,8 @@ test("testCodexAppServerConnection: readyz probe pins redirects (no token leak v }); test("testCodexAppServerConnection: env token + remote psd URL reports unconfigured, no network", async () => { - const { testCodexAppServerConnection } = await import( - "../../src/app/api/providers/[id]/test/codexAppServerHealth.ts" - ); + const { testCodexAppServerConnection } = + await import("../../src/app/api/providers/[id]/test/codexAppServerHealth.ts"); const originalFetch = globalThis.fetch; let fetched = false; globalThis.fetch = (async () => { @@ -881,7 +885,10 @@ test("testCodexAppServerConnection: env token + remote psd URL reports unconfigu }); assert.ok(result); assert.equal(result!.valid, false); - assert.match(String((result!.diagnosis as { code?: string })?.code), /app_server_unconfigured/); + assert.match( + String((result!.diagnosis as { code?: string })?.code), + /app_server_unconfigured/ + ); }); assert.equal(fetched, false, "binding refusal must happen before any network call"); } finally {