chore: update Codex channel - #5461
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
WalkthroughThis PR removes the Codex OAuth two-step authorization flow and replaces it with a credential refresh mechanism. Backend OAuth exchange and PKCE/state logic are removed; new admin endpoints for credential refresh and usage were added. Frontends remove OAuth UI/components, add direct refresh actions, and update channel branding and i18n to "ChatGPT Subscription (Codex)". ChangesCodex OAuth Removal & Credential Refresh Migration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx (1)
725-742:⚠️ Potential issue | 🟠 Major | ⚡ Quick winClear the revealed key after a successful Codex refresh.
On success you invalidate the detail query, but
channelKeyis left untouched. If the user had already revealed the current key, the drawer keeps showing and copying the pre-refresh credential from lines 1947-2000 even though/codex/refreshhas rotated it. That makes the new refresh action immediately serve stale data.💡 Suggested fix
const handleRefreshCodexCredential = useCallback(async () => { if (!channelId) return setIsCodexCredentialRefreshing(true) try { const res = await refreshCodexCredential(channelId) if (!res.success) { throw new Error(res.message || t('Failed to refresh credential')) } + setChannelKey(null) toast.success(t('Credential refreshed')) queryClient.invalidateQueries({ queryKey: channelsQueryKeys.detail(channelId), })If you want to keep the field populated, re-fetch it behind the existing secure-verification flow instead of reusing the old revealed value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx` around lines 725 - 742, handleRefreshCodexCredential currently refreshes the Codex credential but leaves the revealed channelKey state intact, causing the UI to continue showing/copying the old credential; update the handler to clear any revealed key state after a successful refresh by resetting the channelKey (or the state variable that holds the revealed credential) and any related "revealed" boolean flag so the UI requires re-reveal or refetch, and ensure this uses the same secure-verification flow that normally populates the key (referencing handleRefreshCodexCredential, channelKey and the reveal/copy handlers) and still invalidates the detail query via queryClient.invalidateQueries.service/codex_oauth.go (1)
77-81:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve upstream error details on refresh failures.
This decodes the success payload before checking
resp.StatusCode, so a non-2xx response can collapse into a genericstatus=<code>error or a JSON decode error. With the authorization-code flow removed, this refresh path is now the only way to recover Codex credentials, so losing the upstream error body will make invalid/expired refresh tokens much harder to diagnose.💡 Suggested fix
+import "io" + - if err := common.DecodeJson(resp.Body, &payload); err != nil { - return nil, err - } - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return nil, fmt.Errorf("codex oauth refresh failed: status=%d", resp.StatusCode) - } + body, err := io.ReadAll(io.LimitReader(resp.Body, 4096)) + if err != nil { + return nil, err + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf( + "codex oauth refresh failed: status=%d body=%s", + resp.StatusCode, + strings.TrimSpace(string(body)), + ) + } + if err := common.Unmarshal(body, &payload); err != nil { + return nil, err + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@service/codex_oauth.go` around lines 77 - 81, The code decodes the response body into payload before checking resp.StatusCode, which can lose upstream error details; change the flow in the Codex refresh path so you first read the full resp.Body into bytes (e.g., ioutil.ReadAll or io.ReadAll), then if resp.StatusCode is not 2xx return an error that includes both the status code and the response body bytes for debugging, and only on a 2xx status decode those bytes into payload using common.DecodeJson (or decode from the already-read bytes). Update the logic around resp, payload, and common.DecodeJson accordingly so non-2xx bodies are preserved in the returned error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/i18n/locales/fr.json`:
- Line 1211: The French translation value for the long disclaimer JSON key is
missing several diacritics; update the value string for the key "Disclaimer:
Personal use only. Do not distribute or share any credentials. This channel has
prerequisites and requires prior setup; use it only if you understand the flow
and risks, and comply with OpenAI's terms and policies. Credentials and
configuration are for Codex CLI integration only, and are not intended for any
other client, platform, or channel." to correct accents (e.g., change
"prerequis" → "prérequis", "necessite" → "nécessite", "prealable" → "préalable",
"procedure" → "procédure", "reserves" → "réservés", "destines" → "destinés") so
the user-facing French string uses proper diacritics throughout.
---
Outside diff comments:
In `@service/codex_oauth.go`:
- Around line 77-81: The code decodes the response body into payload before
checking resp.StatusCode, which can lose upstream error details; change the flow
in the Codex refresh path so you first read the full resp.Body into bytes (e.g.,
ioutil.ReadAll or io.ReadAll), then if resp.StatusCode is not 2xx return an
error that includes both the status code and the response body bytes for
debugging, and only on a 2xx status decode those bytes into payload using
common.DecodeJson (or decode from the already-read bytes). Update the logic
around resp, payload, and common.DecodeJson accordingly so non-2xx bodies are
preserved in the returned error.
In
`@web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx`:
- Around line 725-742: handleRefreshCodexCredential currently refreshes the
Codex credential but leaves the revealed channelKey state intact, causing the UI
to continue showing/copying the old credential; update the handler to clear any
revealed key state after a successful refresh by resetting the channelKey (or
the state variable that holds the revealed credential) and any related
"revealed" boolean flag so the UI requires re-reveal or refetch, and ensure this
uses the same secure-verification flow that normally populates the key
(referencing handleRefreshCodexCredential, channelKey and the reveal/copy
handlers) and still invalidates the detail query via
queryClient.invalidateQueries.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e48fca13-8189-4788-937f-544825c888b0
📒 Files selected for processing (25)
constant/channel.gocontroller/codex_oauth.gorouter/api-router.goservice/codex_oauth.goweb/classic/src/components/table/channels/modals/CodexOAuthModal.jsxweb/classic/src/components/table/channels/modals/EditChannelModal.jsxweb/classic/src/constants/channel.constants.jsweb/classic/src/i18n/locales/en.jsonweb/classic/src/i18n/locales/fr.jsonweb/classic/src/i18n/locales/ja.jsonweb/classic/src/i18n/locales/ru.jsonweb/classic/src/i18n/locales/vi.jsonweb/classic/src/i18n/locales/zh-CN.jsonweb/classic/src/i18n/locales/zh-TW.jsonweb/default/scripts/sync-i18n.mjsweb/default/src/features/channels/api.tsweb/default/src/features/channels/components/dialogs/codex-oauth-dialog.tsxweb/default/src/features/channels/components/drawers/channel-mutate-drawer.tsxweb/default/src/features/channels/constants.tsweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
💤 Files with no reviewable changes (13)
- web/classic/src/components/table/channels/modals/CodexOAuthModal.jsx
- web/default/src/features/channels/components/dialogs/codex-oauth-dialog.tsx
- controller/codex_oauth.go
- router/api-router.go
- web/classic/src/i18n/locales/zh-TW.json
- web/default/src/features/channels/api.ts
- web/classic/src/components/table/channels/modals/EditChannelModal.jsx
- web/classic/src/i18n/locales/vi.json
- web/classic/src/i18n/locales/ru.json
- web/classic/src/i18n/locales/en.json
- web/classic/src/i18n/locales/fr.json
- web/classic/src/i18n/locales/zh-CN.json
- web/classic/src/i18n/locales/ja.json
| "Discount rate must be greater than 0": "Le taux de remise doit être supérieur à 0", | ||
| "Discount Rate:": "Taux de réduction :", | ||
| "Discount ratio for cache hits.": "Ratio de réduction pour les accès au cache.", | ||
| "Disclaimer: Personal use only. Do not distribute or share any credentials. This channel has prerequisites and requires prior setup; use it only if you understand the flow and risks, and comply with OpenAI's terms and policies. Credentials and configuration are for Codex CLI integration only, and are not intended for any other client, platform, or channel.": "Avertissement : usage personnel uniquement. Ne distribuez ni ne partagez aucun identifiant. Ce canal a des prerequis et necessite une configuration prealable ; utilisez-le uniquement si vous comprenez la procedure et les risques, et respectez les conditions et politiques d'OpenAI. Les identifiants et la configuration sont reserves a l'integration Codex CLI et ne sont pas destines a d'autres clients, plateformes ou canaux.", |
There was a problem hiding this comment.
Fix French diacritics in the disclaimer copy.
The new translation has several missing accents in user-facing legal text, which degrades localization quality (e.g., prérequis, nécessite, préalable, procédure, réservés, destinés).
Suggested text update
- "Disclaimer: Personal use only. Do not distribute or share any credentials. This channel has prerequisites and requires prior setup; use it only if you understand the flow and risks, and comply with OpenAI's terms and policies. Credentials and configuration are for Codex CLI integration only, and are not intended for any other client, platform, or channel.": "Avertissement : usage personnel uniquement. Ne distribuez ni ne partagez aucun identifiant. Ce canal a des prerequis et necessite une configuration prealable ; utilisez-le uniquement si vous comprenez la procedure et les risques, et respectez les conditions et politiques d'OpenAI. Les identifiants et la configuration sont reserves a l'integration Codex CLI et ne sont pas destines a d'autres clients, plateformes ou canaux.",
+ "Disclaimer: Personal use only. Do not distribute or share any credentials. This channel has prerequisites and requires prior setup; use it only if you understand the flow and risks, and comply with OpenAI's terms and policies. Credentials and configuration are for Codex CLI integration only, and are not intended for any other client, platform, or channel.": "Avertissement : usage personnel uniquement. Ne distribuez ni ne partagez aucun identifiant. Ce canal a des prérequis et nécessite une configuration préalable ; utilisez-le uniquement si vous comprenez la procédure et les risques, et respectez les conditions et politiques d'OpenAI. Les identifiants et la configuration sont réservés à l'intégration Codex CLI et ne sont pas destinés à d'autres clients, plateformes ou canaux.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "Disclaimer: Personal use only. Do not distribute or share any credentials. This channel has prerequisites and requires prior setup; use it only if you understand the flow and risks, and comply with OpenAI's terms and policies. Credentials and configuration are for Codex CLI integration only, and are not intended for any other client, platform, or channel.": "Avertissement : usage personnel uniquement. Ne distribuez ni ne partagez aucun identifiant. Ce canal a des prerequis et necessite une configuration prealable ; utilisez-le uniquement si vous comprenez la procedure et les risques, et respectez les conditions et politiques d'OpenAI. Les identifiants et la configuration sont reserves a l'integration Codex CLI et ne sont pas destines a d'autres clients, plateformes ou canaux.", | |
| "Disclaimer: Personal use only. Do not distribute or share any credentials. This channel has prerequisites and requires prior setup; use it only if you understand the flow and risks, and comply with OpenAI's terms and policies. Credentials and configuration are for Codex CLI integration only, and are not intended for any other client, platform, or channel.": "Avertissement : usage personnel uniquement. Ne distribuez ni ne partagez aucun identifiant. Ce canal a des prérequis et nécessite une configuration préalable ; utilisez-le uniquement si vous comprenez la procédure et les risques, et respectez les conditions et politiques d'OpenAI. Les identifiants et la configuration sont réservés à l'intégration Codex CLI et ne sont pas destinés à d'autres clients, plateformes ou canaux.", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/src/i18n/locales/fr.json` at line 1211, The French translation
value for the long disclaimer JSON key is missing several diacritics; update the
value string for the key "Disclaimer: Personal use only. Do not distribute or
share any credentials. This channel has prerequisites and requires prior setup;
use it only if you understand the flow and risks, and comply with OpenAI's terms
and policies. Credentials and configuration are for Codex CLI integration only,
and are not intended for any other client, platform, or channel." to correct
accents (e.g., change "prerequis" → "prérequis", "necessite" → "nécessite",
"prealable" → "préalable", "procedure" → "procédure", "reserves" → "réservés",
"destines" → "destinés") so the user-facing French string uses proper diacritics
throughout.
# Conflicts: # web/default/src/components/provider-badge.tsx
合并上游 QuantumNous/new-api v1.0.0-rc.11,主要新增 Claude Opus 4.8、 OpenAI 图片流式中继、渠道粘性清空选项、安全审计日志、模型定价双栏重构、 Dialog prop-based API 重构。 冲突解决(20 文件): - 13 个 dialog 采用上游新结构,保留 dev sm: 响应式前缀与 ESLint 注释 - common-logs-columns / details-dialog 的 multikey 徽章功能完整保留 - channels-table 采用上游 useDebouncedColumnFilter - model-pricing-sheet / model-ratio-visual-editor 采用 upstream 版本 - codex-oauth-dialog 删除(跟随上游 QuantumNous#5461) 撞车修复核对通过:视频任务 GET 验证(QuantumNous#4834/QuantumNous#5133)、匿名请求体限制(QuantumNous#5244) 逻辑均正确保留,无重复。 验证:前端 typecheck + 生产 build 通过,后端 go build 通过,i18n 全语言对齐。
## 背景 newpay 分支 /channels 编辑抽屉里 Codex 渠道类型(type=57)已经显示 "Authorize" 按钮和 CodexOAuthDialog,前端会 POST 到: - /api/channel/codex/oauth/start - /api/channel/codex/oauth/complete 但从 git 历史查证,主分支 commit 1292b8b "chore: update Codex channel (QuantumNous#5461)"(Jun 12 2026)**删除了**这两条路由以及对应 handler `controller/codex_oauth.go`(247 LOC)与 `service/codex_oauth.go` 中 的 OAuth 授权流程函数。newpay 通过 4df4a8c 主动恢复了前端的 codex-oauth-dialog.tsx 与 api.ts 里的 startCodexOAuth / completeCodexOAuth 导出,但**后端 handler 一直没有回来**,导致点击 Authorize 按钮时收到 404,Codex OAuth 授权在 newpay 上无法真正跑通。 ## 修复 从 1292b8b^ 的历史快照恢复: 1. **controller/codex_oauth.go**(新增 247 LOC):包含 - StartCodexOAuth / CompleteCodexOAuth(无渠道 ID,创建新渠道时使用) - StartCodexOAuthForChannel / CompleteCodexOAuthForChannel(已有渠道刷新使用) - codexOAuthSessionKey / parseCodexAuthorizationInput 工具函数 2. **service/codex_oauth.go**(170 → 317 LOC)恢复被 1292b8b 清理掉的: - CodexOAuthAuthorizationFlow 类型 - CreateCodexOAuthAuthorizationFlow(发起 PKCE 流程) - ExchangeCodexAuthorizationCode / WithProxy(用 code+verifier 换 token) - buildCodexAuthorizeURL / createStateHex / generatePKCEPair 支持函数 - 常量:codexOAuthAuthorizeURL、codexOAuthRedirectURI、codexOAuthScope 3. **router/channel-router.go** 注册 4 条路由,权限 = ChannelSensitiveWrite (AdminAuth 已在 registerChannelRoutes 中间件层强制): - POST /api/channel/codex/oauth/start - POST /api/channel/codex/oauth/complete - POST /api/channel/:id/codex/oauth/start - POST /api/channel/:id/codex/oauth/complete ## 依赖 复用现有: - github.com/gin-contrib/sessions(main.go:197 已在全局注册 session 中间件) - relay/channel/codex.OAuthKey(未被 1292b8b 删除,仍在库中) - 会话存储、AdminAuth 中间件、authz.ChannelSensitiveWrite 权限 ## 验证 - go build ./... 通过 - go test ./... 全部通过(controller/service/router 无回归) - 前端 /api/channel/codex/oauth/start 现在会命中路由(原来 404), 实际授权走 OpenAI 官方 https://auth.openai.com/oauth/authorize + PKCE 流程 ## AI 辅助生成说明 本提交由 AI 辅助生成(Claude Code)从历史 commit 回捡代码后合并。 Co-Authored-By: Claude <noreply@anthropic.com>
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)
Summary by CodeRabbit
New Features
Changes