Commit Graph

10 Commits

  • feat: use encrypted local secrets for CLI auth (#27539)
    ## Why
    
    Windows Credential Manager limits generic credential blobs to 2,560
    bytes. Large serialized ChatGPT auth payloads can exceed that limit, so
    keyring-mode CLI auth needs a backend that keeps only the encryption key
    in the OS keyring and stores the payload in Codex's encrypted
    local-secrets file.
    
    This is the third PR in the encrypted-auth stack:
    
    1. #27504 — feature and config selection
    2. #27535 — auth-specific local-secrets namespaces
    3. This PR — CLI auth implementation and activation
    4. MCP OAuth implementation and activation
    
    ## What Changed
    
    - Added encrypted CLI-auth storage using the `CliAuth` secrets
    namespace.
    - Preserved direct keyring storage for platforms/configurations where it
    remains selected.
    - Selected the backend consistently for login, logout, refresh,
    device-code login, auth loading, and login restrictions.
    - Threaded resolved bootstrap/full config through CLI, exec, TUI,
    app-server account handling, cloud config, and cloud tasks.
    - Removed stale `auth.json` fallback data after successful encrypted
    saves and removed encrypted, direct-keyring, and fallback data during
    logout.
    - Added storage and integration coverage for both direct and encrypted
    keyring modes.
    
    MCP OAuth persistence is intentionally left to the next PR.
    
    ## Validation
    
    - `just test -p codex-login` — 131 passed
    - `just test -p codex-cli` — 280 passed
    - `just test -p codex-app-server v2::account` — 25 passed
    - `just test -p codex-cloud-config service` — 21 passed, 7 skipped
    - `just fix -p codex-login`
    - `just fix -p codex-cli`
    - `just fmt`
  • [codex] Pass auth mode to plugin manager (#27517)
    ## Summary
    - Add auth mode state to `PluginsManager`.
    - Sync the plugin manager auth mode when `ThreadManager` is created and
    when account auth changes.
    - Route plugin load outcomes through an auth-aware projection hook so
    follow-up plugin filtering can stay inside `core-plugins`.
    
    ## Motivation
    This prepares plugin capability loading to be configured by auth mode,
    such as hiding or exposing app/MCP-backed plugin surfaces based on
    whether the user is using ChatGPT auth or API-key auth, without leaking
    those details outside the plugin manager.
    
    ## Tests
    - `just fmt`
    - `just test -p codex-core-plugins`
    - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p
    codex-core thread_manager::tests`
    - `env -u CODEX_SANDBOX_NETWORK_DISABLED -u CODEX_SANDBOX just test -p
    codex-app-server`
  • [codex-rs] support v2 personal access tokens (#25731)
    ## Summary
    
    - add v2 personal access token support for `codex login
    --with-access-token` and `CODEX_ACCESS_TOKEN`
    - classify opaque `at-` tokens separately from legacy Agent Identity
    JWTs
    - hydrate required ChatGPT account metadata through AuthAPI
    `/v1/user-auth-credential/whoami`
    - use PATs directly as bearer tokens while preserving existing ChatGPT
    account surfaces
    - expose PAT-backed auth as the explicit `personalAccessToken`
    app-server auth mode
    
    ## Implementation
    
    PAT auth is intentionally small and stateless. Loading a PAT performs
    one AuthAPI metadata request, stores the hydrated metadata in the
    in-memory auth object, and redacts the secret from debug output. Legacy
    Agent Identity JWT handling remains unchanged. The shared access-token
    classifier lives in a private neutral module because it dispatches
    between both credential types.
    
    PAT hydration fails closed when AuthAPI omits any required metadata,
    including email. Hydrated metadata is intentionally not persisted:
    startup performs a live `whoami` preflight so revoked tokens or changed
    account metadata are not accepted from a stale cache.
    
    ## Workspace restriction scope
    
    This change intentionally does **not** apply
    `forced_chatgpt_workspace_id` to PAT authentication. The setting is a
    client-side config guardrail, not an authorization boundary, and PAT
    does not currently require workspace-ID parity. The PAT login and
    `CODEX_ACCESS_TOKEN` paths therefore validate through AuthAPI without
    threading workspace-restriction state through access-token loading.
    Existing workspace checks for non-PAT auth remain on their established
    paths.
    
    ## App-server compatibility
    
    The public app-server `AuthMode` is shared across v1 and v2, and
    PAT-backed auth reports `personalAccessToken` through both APIs.
    Following human review, this intentionally removes the temporary v1
    compatibility mapping that reported PATs as `chatgpt`; the deprecated v1
    API is kept in parity with v2 rather than maintaining a separate closed
    enum. Clients with exhaustive auth-mode handling in either API version
    must add the new case and should generally treat it as ChatGPT-backed
    unless they need PAT-specific behavior.
    
    The v1 auth-status response still omits the raw PAT when `includeToken`
    is requested because that response cannot carry the account metadata
    needed to reuse the credential safely. Persisted PAT auth also omits the
    new enum value so older Codex builds can deserialize `auth.json` and
    infer PAT auth from the credential field after a rollback.
    
    ## Validation
    
    Latest review-fix validation:
    
    - `CARGO_INCREMENTAL=0 just test -p codex-login` (126 passed)
    - `CARGO_INCREMENTAL=0 just test -p codex-cli` (263 passed)
    - `CARGO_INCREMENTAL=0 just test -p codex-cli
    stored_auth_validation_handles_personal_access_token`
    - `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol` (226
    passed)
    - `CARGO_INCREMENTAL=0 just test -p codex-models-manager
    refresh_available_models_uses_remote_only_catalog_for_chatgpt_auth`
    - `CARGO_INCREMENTAL=0 just test -p codex-tui
    existing_non_oauth_chatgpt_login_counts_as_signed_in`
    - `CARGO_INCREMENTAL=0 just fix -p codex-login -p
    codex-app-server-protocol -p codex-models-manager -p codex-tui -p
    codex-cli`
    - `just fmt`
    - `git diff --check`
    
    The broader `codex-tui` suite previously compiled and ran 2,834 tests.
    Three unrelated environment-sensitive guardian/IDE-socket tests failed
    after retries; the PAT-relevant TUI coverage passed.
  • feat(app-server): expose account token usage [1 of 2] (#25344)
    ## Why
    
    Token activity is useful account-level context, but terminal clients
    need a supported app-server path to fetch it without reaching into
    ChatGPT backend details directly. The API should also live under the
    broader account usage umbrella so future usage surfaces can be added
    without proliferating user-facing concepts.
    
    ## What Changed
    
    - Add `codex-backend-client` support for the ChatGPT profile token-usage
    payload.
    - Add the v2 `account/usage/read` app-server RPC.
    - Map lifetime usage, peak daily usage, streak, longest task duration,
    and daily buckets into app-server protocol types.
    - Gate the request on Codex-backend auth, which supports ChatGPT auth
    tokens and AgentIdentity.
    - Regenerate the app-server JSON and TypeScript schema fixtures.
    
    ## Token Count Source
    
    `account/usage/read` returns the token-usage aggregate supplied by the
    ChatGPT profile backend. App-server maps that backend-owned aggregate
    into protocol fields; it does not recompute cached-token treatment,
    usage multipliers, or raw input/output totals locally.
    
    ## Stack
    
    1. feat(app-server): expose account token usage [1 of 2] (this PR)
    2. [#25345](https://github.com/openai/codex/pull/25345) feat(tui): add
    token activity command [2 of 2]
    
    ## How to Test
    
    1. Start an app-server client from this branch while authenticated with
    ChatGPT or AgentIdentity.
    2. Call `account/usage/read`.
    3. Confirm the response includes `summary` and `dailyUsageBuckets`.
    4. Also verify a session without Codex-backend auth receives the
    existing auth error path.
    
    Targeted tests:
    - `just test -p codex-backend-client -p codex-app-server-protocol -p
    codex-app-server`
    - `just write-app-server-schema`
  • Switch runtime to cloud config bundle (#24622)
    ## Summary
    
    - Adapts the moved `codex-cloud-config` crate from the legacy cloud
    requirements endpoint to the new config bundle endpoint.
    - Switches runtime consumers from `CloudRequirementsLoader` to
    `CloudConfigBundleLoader` so one shared bundle supplies cloud-delivered
    config and requirements.
    - Removes the legacy cloud requirements domain loader path.
    
    ## Details
    
    This intentionally keeps `codex-cloud-config` monolithic for review
    lineage: the previous PR establishes the crate move, and this PR shows
    the behavior change against that moved implementation. A follow-up PR
    splits the module back into focused files.
    
    The new bundle path preserves the important cloud requirements loader
    semantics where intended: account-scoped signed cache, 30 minute TTL, 5
    minute refresh cadence, retry/backoff, auth recovery, and fail-closed
    startup loading. The cached payload changes from a single requirements
    TOML string to the backend-delivered bundle, and validation rejects
    malformed config or requirements fragments before cache write/use.
  • [codex] Support multiple forced ChatGPT workspaces (#18161)
    ## Summary
    
    This change lets `forced_chatgpt_workspace_id` accept multiple workspace
    IDs instead of a single value.
    
    It keeps the existing config key name, adds backward-compatible parsing
    for a single string in `config.toml`, and normalizes the setting into an
    allowed workspace list across login enforcement, app-server config
    surfaces, and local ChatGPT auth helpers.
    
    ## Why
    
    Workspace-restricted deployments may need to allow more than one ChatGPT
    workspace without dropping the guardrail entirely.
    
    ## Server-side impact
    
    Codex's local server and app-server protocol needed changes because they
    previously assumed a single workspace ID. The local login flow now
    matches the auth backend interface by sending the allowed workspace list
    as a single comma-separated `allowed_workspace_id` query parameter.
    
    ## Validation
    
    This was tested with:
    
    - A single workspace config
    - With multi-workspace configs
    - With multiple workspaces in the config
    - The user only being a part of a subset of them
    
    All were successful.
    
    Automated coverage:
    
    - `cargo test -p codex-login`
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-tui local_chatgpt_auth`
    - `cargo test --locked -p codex-app-server
    login_account_chatgpt_includes_forced_workspace_allowlist_query_param`
  • [app-server] Gate login issuer override constant (#22338)
    Gate the debug-only login issuer override constant so release builds no
    longer warn that it is unused.
  • Preserve session MCP config on refresh (#21055)
    # Overview
    MCP refreshes were rebuilding active threads from fresh disk-backed
    config only, which dropped thread-start session overlays such as
    app-injected MCP servers. This keeps refreshes current with disk config
    while preserving the thread-local config that only the active thread
    knows about.
    
    # Changes
    - Rebuild refreshed config per active thread using that thread's current
    `cwd`, rather than fanning out one app-server config to every thread.
    - Preserve each thread's `SessionFlags` layer while replacing reloadable
    config layers with freshly loaded config, then derive the MCP refresh
    payload from the rebuilt result.
    - Move MCP refresh orchestration into app-server so manual refreshes
    fail loudly while background refreshes remain best-effort, and route
    plugin-triggered refreshes through the same per-thread reload path.
    - Add regression coverage for session overlays, fresh project config,
    plugin-derived MCP config, current requirements, and strict vs
    best-effort refresh behavior.
    
    # Verification
    - Passed focused Rust coverage for the thread-config rebuild behavior
    and deferred MCP refresh flow, plus `cargo test -p codex-app-server
    --lib`.
    - Verified end to end in the Codex dev app against the locally built
    CLI: registered an MCP via thread config, verified that it could be used
    successfully before refresh, manually triggered MCP refresh, and
    verified that it continued to be available afterward.
  • [codex] Use shared app-server JSON-RPC error helpers (#21221)
    ## Why
    
    App-server had repeated hand-built JSON-RPC error objects for standard
    error shapes. Using the shared helpers keeps the common
    `invalid_request`, `invalid_params`, and `internal_error` construction
    in one place and reduces the chance of new call sites drifting from the
    common error payload shape.
    
    ## What changed
    
    - Replaced manual standard JSON-RPC error object creation with
    `internal_error(...)`, `invalid_request(...)`, and `invalid_params(...)`
    across app-server request processors and runtime paths.
    - Removed local duplicate helper definitions from search and review
    request handling.
    - Preserved existing structured `data` payloads by creating the shared
    helper error first and then attaching the existing metadata.
    - Left custom non-standard errors and raw error-code assertions intact.
    
    ## Validation
    
    - `cargo test -p codex-app-server`
  • [codex] Split app-server request processors (#20940)
    ## Why
    
    The app-server request path had grown around a large
    `CodexMessageProcessor` plus separate API wrapper/helper modules. That
    made the dependency graph hard to see and forced unrelated request
    families to share broad processor state.
    
    This PR makes the split mechanical and command-prefix oriented so
    request families own only the dependencies they use.
    
    ## What changed
    
    - Replaced `CodexMessageProcessor` with command-prefix request
    processors under `app-server/src/request_processors/`.
    - Removed the old config, device-key, external-agent-config, and fs API
    wrapper files by moving their API handling into processors.
    - Split apps, plugins, marketplace, catalog, account, MCP, command exec,
    fs, git, feedback, thread, turn, thread goals, and Windows sandbox
    handling into dedicated processors.
    - Kept shared lifecycle, summary conversion, token usage replay, and
    shared error mapping only where multiple processors use them; single-use
    helpers were inlined into their owning processor.
    - Removed the fallback processor path and moved processor tests to
    `_tests` files.
    
    ## Validation
    
    - `cargo test -p codex-app-server`
    - `cargo check -p codex-app-server`
    - `just fix -p codex-app-server`