Skip to content

Add first-class Codex provider#12

Open
Logo-web wants to merge 2 commits intoamruth-sn:mainfrom
Logo-web:codex/add-codex-provider
Open

Add first-class Codex provider#12
Logo-web wants to merge 2 commits intoamruth-sn:mainfrom
Logo-web:codex/add-codex-provider

Conversation

@Logo-web
Copy link

@Logo-web Logo-web commented Mar 25, 2026

Summary

This adds a first-class codex provider to Kong, backed by the ChatGPT Codex OAuth flow instead of the standard OpenAI API.

What changed

  • added LLMProvider.CODEX
  • added CodexClient for ChatGPT Codex backend requests
  • added codex_auth helpers for loading and refreshing local Codex OAuth credentials
  • wired Codex into kong setup, provider resolution, endpoint probing, and CLI messaging
  • kept existing openai and custom provider behavior intact
  • added tests for Codex auth, Codex client flow, setup, probe, and provider routing
  • updated README usage docs

Why

Kong previously could reuse a local Codex login only as a credential source for the normal OpenAI API path. That still fails for accounts without OpenAI API billing.

This change adds a real Codex-backed path so users can run Kong through their local ChatGPT/Codex login directly.

Verification

  • uv run pytest -q
  • full suite passing: 448 passed
  • local Codex probe verified successfully

Summary by cubic

Adds a first-class codex provider that talks to the ChatGPT Codex backend via OAuth, independent of the OpenAI API. Users can run Kong with a local ChatGPT login; setup, probing, routing, and usage reporting were updated (tokens only, no cost).

  • New Features

    • Added LLMProvider.CODEX and a Codex client with SSE streaming, tool-calling, token usage, and OAuth auto-refresh on 401s.
    • Auth: codex_auth loads/refreshes from ~/.codex/auth.json (override with CODEX_HOME); openai_auth now auto-resolves OPENAI_API_KEY, Codex API key, or Codex OAuth; the OpenAI client re-resolves credentials dynamically.
    • Setup/UX: wizard adds codex and Anthropic + Codex, shows credential source labels, and guides to run codex; provider labels/help updated; default Codex model is gpt-5-codex; clearer errors when Codex login is missing or when OpenAI uses Codex OAuth without API billing.
    • Probing: Codex probe added; OpenAI probe falls back to an inference check if model-list scope is missing.
    • Usage/Export/Docs: treat codex as non-billable (token counts only; exports mark cost tracking off); README adds Codex sign-in (codex), CODEX_HOME, separate billing notes, and --provider codex examples.
  • Migration

    • No breaking changes; openai and custom behavior unchanged.
    • To use Codex: run codex to sign in, then kong setup and choose codex (or Anthropic + Codex).
    • If openai runs via Codex OAuth and requests fail, enable OpenAI API billing or set OPENAI_API_KEY.

Written for commit 300ad95. Summary will update on new commits.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 18 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/test_codex_auth.py">

<violation number="1" location="tests/test_codex_auth.py:53">
P2: Missing assertion on `credential.refresh_token` (and `credential.account_id`) for the returned object. The test verifies these fields in the saved file but not on the credential returned to the caller, so a bug where the returned object carries stale values would go undetected.</violation>
</file>

<file name="kong/llm/codex_auth.py">

<violation number="1" location="kong/llm/codex_auth.py:97">
P1: Credentials file is written with default permissions (world-readable). The refresh token and access token are sensitive — restrict the file to owner-only (`0o600`) to prevent other users on the system from reading them.</violation>
</file>

<file name="tests/test_cli.py">

<violation number="1" location="tests/test_cli.py:181">
P2: Missing return-value assertion. Every other test in `TestCreateLLMClient` captures the result and checks `isinstance(client, ...)`, but this test discards the return value. Add the assertion to verify `create_llm_client` actually returns the `CodexClient` instance.</violation>
</file>

<file name="kong/llm/codex_client.py">

<violation number="1" location="kong/llm/codex_client.py:297">
P1: SSE parser silently drops the last event if the stream doesn't end with a trailing blank line. After the `while True` loop exits (on EOF), any remaining `data_lines` are never flushed. If `response.completed` is the final event and it lacks a trailing blank line, `completed_response` will be `None` and the request will fail.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="kong/llm/codex_auth.py">

<violation number="1" location="kong/llm/codex_auth.py:98">
P2: TOCTOU race: credentials are briefly world-readable between `write_text` and `chmod`. The file is created with the default umask (often `0o644`) before permissions are tightened. Use `os.open` with explicit mode to avoid the window.

For example, write via a file descriptor opened with `0o600` so the file never has open permissions.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

auth_path = current.auth_path or codex_auth_path()
auth_path.parent.mkdir(parents=True, exist_ok=True)
auth_path.write_text(json.dumps(updated, indent=2), encoding="utf-8")
_restrict_auth_file_permissions(auth_path)
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: TOCTOU race: credentials are briefly world-readable between write_text and chmod. The file is created with the default umask (often 0o644) before permissions are tightened. Use os.open with explicit mode to avoid the window.

For example, write via a file descriptor opened with 0o600 so the file never has open permissions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At kong/llm/codex_auth.py, line 98:

<comment>TOCTOU race: credentials are briefly world-readable between `write_text` and `chmod`. The file is created with the default umask (often `0o644`) before permissions are tightened. Use `os.open` with explicit mode to avoid the window.

For example, write via a file descriptor opened with `0o600` so the file never has open permissions.</comment>

<file context>
@@ -95,6 +95,7 @@ def refresh_codex_credential(credential: CodexCredential | None = None) -> Codex
     auth_path = current.auth_path or codex_auth_path()
     auth_path.parent.mkdir(parents=True, exist_ok=True)
     auth_path.write_text(json.dumps(updated, indent=2), encoding="utf-8")
+    _restrict_auth_file_permissions(auth_path)
 
     return CodexCredential(
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant