Files
codex/sdk/python/tests/test_app_server_login.py
T
Ahmed Ibrahim 0db49a7e6a [codex] Rename Python SDK AppServerConfig to CodexConfig (#24800)
## Why

`AppServerConfig` is exported as part of the ergonomic Python SDK
surface and passed to `Codex(...)` and `AsyncCodex(...)`. That name
exposes the underlying app-server transport at the same layer where
users are configuring the Codex client. `CodexConfig` makes the common
callsite read naturally and names the object it configures.

## What changed

- Renamed the public configuration dataclass from `AppServerConfig` to
`CodexConfig`.
- Updated `Codex`, `AsyncCodex`, and the transport clients to accept
`CodexConfig`.
- Updated binary-resolution messages, package exports, docs, examples,
and related coverage to use the new public name.

## API impact

```python
from openai_codex import Codex, CodexConfig

with Codex(config=CodexConfig(codex_bin="/path/to/codex")) as codex:
    ...
```

Callers should now import and construct `CodexConfig`; `AppServerConfig`
is no longer part of the Python SDK surface.

## Validation

- `uv run --frozen --extra dev ruff check src/openai_codex scripts
examples tests`
- Tests are deferred to online CI for this PR.
2026-05-27 16:10:15 -07:00

91 lines
3.3 KiB
Python

from __future__ import annotations
import base64
import json
from app_server_harness import AppServerHarness
from openai_codex import Codex, CodexConfig
from openai_codex.generated.v2_all import (
ChatgptAuthTokensLoginAccountParams,
LoginAccountParams,
)
def _app_server_config(harness: AppServerHarness) -> CodexConfig:
"""Build an isolated login config without inheriting ambient API-key auth."""
config = harness.app_server_config()
config.env = {**(config.env or {}), "OPENAI_API_KEY": ""}
return config
def test_api_key_login_authenticates_follow_up_model_requests(tmp_path) -> None:
"""API-key login should authorize the next Responses request with that key."""
with AppServerHarness(tmp_path, requires_openai_auth=True) as harness:
harness.responses.enqueue_assistant_message("api key auth", response_id="api-key-auth")
with Codex(config=_app_server_config(harness)) as codex:
codex.login_api_key("sk-sdk-login-test")
result = codex.thread_start().run("prove api key auth")
request = harness.responses.single_request()
assert {
"final_response": result.final_response,
"authorization": request.header("authorization"),
} == {
"final_response": "api key auth",
"authorization": "Bearer sk-sdk-login-test",
}
def test_chatgpt_token_login_authenticates_follow_up_model_requests(tmp_path) -> None:
"""ChatGPT token handoff should authorize later Responses requests with that token."""
account_id = "workspace-sdk-chatgpt"
def _encode(payload: dict[str, object]) -> str:
raw = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
return base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")
# App-server parses claims from the access token before persisting external ChatGPT auth.
header = _encode({"alg": "none", "typ": "JWT"})
claims = _encode(
{
"email": "sdk-chatgpt@example.com",
"https://api.openai.com/auth": {
"chatgpt_account_id": account_id,
"chatgpt_plan_type": "pro",
},
}
)
access_token = f"{header}.{claims}.sig"
with AppServerHarness(tmp_path, requires_openai_auth=True) as harness:
harness.responses.enqueue_assistant_message(
"chatgpt token auth",
response_id="chatgpt-token-auth",
)
with Codex(config=_app_server_config(harness)) as codex:
login = codex._client.account_login_start(
LoginAccountParams(
root=ChatgptAuthTokensLoginAccountParams(
access_token=access_token,
chatgpt_account_id=account_id,
chatgpt_plan_type="pro",
type="chatgptAuthTokens",
)
)
)
result = codex.thread_start().run("prove chatgpt token auth")
request = harness.responses.single_request()
assert {
"login_type": login.root.type,
"final_response": result.final_response,
"authorization": request.header("authorization"),
} == {
"login_type": "chatgptAuthTokens",
"final_response": "chatgpt token auth",
"authorization": f"Bearer {access_token}",
}