Skip to content
Draft
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
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/fr/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ redirections, les réponses trop volumineuses et les catalogues invalides sont r
écriture locale. L'authentification est facultative et lue uniquement par référence à une variable
d'environnement (`--auth-env`), jamais depuis argv.

Les requêtes HTTP en loopback sont refusées avant l’ajout des en-têtes d’authentification ou tout envoi si `HTTP_PROXY` ou `http_proxy` s’applique sans exception correspondante dans `NO_PROXY` ou `no_proxy`. `ALL_PROXY`/`all_proxy` et les paramètres limités à `HTTPS_PROXY`/`https_proxy` ne déclenchent pas cette restriction HTTP ; l’acquisition de catalogues en HTTPS reste autorisée. Le message de refus ne contient ni l’adresse du proxy ni le jeton d’authentification. Les valeurs non vides de `http_proxy` et `no_proxy` ont priorité sur `HTTP_PROXY` et `NO_PROXY`, respectivement. Pour des exceptions compatibles avec Bun, utilisez des noms d’hôte, des entrées `host:port` correspondantes, des adresses IPv6 entre crochets comme `[::1]`, ou `*`, sans URL, chemin ni préfixe `*.`.

Le catalogue et le cache sont écrits sous le verrou de catalogue Codex partagé ; un échec préserve
les derniers fichiers valides connus. Des octets identiques constituent une non-opération qui
préserve les mtimes. `--restart-codex`, `--restart-app-server-only` et l'alias déprécié
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/ja/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ Codex のローカル モデル ピッカー キャッシュを無効にし、
カタログは、ローカル書き込みの前に拒否されます。認証は任意で、環境変数参照 (`--auth-env`) から
のみ読み取られ、argv からは読み取られません。

`HTTP_PROXY` または `http_proxy` が適用され、`NO_PROXY` または `no_proxy` に一致する除外設定がない場合、ループバック HTTP リクエストは認証ヘッダーの付与や送信より前に拒否されます。`ALL_PROXY`/`all_proxy`、または `HTTPS_PROXY`/`https_proxy` だけの設定では、この HTTP 制限は適用されず、HTTPS によるカタログ取得は引き続き許可されます。拒否メッセージにプロキシのアドレスや認証トークンは含まれません。 空でない `http_proxy` と `no_proxy` は、それぞれ `HTTP_PROXY` と `NO_PROXY` より優先されます。Bun に対応する除外ルールには、ホスト名、一致する `host:port`、`[::1]` のように角括弧で囲んだ IPv6 アドレス、または `*` を使い、URL、パス、`*.` 接頭辞は使わないでください。

カタログとキャッシュは共有の Codex カタログロックの下で書き込まれ、失敗時は last-known-good の
ファイルが保持されます。バイトが同一の場合は mtime を保持する no-op です。`--restart-codex`、
`--restart-app-server-only`、非推奨エイリアス `--restart-desktop-app` は、実際の書き込みの後に
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/ko/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ Codex의 로컬 모델 선택기 캐시를 무효화하여, 활성 opencodex 카
자격증명, 쿼리, 프래그먼트, 리다이렉트, 크기를 넘는 응답, 잘못된 카탈로그는 로컬에 쓰기 전에
거절합니다. 인증은 선택이며 환경변수 이름(`--auth-env`)으로만 읽고 argv로는 받지 않습니다.

`HTTP_PROXY` 또는 `http_proxy`가 적용되고 `NO_PROXY` 또는 `no_proxy`에 일치하는 우회 항목이 없으면 루프백 HTTP 요청은 인증 헤더를 붙이거나 요청을 보내기 전에 거부됩니다. `ALL_PROXY`/`all_proxy` 또는 `HTTPS_PROXY`/`https_proxy`만 설정한 경우에는 이 HTTP 제한에 해당하지 않으며, HTTPS 카탈로그 취득은 계속 허용됩니다. 거부 메시지에는 프록시 주소나 인증 토큰이 포함되지 않습니다. 값이 비어 있지 않은 `http_proxy`와 `no_proxy`는 각각 `HTTP_PROXY`와 `NO_PROXY`보다 우선합니다. Bun과 호환되는 우회 규칙에는 호스트 이름, 일치하는 `host:port`, `[::1]`처럼 대괄호로 감싼 IPv6 주소 또는 `*`를 사용하고, URL·경로·`*.` 접두사는 사용하지 마세요.

