docs(prd): add Codex host credentials egress plan

This commit is contained in:
2026-05-29 03:14:13 -04:00
committed by didericis
parent 2350cd11e0
commit 0b80ffb16a
@@ -0,0 +1,169 @@
# PRD 0029: Codex host credentials through egress
- **Status:** Draft
- **Author:** didericis-codex
- **Created:** 2026-05-29
- **Issue:** #109
## Summary
Allow Codex bottles to use a host-authorized ChatGPT/device-login
access token by forwarding it only into the egress sidecar, gated by an
explicit `agent_provider.forward_host_credentials` manifest flag.
## Problem
Codex bottles can reach `chatgpt.com` after the host is added to egress,
but requests to `chatgpt.com/backend-api/codex/...` still fail with
HTTP 403. The egress proxy strips agent-originated `Authorization`
headers and only re-injects auth for routes that declare an egress-owned
token. A bare `chatgpt.com` route therefore forwards Codex requests
without the ChatGPT bearer token.
Copying `~/.codex/auth.json` into the agent would solve auth but would
also put access and refresh material inside the agent sandbox. That cuts
against bot-bottle's credential minimization model: provider credentials
should live in the sidecar boundary when possible, not in the agent.
## Goals / Success Criteria
- A Codex bottle with host ChatGPT auth can call
`chatgpt.com/backend-api/codex/...` through egress.
- Host credential forwarding happens only when the bottle declares
`agent_provider.forward_host_credentials: true`.
- The agent container does not receive `OPENAI_API_KEY`,
`CODEX_ACCESS_TOKEN`, `tokens.access_token`, `tokens.refresh_token`,
or `auth.json`.
- Egress route files remain non-secret: they contain only host/path/auth
slot metadata, never token values.
- Missing, non-ChatGPT, malformed, or expired host Codex auth fails
launch with a clear operator-facing message.
- Existing Claude OAuth placeholder behavior remains unchanged.
## Non-goals
- Refreshing Codex tokens in the sidecar. The first cut reads the host's
current access token at launch; operators can restart after host Codex
refreshes auth.
- Copying host `~/.codex/auth.json` into the agent.
- Allowing arbitrary host credential forwarding. This PRD covers Codex
ChatGPT/device-login credentials only.
- Hot-applying a new authenticated `chatgpt.com` route to an existing
running sidecar. The current hot-apply path cannot safely populate new
token env slots in an already-running container.
## Scope
### In scope
- Add `agent_provider.forward_host_credentials` to the bottle manifest
schema, defaulting to `false`.
- Support the flag for `agent_provider.template: codex`.
- Read host Codex auth from `$CODEX_HOME/auth.json` when `CODEX_HOME` is
set, otherwise from `~/.codex/auth.json`.
- Extract only `tokens.access_token`.
- Validate that `auth_mode` is `chatgpt` and the access token is present,
JWT-shaped, and not expired.
- Add or upgrade a `chatgpt.com` egress route to inject that access token
via an `EGRESS_TOKEN_N` sidecar env slot.
- Pass the extracted token only into the sidecar compose/run
environment, alongside other egress token values.
### Out of scope
- Sidecar-owned refresh using `tokens.refresh_token`.
- Sharing full Codex auth state with the agent.
- Supporting host credential forwarding for non-Codex providers.
## Design
### Manifest
Extend `agent_provider`:
```yaml
agent_provider:
template: codex
forward_host_credentials: true
```
The field defaults to `false`. If set on a non-Codex provider, manifest
validation should reject it until that provider has a concrete,
credential-minimizing implementation.
### Host auth extraction
At prepare/launch time, when the flag is enabled for Codex:
1. Resolve the host Codex home directory from `$CODEX_HOME`, falling
back to `~/.codex`.
2. Parse `auth.json`.
3. Require `auth_mode == "chatgpt"`.
4. Require a non-empty `tokens.access_token`.
5. Parse the JWT payload enough to require an `exp` claim in the future.
6. Return only the access token value to the launch path.
Errors should name the missing or invalid condition and point the
operator at `codex login --device-auth`, without printing token values.
### Egress route
When forwarding host Codex credentials, the effective egress route table
should contain an authenticated `chatgpt.com` route. If the bottle
already declares `chatgpt.com` as a bare-pass route, upgrade it in the
effective route table rather than requiring a duplicate manifest entry.
If the bottle already declares an authenticated `chatgpt.com` route,
fail rather than guessing whether to override operator-provided auth.
The rendered route should look like any other egress-owned auth route:
```yaml
routes:
- host: "chatgpt.com"
auth_scheme: "Bearer"
token_env: "EGRESS_TOKEN_N"
```
The access token value is supplied through the sidecar process
environment for that `EGRESS_TOKEN_N` slot. It must not be written to
`routes.yaml`, compose files, env files, logs, or user-facing output.
### Data flow
```mermaid
flowchart LR
H["Host ~/.codex/auth.json"] --> L["bot-bottle launch"]
L -->|access token only| S["egress sidecar env"]
A["Codex agent"] -->|HTTPS via proxy, auth stripped| E["egress"]
E -->|Bearer injected from env| C["chatgpt.com"]
```
## Implementation chunks
1. **PRD first.** Land this document as the first commit on the feature
branch.
2. **Manifest schema.** Add `forward_host_credentials`, validation, and
unit tests.
3. **Host Codex auth reader.** Add a small stdlib-only helper for
parsing and validating host Codex auth without printing values.
4. **Effective egress route.** Add/upgrade the `chatgpt.com` route when
the flag is enabled, and add tests for bare route upgrade,
missing-route insertion, and authenticated-route conflict.
5. **Launch wiring.** Pass the host access token into the egress sidecar
env for Docker and smolmachines without exposing it to the agent.
6. **Docs and tests.** Update README examples and run the unit suite.
## Open questions
- Should a later version support sidecar refresh using the host refresh
token, or should restart-on-expiry remain the policy?
- Should telemetry hosts such as `ab.chatgpt.com` stay blocked by
default even when Codex ChatGPT auth is enabled?
## References
- Gitea issue #109: Codex ChatGPT auth should inject host access token
via egress.
- PRD 0017: Egress-proxy — universal MITM with path filtering + auth
injection.
- PRD 0026: Agent provider templates.