Skip to content
Merged
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: 5 additions & 4 deletions docs-site/src/content/docs/fr/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,13 @@ Ajoutez un nom d'affichage depuis la CLI ; si le proxy est actif, il synchronise
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

Les clients Codex distants peuvent récupérer le même catalogue généré par l'API de gestion, avec le même jeton
d'admission que pour les autres routes `/api/*` :
Les clients Codex distants peuvent récupérer le même catalogue généré avec une clé ordinaire du plan de données — le même identifiant que celui utilisé pour `/v1/responses`, et non un jeton de gestion ou d'administration :

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
Comment thread
coderabbitai[bot] marked this conversation as resolved.
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -274,6 +273,8 @@ Vous pouvez également définir ou modifier ce nom dans l'API de gestion — `PO
`PUT /api/custom-models/<id>` avec une chaîne `displayName` — et dans le tableau de bord web. Le caractère `/`
est refusé, car il entrerait en collision avec le séparateur des identifiants de routage.

`GET /v1/catalog` existe pour que la lecture d'une liste de modèles ne coûte pas un jeton d'administration. La route est en lecture seule (`GET` et `HEAD`), accepte `x-opencodex-api-key`, un jeton bearer ou `x-api-key`, et renvoie exactement les mêmes octets que la route de gestion. Les réponses portent un `ETag` fort — renvoyez-le dans `If-None-Match` pour revalider et obtenir un `304` — et `Cache-Control: private, no-cache`. Une clé du plan de données admise ici n'obtient **rien** sur le plan de gestion : `/api/catalog` et toutes les routes `/api/*` exigent toujours le jeton d'administration ou une session du tableau de bord.