카탈로그와 캐시는 공유 Codex 카탈로그 잠금 아래에서 쓰고, 실패하면 직전까지 정상이던 파일을
그대로 둡니다. 바이트가 같으면 mtime까지 건드리지 않는 no-op입니다. `--restart-codex`,
`--restart-app-server-only`, 폐기 예정 별칭 `--restart-desktop-app`은 실제로 쓴 뒤에만
Expand Down
6 changes: 5 additions & 1 deletion docs-site/src/content/docs/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@ before rebuilding the cache. It works even when the local Codex integration desi

The URL must be HTTPS; loopback HTTP is accepted for local testing. Embedded URL credentials,
queries, fragments, redirects, oversized responses, malformed JSON, duplicate or unsafe slugs, and
unknown `input_modalities` are refused before any local write. Authentication is optional and is
unknown `input_modalities` are refused before any local write.

Loopback HTTP requests are refused before authentication headers are attached or any request is sent when `HTTP_PROXY` or `http_proxy` applies without a matching `NO_PROXY` or `no_proxy` bypass. `ALL_PROXY`/`all_proxy` and settings limited to `HTTPS_PROXY`/`https_proxy` do not trigger this HTTP restriction; HTTPS catalog acquisition remains allowed. The refusal message includes neither the proxy address nor the authentication token. Nonempty `http_proxy` and `no_proxy` take precedence over `HTTP_PROXY` and `NO_PROXY`, respectively. For Bun-compatible bypass rules, use hostnames, matching `host:port` entries, bracketed IPv6 addresses such as `[::1]`, or `*`; do not use URLs, paths, or `*.` prefixes.

Authentication is optional and is
read only by environment-variable reference:

