mirror of
https://github.com/openai/codex.git
synced 2026-05-13 15:52:40 +00:00
## Summary TL;DR: teaches `codex-rs` / app-server to request a desktop-provided attestation token and attach it as `x-oai-attestation` on the scoped ChatGPT Codex request paths.  ## Details This PR teaches the Codex app-server runtime how to request and attach an attestation token. It does not generate DeviceCheck tokens directly; instead, it relies on the connected desktop app to advertise that it can generate attestation and then asks that app for a fresh header value when needed. The flow is: 1. The Codex desktop app connects to app-server. 2. During `initialize`, the app can advertise that it supports `requestAttestation`. 3. Before app-server calls selected ChatGPT Codex endpoints, it sends the internal server request `attestation/generate` to the app. 4. app-server receives a pre-encoded header value back. 5. app-server forwards that value as `x-oai-attestation` on the scoped outbound requests. The code in this repo is mostly protocol and runtime plumbing: it adds the app-server request/response shape, introduces an attestation provider in core, wires that provider into Responses / compaction / realtime setup paths, and covers the intended scoping with tests. The signed macOS DeviceCheck generation remains owned by the desktop app PR. ## Related PR - Codex desktop app implementation: https://github.com/openai/openai/pull/878649 ## Validation <details> <summary>Tests run</summary> ```sh cargo test -p codex-app-server-protocol cargo test -p codex-core attestation --lib cargo test -p codex-app-server --lib attestation ``` Also ran: ```sh just fix -p codex-core just fix -p codex-app-server just fix -p codex-app-server-protocol just fmt just write-app-server-schema ``` </details> <details> <summary>E2E DeviceCheck validation</summary> First validated the signed desktop app boundary directly: launched a packaged signed `Codex.app`, sent `attestation/generate`, decoded the returned `v1.` attestation header, and validated the extracted DeviceCheck token with `personal/jm/verify_devicecheck_token.py` using bundle ID `com.openai.codex`. Apple returned `status_code: 200` and `is_ok: true`. Then ran the fuller app + app-server flow. The packaged `Codex.app` launched a current-branch app-server via `CODEX_CLI_PATH`, and a local MITM proxy intercepted outbound `chatgpt.com` traffic. The app-server requested `attestation/generate` from the real Electron app process, and the intercepted `/backend-api/codex/responses` traffic included `x-oai-attestation` on both routes: ```text GET /backend-api/codex/responses Upgrade: websocket x-oai-attestation: present POST /backend-api/codex/responses Upgrade: none x-oai-attestation: present ``` The captured header decoded to a DeviceCheck token that also validated with Apple for `com.openai.codex` (`status_code: 200`, `is_ok: true`, team `2DC432GLL2`). </details> --------- Co-authored-by: Codex <noreply@openai.com>
WARNING: this code is mainly generated by Codex and should not be used in production
codex-debug-client
A tiny interactive client for codex app-server (protocol v2 only). It prints
all JSON-RPC lines from the server and lets you send new turns as you type.
Usage
Start the app-server client (it will spawn codex app-server itself):
cargo run -p codex-debug-client -- \
--codex-bin codex \
--approval-policy on-request \
--output-file /tmp/app-server-server-json.jsonl
You can resume a specific thread:
cargo run -p codex-debug-client -- --thread-id thr_123
CLI flags
--codex-bin <path>: path to thecodexbinary (default:codex).-c, --config key=value: pass through--configoverrides tocodex.--thread-id <id>: resume a thread instead of starting a new one.--approval-policy <policy>:untrusted,on-failure(deprecated),on-request,never.--auto-approve: auto-approve command/file-change approvals (default: decline).--final-only: only show completed assistant messages and tool items.--output-file <path>: write raw server JSONL to this file instead of stdout.--model <name>: optional model override for thread start/resume.--model-provider <name>: optional provider override.--cwd <path>: optional working directory override.
Interactive commands
Type a line to send it as a new turn. Commands are prefixed with ::
:helpshow help:newstart a new thread:resume <thread-id>resume a thread:use <thread-id>switch active thread without resuming:refresh-threadlist available threads:quitexit
The prompt shows the active thread id. Client messages (help, errors, approvals)
print to stderr; raw server JSON prints to stdout so you can pipe/record it
unless --final-only is set. Pass --output-file <path> to record raw server
JSONL to a file instead of stdout.
Notes
- The client performs the required initialize/initialized handshake.
- It prints every server notification and response line as it arrives.
- Approvals for
item/commandExecution/requestApprovalanditem/fileChange/requestApprovalare auto-responded to with decline unless--auto-approveis set.