Le nom d'affichage sert **uniquement à l'affichage et reste stable entre les régénérations**. À chaque `ocx sync`
et à chaque actualisation du catalogue, opencodex reconstruit les entrées routées depuis `config.json`, y compris
`customModels` ; le nom configuré est donc réappliqué au lieu de revenir à l'identifiant de routage. Un service
Expand Down
20 changes: 16 additions & 4 deletions docs-site/src/content/docs/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,14 @@ Add a display name from the CLI (the proxy syncs the catalog right away when liv
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

Remote Codex clients can fetch the same generated catalog over the management API (same
admission token as other `/api/*` routes):
Remote Codex clients can fetch the same generated catalog with an ordinary **data-plane** key
— the same credential they already use for `/v1/responses`, not an admin token:

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -281,6 +281,18 @@ The response is the raw `opencodex-catalog.json` document (no provider credentia
available, the `x-opencodex-codex-version` header reports the Codex runtime version on the
server so clients can spot version skew.

`GET /v1/catalog` exists so that reading a list of models does not cost an admin token. It is
read-only (`GET` and `HEAD`), accepts `x-opencodex-api-key`, a bearer token, or
`x-api-key`, and serves exactly the same bytes as the management route. Responses carry a
strong `ETag` — pass it back as `If-None-Match` to re-validate and get a `304` instead of the
full document — and `Cache-Control: private, no-cache`, since the body sits behind a
credential.

A data-plane key admitted here gains **nothing** on the management plane: `/api/catalog` and
every other `/api/*` route still require the admin token or a dashboard session. The older
`/api/catalog` route keeps working unchanged for the dashboard and for scripts that already
hold an admin token.

You can also set or edit it through the management API (`POST /api/custom-models`,
`PUT /api/custom-models/<id>` with a `displayName` string) and the web dashboard. A `/` is rejected
because it would collide with the routed-slug separator.
Expand Down
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/ja/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@ CLI から表示名を追加します (プロキシは、ライブ時にカタ
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

リモート Codex クライアントは、管理 API 経由で同じ生成されたカタログをフェッチできます (他の `/api/*` ルートと同じアドミッション トークン)
リモート Codex クライアントは、通常のデータプレーン キー(管理者トークンではなく、`/v1/responses` で既に使用しているものと同じ資格情報)で同じ生成済みカタログを取得できます

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -178,6 +178,8 @@ ocx sync-cache

管理 API (`POST /api/custom-models`、`PUT /api/custom-models/<id>` と `displayName` 文字列) および Web ダッシュボードを通じて設定または編集することもできます。 `/` は、配線済みスラグ セパレータと衝突する可能性があるため拒否されます。

`GET /v1/catalog` は、モデル一覧の読み取りに管理トークンを必要としないために存在します。読み取り専用(`GET` と `HEAD`)で、`x-opencodex-api-key`、bearer トークン、`x-api-key` を受け付け、管理ルートとまったく同じバイト列を返します。レスポンスには強い `ETag` が付き、`If-None-Match` で送り返すと全文ではなく `304` が返ります。また `Cache-Control: private, no-cache` が設定されます。ここで許可されたデータプレーンキーは、管理プレーンでは**何も**得られません。`/api/catalog` を含むすべての `/api/*` ルートは、引き続き管理トークンまたはダッシュボードセッションを要求します。

表示名は **表示専用であり、再生成しても安定しています**。 `ocx sync` およびカタログが更新されるたびに、`config.json` (`customModels` を含む) からルーティングされたエントリが再取得されるため、設定された名前はルーティングされたスラッグに戻るのではなく、再適用されます。管理対象サービスの再起動でも、プロキシのバインド直後にこの同期が試行されます。オフライン ログイン中など、ベストエフォート型ブート同期が失敗した場合、以前に永続化されたカタログが保持され、次に成功した `ocx sync` が構成された名前を再適用します。本物のアップストリーム ネイティブ名 (例: `gpt-5.6-sol` → "GPT-5.6-Sol") は、固定されたアップストリーム スナップショットから取得され、カスタム表示名によって上書きされることはありません。

### 外部プロバイダーマネージャー
Expand Down
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/ko/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,13 @@ CLI에서 표시 이름을 추가할 수 있습니다(proxy가 live 상태면 ca
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

원격 Codex client는 management API로 같은 생성된 catalog를 가져올 수 있습니다(다른 `/api/*` 경로와 같은 admission token을 사용합니다):
원격 Codex client는 관리자 토큰이 아니라 일반 데이터 플레인 키(`/v1/responses`에 이미 사용하는 것과 같은 자격 증명)로 같은 생성된 catalog를 가져올 수 있습니다:

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -168,6 +168,8 @@ ocx sync-cache

또한 management API(`POST /api/custom-models`, `PUT /api/custom-models/<id>`의 `displayName` string)와 웹 대시보드에서도 설정하거나 수정할 수 있습니다. `/`는 routed-slug separator와 충돌하므로 거부됩니다.

`GET /v1/catalog`은 모델 목록을 읽는 데 관리자 토큰이 필요하지 않도록 존재합니다. 읽기 전용(`GET`, `HEAD`)이며 `x-opencodex-api-key`, bearer 토큰, `x-api-key`를 허용하고 관리 라우트와 완전히 동일한 바이트를 제공합니다. 응답에는 강한 `ETag`가 포함되므로 `If-None-Match`로 다시 보내면 전체 문서 대신 `304`를 받고, `Cache-Control: private, no-cache`가 함께 설정됩니다. 여기서 허용된 데이터 플레인 키는 관리 플레인에서 **아무 권한도** 얻지 못합니다. `/api/catalog`을 비롯한 모든 `/api/*` 라우트는 여전히 관리자 토큰이나 대시보드 세션을 요구합니다.

표시 이름은 **표시 전용이며 재생성 사이에서도 안정적**입니다. 모든 `ocx sync`와 catalog refresh는 `config.json`(`customModels` 포함)에서 routed entry를 다시 계산하므로, 설정된 이름이 라우팅 slug로 되돌아가지 않고 다시 적용됩니다. 관리형 service restart도 proxy가 bind된 직후 이 sync를 다시 시도합니다. 예를 들어 offline login 중이라 이 best-effort boot sync가 실패하면, 이전에 저장된 catalog는 유지되고 다음에 성공한 `ocx sync`가 설정된 이름을 다시 적용합니다. 진짜 upstream native name(예: `gpt-5.6-sol` → "GPT-5.6-Sol")은 고정된 upstream snapshot에서 오며, custom display name으로 덮어쓰지 않습니다.

### 외부 provider manager
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/reference/management-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ first and submit the returned digest. Prefer quarantine when recovery may be nee

| Method and path | Purpose | Notable errors |
| --- | --- | --- |
| `GET /api/catalog` | Return the installed Codex catalog document | 404 catalog not found |
| `GET /api/catalog` | Return the installed Codex catalog document. Remote clients should prefer the data-plane `GET /v1/catalog`, which still requires an ordinary data-plane credential but not an admin token. | 404 catalog not found |
| `GET /api/models` | Return the dashboard/CLI model rows | `catalog_busy` when gathering is saturated |
| `GET /api/client-config?client=...` | Build a read-only client config for any supported file integration | 400 unsupported client; 503 catalog unavailable |
| `PUT /api/disabled-models` | Replace the shared disabled-model list | 400 invalid JSON |
Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/ru/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-windo
```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -264,6 +264,8 @@ Display name можно задать или отредактировать и ч
(`POST /api/custom-models`, `PUT /api/custom-models/<id>` с полем `displayName`) и через
веб-дашборд. Символ `/` запрещён, потому что он столкнулся бы с разделителем routed-slug.

`GET /v1/catalog` существует для того, чтобы чтение списка моделей не требовало админского токена. Маршрут только для чтения (`GET` и `HEAD`), принимает `x-opencodex-api-key`, bearer-токен или `x-api-key` и отдаёт в точности те же байты, что и управляющий маршрут. Ответы содержат строгий `ETag` — верните его в `If-None-Match`, чтобы повторно проверить и получить `304` вместо полного документа — и `Cache-Control: private, no-cache`. Ключ плоскости данных, допущенный здесь, **не получает ничего** на плоскости управления: `/api/catalog` и все маршруты `/api/*` по-прежнему требуют админский токен или сессию панели.

Display name — это **только отображение, и оно устойчиво к перегенерации**. Каждый `ocx sync` и
каждое обновление каталога заново выводят маршрутизируемые записи из `config.json`
(включая `customModels`), поэтому настроенное имя накладывается снова и не «дрейфует» обратно к
Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/tr/guides/codex-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ getirebilir (diğer `/api/*` rotalarıyla aynı kabul belirteci):
```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -307,6 +307,8 @@ dizesiyle `PUT /api/custom-models/<id>`) ve web kontrol paneli aracılığıyla
ayarlayabilir veya düzenleyebilirsiniz. Yönlendirilen slug ayırıcısıyla
çakışacağı için `/` işareti reddedilir.

`GET /v1/catalog`, bir model listesini okumanın yönetici belirtecine mal olmaması için vardır. Rota salt okunurdur (`GET` ve `HEAD`), `x-opencodex-api-key`, bearer belirteci veya `x-api-key` kabul eder ve yönetim rotasıyla tamamen aynı baytları sunar. Yanıtlar güçlü bir `ETag` taşır — tam belge yerine `304` almak için `If-None-Match` ile geri gönderin — ve `Cache-Control: private, no-cache` içerir. Burada kabul edilen bir veri düzlemi anahtarı yönetim düzleminde **hiçbir şey** kazanmaz: `/api/catalog` ve tüm `/api/*` rotaları hâlâ yönetici belirteci veya pano oturumu gerektirir.

Görünen ad **yalnızca görüntüleme amaçlıdır ve yeniden oluşturma boyunca
kararlıdır**. Her `ocx sync` ve katalog yenilemesi yönlendirilen girdileri
`config.json`'dan (`customModels` dahil) yeniden türetir, böylece yapılandırılan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,13 @@ Browser 或 Computer Use。原生 OpenAI 条目会保持其上游 tool mode 不
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

远程 Codex 客户端也可以通过管理 API 拉取同一个生成好的 catalog(与其他 `/api/*` 路由使用相同的 admission token)
远程 Codex 客户端可以使用普通的数据面密钥(与 `/v1/responses` 所用凭据相同,而非管理员令牌)拉取同一个生成好的 catalog

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -230,6 +230,8 @@ ocx sync-cache
你也可以通过管理 API(`POST /api/custom-models`、带 `displayName` 字符串的 `PUT /api/custom-models/<id>`)
以及 web dashboard 来设置或编辑它。因为会与路由 slug 分隔符冲突,所以 `/` 会被拒绝。

`GET /v1/catalog` 的存在是为了让读取模型列表不再需要管理员令牌。该路由为只读(`GET` 与 `HEAD`),接受 `x-opencodex-api-key`、bearer 令牌或 `x-api-key`,并返回与管理路由完全相同的字节。响应携带强 `ETag`——通过 `If-None-Match` 回传即可重新验证并获得 `304` 而非完整文档——同时设置 `Cache-Control: private, no-cache`。在此被接纳的数据面密钥在管理面上**不会**获得任何权限:`/api/catalog` 以及所有 `/api/*` 路由仍然要求管理员令牌或仪表板会话。

display name 是 **仅用于显示且在重新生成时保持稳定的**。每一次 `ocx sync` 和 catalog refresh 都会从
`config.json`(包括 `customModels`)重新派生路由条目,因此配置过的名称会重新应用,而不是漂回路由 slug。
受管服务重启后也会在 proxy 绑定完成后不久尝试做这次 sync。如果这个尽力而为的启动 sync 失败了,比如在离线登录时,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,13 @@ provider 與原生 OpenAI 行銷名稱都維持不動。
ocx models add deepseek deepseek-v4 --display-name "DeepSeek V4" --context-window 128000
```

遠端 Codex client 也能透過管理 API 取得相同的產生目錄,使用與其他 `/api/*` route 相同的 admission
token:
遠端 Codex client 可以使用一般的資料平面金鑰取得相同的產生目錄——與 `/v1/responses` 所用的憑證相同,而非管理或管理員權杖:

```bash
dest="${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"
tmp="$(mktemp "${dest}.XXXXXX")"
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_ADMIN_AUTH_TOKEN" \
"https://proxy.example.com/api/catalog" > "$tmp" \
curl -fsS -H "x-opencodex-api-key: $OPENCODEX_API_AUTH_TOKEN" \
"https://proxy.example.com/v1/catalog" > "$tmp" \
&& mv "$tmp" "$dest"
ocx sync-cache
```
Expand All @@ -237,6 +236,8 @@ ocx sync-cache
也可以透過管理 API(`POST /api/custom-models`、`PUT /api/custom-models/<id>`,搭配 `displayName`
字串)與 web 儀表板設定或編輯。`/` 會被拒絕,因為它會與路由 slug 的分隔符衝突。

`GET /v1/catalog` 的存在是為了讓讀取模型清單不再需要管理員權杖。該路由為唯讀(`GET` 與 `HEAD`),接受 `x-opencodex-api-key`、bearer 權杖或 `x-api-key`,並回傳與管理路由完全相同的位元組。回應帶有強 `ETag`——以 `If-None-Match` 回傳即可重新驗證並取得 `304` 而非完整文件——同時設定 `Cache-Control: private, no-cache`。在此被接納的資料平面金鑰在管理平面上**不會**取得任何權限:`/api/catalog` 以及所有 `/api/*` 路由仍要求管理員權杖或儀表板工作階段。

顯示名稱**只用於顯示,且在重新產生時保持穩定**。每次 `ocx sync` 與目錄 refresh 都會從
`config.json`(包含 `customModels`)重新推導路由條目,因此會重新套用已設定名稱,而不會漂移回路由
slug。受管服務重啟後,也會在 proxy bind 後盡力同步一次。若這次啟動時的 best-effort 同步失敗,例如
Expand Down
4 changes: 4 additions & 0 deletions src/server/auth-cors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ export const AUTH_MATRIX: readonly ApiAuthMatrixRow[] = [
{ endpoint: "/v1/chat/completions", bearer: "accepted", dedicated: "accepted", xApiKey: "rejected" },
{ endpoint: "/v1/messages", bearer: "accepted", dedicated: "accepted", xApiKey: "accepted" },
{ endpoint: "/v1/models", bearer: "accepted", dedicated: "accepted", xApiKey: "accepted" },
// #809: least-privilege catalog read for remote Codex clients. Same admission set as
// /v1/models and for the same reason — it forwards no caller credential upstream — so a
// remote client no longer needs an admin token just to read the model catalog.
{ endpoint: "/v1/catalog", bearer: "accepted", dedicated: "accepted", xApiKey: "accepted" },
];

/** Whether `token` is the environment-provided management secret. */
Expand Down
Loading
Loading