```bash
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/ru/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ loopback. Учётные данные в URL, query, фрагменты, ред
каталоги отклоняются до любой локальной записи. Аутентификация необязательна и читается только по
имени переменной окружения (`--auth-env`), но не из argv.

HTTP-запросы к loopback отклоняются до добавления заголовков аутентификации и отправки запроса, если применяется `HTTP_PROXY` или `http_proxy`, а в `NO_PROXY` или `no_proxy` нет подходящего исключения. `ALL_PROXY`/`all_proxy` и настройки только `HTTPS_PROXY`/`https_proxy` не вызывают это ограничение для HTTP; получение каталогов по HTTPS остаётся разрешённым. Сообщение об отказе не содержит адрес прокси или токен аутентификации. Непустые значения `http_proxy` и `no_proxy` имеют приоритет над `HTTP_PROXY` и `NO_PROXY` соответственно. Для совместимых с Bun правил обхода прокси используйте имена хостов, совпадающие записи `host:port`, IPv6-адреса в квадратных скобках, например `[::1]`, или `*`; не используйте URL, пути или префикс `*.`.

Каталог и кэш пишутся под общей блокировкой каталога Codex; при сбое сохраняются last-known-good
файлы. Идентичные байты — это no-op, сохраняющий mtime. `--restart-codex`,
`--restart-app-server-only` и устаревший alias `--restart-desktop-app` здесь означают то же, что
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/tr/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ yanıtlar ve geçersiz kataloglar, herhangi bir yerel yazma işleminden önce re
doğrulama isteğe bağlıdır ve yalnızca ortam değişkeni adıyla (`--auth-env`) okunur, argv'den
alınmaz.

`HTTP_PROXY` veya `http_proxy` geçerliyken `NO_PROXY` ya da `no_proxy` içinde eşleşen bir istisna yoksa loopback HTTP istekleri, kimlik doğrulama başlıkları eklenmeden ve herhangi bir istek gönderilmeden reddedilir. `ALL_PROXY`/`all_proxy` ve yalnızca `HTTPS_PROXY`/`https_proxy` ayarları bu HTTP kısıtlamasını tetiklemez; HTTPS üzerinden katalog alımına izin verilmeye devam edilir. Ret mesajı proxy adresini veya kimlik doğrulama belirtecini içermez. Boş olmayan `http_proxy` ve `no_proxy` değerleri sırasıyla `HTTP_PROXY` ve `NO_PROXY` değerlerinden önce gelir. Bun ile uyumlu proxy atlama kuralları için ana makine adları, eşleşen `host:port` girdileri, `[::1]` gibi köşeli parantez içindeki IPv6 adresleri veya `*` kullanın; URL, yol veya `*.` öneki kullanmayın.

Katalog ve önbellek, paylaşılan Codex katalog kilidi altında yazılır; bir hata durumunda
last-known-good dosyalar korunur. Aynı baytlar, mtime değerlerini koruyan bir no-op'tur.
`--restart-codex`, `--restart-app-server-only` ve kullanımdan kaldırılmış takma ad
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/zh-cn/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ ocx status --json

安装由另一个 OpenCodex 实例的 `/v1/catalog` 端点提供的完整目录,然后同步 `models_cache.json`。URL 必须是 HTTPS;仅回环地址允许 HTTP。URL 内嵌凭据、查询、片段、重定向、超出大小的响应以及无效目录,都会在任何本地写入之前被拒绝。认证是可选的,并且只通过环境变量名(`--auth-env`)读取,不接受 argv 传入。

如果 `HTTP_PROXY` 或 `http_proxy` 生效,且 `NO_PROXY` 或 `no_proxy` 中没有匹配的绕过规则,回环 HTTP 请求会在添加认证标头或发送请求之前被拒绝。`ALL_PROXY`/`all_proxy` 以及仅设置 `HTTPS_PROXY`/`https_proxy` 的情况不会触发此 HTTP 限制;仍允许通过 HTTPS 获取目录。拒绝消息不会包含代理地址或认证令牌。 非空的 `http_proxy` 和 `no_proxy` 分别优先于 `HTTP_PROXY` 和 `NO_PROXY`。要设置与 Bun 兼容的代理绕过规则,请使用主机名、匹配的 `host:port`、`[::1]` 等带方括号的 IPv6 地址或 `*`,不要使用 URL、路径或 `*.` 前缀。

目录和缓存在共享的 Codex 目录锁下写入;失败时保留 last-known-good 文件。字节完全相同时是保留 mtime 的空操作。`--restart-codex`、`--restart-app-server-only` 以及已弃用别名 `--restart-desktop-app` 仅在发生真实写入之后生效,含义与 `ocx sync` / `ocx sync-cache` 相同。`ETag` 条件请求不属于此命令。完整的 `--json` 信封与退出码请参见[英文参考](/reference/cli/lifecycle/)。

## 后台服务
Expand Down
2 changes: 2 additions & 0 deletions docs-site/src/content/docs/zh-tw/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ ocx status --json

安裝由另一個 OpenCodex 執行個體的 `/v1/catalog` 端點提供的完整目錄,接著同步 `models_cache.json`。URL 必須是 HTTPS;僅回送位址允許 HTTP。URL 內嵌憑證、查詢、片段、重新導向、超出大小的回應以及無效目錄,都會在任何本機寫入之前遭拒。驗證為選用,且只透過環境變數名稱(`--auth-env`)讀取,不接受 argv 傳入。

如果 `HTTP_PROXY` 或 `http_proxy` 生效,且 `NO_PROXY` 或 `no_proxy` 中沒有相符的略過規則,回送 HTTP 要求會在加入驗證標頭或送出要求之前遭拒。`ALL_PROXY`/`all_proxy` 以及僅設定 `HTTPS_PROXY`/`https_proxy` 的情況不會觸發此 HTTP 限制;仍允許透過 HTTPS 取得目錄。拒絕訊息不會包含代理位址或驗證權杖。 非空的 `http_proxy` 和 `no_proxy` 分別優先於 `HTTP_PROXY` 和 `NO_PROXY`。若要設定與 Bun 相容的代理略過規則,請使用主機名稱、相符的 `host:port`、`[::1]` 等含方括號的 IPv6 位址或 `*`,不要使用 URL、路徑或 `*.` 前綴。

目錄與快取在共用的 Codex 目錄鎖之下寫入;失敗時保留 last-known-good 檔案。位元組完全相同時是保留 mtime 的無操作。`--restart-codex`、`--restart-app-server-only` 以及已棄用別名 `--restart-desktop-app` 僅在實際寫入之後生效,含義與 `ocx sync` / `ocx sync-cache` 相同。`ETag` 條件式請求不屬於此命令。完整的 `--json` 信封與結束碼請參見[英文參考](/reference/cli/lifecycle/)。

## 背景服務
Expand Down
30 changes: 30 additions & 0 deletions src/codex/catalog/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,42 @@ function safeTimeout(value: number | undefined): number {
? Math.min(Math.floor(value), 120_000) : DEFAULT_TIMEOUT_MS;
}

/** Match Bun fetch's environment routing, not the broader WebSocket NO_PROXY grammar. */
function catalogRequestUsesBunHttpProxy(url: URL): boolean {
if (url.protocol !== "http:") return false;
const proxy = process.env.http_proxy || process.env.HTTP_PROXY;
if (!proxy || proxy === '""' || proxy === "''") return false;
const hostname = url.hostname.toLowerCase();
const host = url.host.toLowerCase();
// Bun env_loader::is_no_proxy (1.4.2): lowercase wins unless empty, ASCII
// whitespace only, no scheme/path/wildcard/bracket/trailing-dot normalization.
const bypasses = process.env.no_proxy || process.env.NO_PROXY || "";
for (let entry of bypasses.split(",")) {
entry = entry.replace(/^[ \t\n\r\v\f]+|[ \t\n\r\v\f]+$/g, "")
.replace(/[A-Z]/g, letter => letter.toLowerCase());
if (entry === "*") return false;
if (entry.startsWith(".")) entry = entry.slice(1);
if (!entry) continue;
const hasPort = entry.startsWith("[")
? entry.includes("]:")
: (entry.match(/:/g)?.length ?? 0) === 1;
if (hasPort ? host === entry : hostname === entry || hostname.endsWith(`.${entry}`)) return false;
}
return true;
}

export async function fetchRemoteCatalog(
input: string,
options: Pick<PullRemoteCatalogOptions, "token" | "timeoutMs" | "maxBytes" | "fetchImpl"> = {},
): Promise<{ document: RemoteCatalogDocument; content: string }> {
const url = validateRemoteCatalogUrl(input);
const token = validateToken(options.token);
if (catalogRequestUsesBunHttpProxy(url)) {
throw new RemoteCatalogError(
"insecure_http_refused",
"Loopback HTTP catalog requests must bypass outbound HTTP proxy routing",
);
}
const headers = new Headers({ Accept: "application/json" });
if (token !== undefined) headers.set("Authorization", `Bearer ${token}`);
let response: Response;
Expand Down
4 changes: 4 additions & 0 deletions structure/catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ is scoped to canonical ChatGPT Responses forwarding; other source-area behavior

Shared parsing and streaming follow the [request-copy](transports/byte-accounting.md#request-copy-accounting) and [stream-buffer accounting](transports/byte-accounting.md#stream-buffer-accounting) contracts. Response-attached WebSocket telemetry follows the [stage record identity contract](transports/responses.md#passthrough-sse-stream-shapes-314).

## Remote catalog HTTP proxy routing

`src/codex/catalog/remote.ts` permits loopback HTTP only when Bun fetch has no effective HTTP proxy or a matching NO_PROXY bypass. Its local matcher follows [Bun fetch semantics](https://github.com/oven-sh/bun/blob/744846f844374847c902b5e7fd59b4342a51ef99/src/dotenv/env_loader.rs#L369), including non-empty lowercase-variable priority, ASCII whitespace, literal host/port comparison and bracket-preserving IPv6. It does not normalize URL-shaped bypass entries, paths, wildcard prefixes, trailing dots or Unicode whitespace, and leaves the broader WebSocket proxy grammar unchanged. It refuses before authentication headers and fetch with a content-free `insecure_http_refused` error. ALL_PROXY and HTTPS-only settings do not affect HTTP acquisition; HTTPS and existing redirect, size, validation and coordinated-installation contracts are preserved. `tests/codex-integration/catalog-remote-pull.test.ts` covers these routing and non-disclosure boundaries.

## Shared catalog

`src/codex/catalog.ts` builds a shared Codex-shaped catalog for CLI, TUI, App, and SDK. It:
Expand Down
2 changes: 2 additions & 0 deletions structure/codex-home.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Codex Home

Catalog HTTP acquisition follows the [proxy-routing contract](catalog.md#remote-catalog-http-proxy-routing).

## Codex home

`src/codex/paths.ts` resolves Codex state from `CODEX_HOME` when set and valid, otherwise from
Expand Down
2 changes: 2 additions & 0 deletions structure/config.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Config Surface

Catalog HTTP acquisition follows the [proxy-routing contract](catalog.md#remote-catalog-http-proxy-routing).

The configuration-only [plaintext V2 contract](subagents.md#plaintext-v2-agent-messages)
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged.

Expand Down
2 changes: 1 addition & 1 deletion structure/gui-and-management-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The shared server request path follows the Responses
[core module ownership](transports/responses.md#core-module-ownership). This surface retains its existing behavior.

The configuration-only [plaintext V2 contract](subagents.md#plaintext-v2-agent-messages)
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged. Response-attached WebSocket telemetry follows the [stage record identity contract](transports/responses.md#passthrough-sse-stream-shapes-314).
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged. Response-attached WebSocket telemetry follows the [stage record identity contract](transports/responses.md#passthrough-sse-stream-shapes-314). Catalog HTTP acquisition follows the [proxy-routing contract](catalog.md#remote-catalog-http-proxy-routing).

## Dashboard serving

Expand Down
2 changes: 2 additions & 0 deletions structure/ops/docs-and-release.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Docs And Release

Catalog HTTP acquisition follows the [proxy-routing contract](../catalog.md#remote-catalog-http-proxy-routing).

The configuration-only [plaintext V2 contract](../subagents.md#plaintext-v2-agent-messages)
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged.

Expand Down
2 changes: 2 additions & 0 deletions structure/providers/openai-tiers.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# OpenAI Provider Account Modes

Catalog HTTP acquisition follows the [proxy-routing contract](../catalog.md#remote-catalog-http-proxy-routing).

The configuration-only [plaintext V2 contract](../subagents.md#plaintext-v2-agent-messages)
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged.

Expand Down
2 changes: 2 additions & 0 deletions structure/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Responses admission and finalization are composed through the
[core module ownership](transports/responses.md#core-module-ownership). This surface retains its existing behavior.

Catalog HTTP acquisition follows the [proxy-routing contract](catalog.md#remote-catalog-http-proxy-routing).

The configuration-only [plaintext V2 contract](subagents.md#plaintext-v2-agent-messages)
is scoped to canonical ChatGPT Responses forwarding; other source-area behavior described here is unchanged.

Expand Down
2 changes: 2 additions & 0 deletions structure/subagents.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Encrypted-task and fallback request handling follow the Responses
[core module ownership](transports/responses.md#core-module-ownership). This surface retains its existing behavior.

Catalog HTTP acquisition follows the [proxy-routing contract](catalog.md#remote-catalog-http-proxy-routing).

## Plaintext V2 agent messages

`src/responses/plaintext-v2-agent-messages.ts` owns the experimental, configuration-only
Expand Down
Loading
Loading