diff --git a/changelog.d/fixes/7521-codex-test-probe-model.md b/changelog.d/fixes/7521-codex-test-probe-model.md new file mode 100644 index 0000000000..8af6bbf9b6 --- /dev/null +++ b/changelog.d/fixes/7521-codex-test-probe-model.md @@ -0,0 +1 @@ +- Fixed the Codex connection **Test** button always reporting success for ChatGPT-account tokens: the probe used `gpt-5.3-codex`, a codex-only model ChatGPT accounts reject with a 400 — the same status the probe treats as "auth OK", so a bad token was indistinguishable from a good one. It now probes with `gpt-5.5`, a model ChatGPT-account sessions actually support (#7521). diff --git a/src/app/api/providers/[id]/test/route.ts b/src/app/api/providers/[id]/test/route.ts index 0424645209..65e570a10c 100644 --- a/src/app/api/providers/[id]/test/route.ts +++ b/src/app/api/providers/[id]/test/route.ts @@ -54,7 +54,12 @@ const OAUTH_TEST_CONFIG = { "User-Agent": "codex-cli/1.0.18 (macOS; arm64)", }, // Minimal invalid body — triggers a fast 400 without consuming quota. - body: JSON.stringify({ model: "gpt-5.3-codex", input: [], stream: false, store: false }), + // #7521: probe with a ChatGPT-account-supported model. "gpt-5.3-codex" is a + // codex-only id that ChatGPT accounts reject with a 400 for the WRONG reason + // (unsupported model, not "auth ok, body invalid") — collapsing the auth signal + // so a bad token looks the same as a good one. "gpt-5.5" is served for + // ChatGPT sessions; `input: []` still yields the intended 400. + body: JSON.stringify({ model: "gpt-5.5", input: [], stream: false, store: false }), // 400 = bad request, but auth was accepted; only 401/403 means the token is bad. acceptStatuses: [400], refreshable: true, diff --git a/tests/unit/oauth-connection-test-codex-endpoint.test.ts b/tests/unit/oauth-connection-test-codex-endpoint.test.ts index e3d955d30a..e7900af836 100644 --- a/tests/unit/oauth-connection-test-codex-endpoint.test.ts +++ b/tests/unit/oauth-connection-test-codex-endpoint.test.ts @@ -67,6 +67,20 @@ test("codex test probes the real /responses endpoint and treats 400 as 'auth ok' const headers = (calls[0].init?.headers ?? {}) as Record; assert.equal(headers.Authorization, "Bearer fake-codex-token"); assert.ok(calls[0].init?.body, "must send a minimal body so the endpoint returns 400 (not 405)"); + + // #7521: the probe model must be one ChatGPT-account sessions actually support. + // "gpt-5.3-codex" is rejected outright for ChatGPT accounts ("The 'gpt-5.3-codex' + // model is not supported when using Codex with a ChatGPT account."), which also + // returns 400 — masking a bad token behind the same status code as a good one and + // making the Test button always report success. Assert the probe body carries a + // supported model instead. + const parsedBody = JSON.parse(String(calls[0].init?.body)); + assert.equal(parsedBody.model, "gpt-5.5", "probe must use a ChatGPT-account-supported model"); + assert.notEqual( + parsedBody.model, + "gpt-5.3-codex", + "probe must not use the codex-only model ChatGPT accounts reject (#7521)" + ); }); test("codex test reports invalid when the endpoint returns 401 (port PR#347)", async (t) => {