Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/opencode/src/plugin/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ export const OAUTH_ALLOWED_MODELS = new Set([
"gpt-5.6-luna",
"gpt-5.6-sol",
"gpt-5.6-terra",
// altimate_change start — allowlisted on catalog evidence and NOT
// backend-probed: the exception to "every entry was verified" above.
// openai/codex's shipped codex-rs/models-manager/models.json lists it with
// visibility "list", upgrade null, and plus/pro in available_in_plans
// (added in openai/codex@126a0ee92e, 2026-10-26); models.dev carries it under
// openai. Probe it against the endpoint above and move it into
// VERIFIED_ACCEPTED (or out of this set) in the test file.
"gpt-6.1-terra",
// altimate_change end
])

/** OAuth (ChatGPT-subscription) model-filter policy for the ACTIVE plugin
Expand Down
34 changes: 31 additions & 3 deletions packages/opencode/test/plugin/codex-allowlist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ const VERIFIED_ACCEPTED = ["gpt-5.3-codex-spark", "gpt-5.5", "gpt-5.6-luna", "gp
* will not drop them for us — the allowlist is what has to. */
const RETIRED_FROM_SUBSCRIPTION = ["gpt-5.4", "gpt-5.4-mini"]

/** Catalog-verified, NOT backend-probed.
*
* `openai/codex`'s shipped codex-rs/models-manager/models.json lists each with
* `visibility: "list"` and `plus`/`pro` in `available_in_plans`, and models.dev
* carries each under `openai`. Nobody has sent these to the live endpoint yet,
* so they are kept apart from VERIFIED_ACCEPTED. Once probed, move each into
* VERIFIED_ACCEPTED (HTTP 200) or VERIFIED_REJECTED (HTTP 400, and drop it from
* OAUTH_ALLOWED_MODELS). */
const CATALOG_VERIFIED_UNPROBED = ["gpt-6.1-terra"]

/** Verified HTTP 400 "not supported when using Codex with a ChatGPT account". */
const VERIFIED_REJECTED = [
"gpt-5",
Expand Down Expand Up @@ -94,10 +104,28 @@ describe("OAUTH_ALLOWED_MODELS — verified subscription truth table", () => {
}
})

test("the allowlist contains nothing beyond the verified-accepted set", () => {
test("every catalog-verified id is allowlisted", () => {
// The Codex catalog lists these for Plus/Pro; hiding them is a false
// negative on models the official client offers subscribers.
for (const id of CATALOG_VERIFIED_UNPROBED) {
expect(OAUTH_ALLOWED_MODELS.has(id)).toBe(true)
expect(shouldAllowOAuthModel(id)).toBe(true)
}
})

test("catalog-verified ids are kept apart from the probed lists", () => {
// An id belongs in exactly one bucket. Probing one moves it out of here.
for (const id of CATALOG_VERIFIED_UNPROBED) {
expect(VERIFIED_ACCEPTED).not.toContain(id)
expect(VERIFIED_REJECTED).not.toContain(id)
}
})

test("the allowlist contains nothing beyond the verified-accepted and catalog-verified sets", () => {
// Trip-wire against speculative additions. To add an id here, probe it
// against the live endpoint first and land it in VERIFIED_ACCEPTED too.
expect([...OAUTH_ALLOWED_MODELS].sort()).toEqual([...VERIFIED_ACCEPTED].sort())
// against the live endpoint and land it in VERIFIED_ACCEPTED, or cite the
// Codex catalog and land it in CATALOG_VERIFIED_UNPROBED.
expect([...OAUTH_ALLOWED_MODELS].sort()).toEqual([...VERIFIED_ACCEPTED, ...CATALOG_VERIFIED_UNPROBED].sort())
})

test("ids retired from the subscription picker are not offered", () => {
Expand Down
Loading