mirror of
https://github.com/openai/codex.git
synced 2026-08-24 13:20:07 +00:00
[Codex Thread 019edd6d-6f14-74e2-853c-345d1803d4a6](https://codex-thread-link.openai.chatgpt-team.site/thread/019edd6d-6f14-74e2-853c-345d1803d4a6) ## Stack Review and merge in order. Every layer is independently correct and documents its safe stopping point. 1. [openai/codex#30292](https://github.com/openai/codex/pull/30292) — aggregate File/Secrets store locking 2. [openai/codex#30293](https://github.com/openai/codex/pull/30293) — resolve and lifecycle-pin the exact OAuth store 3. [openai/codex#30416](https://github.com/openai/codex/pull/30416) — serialized authoritative refresh transaction 4. [openai/codex#30294](https://github.com/openai/codex/pull/30294) — Codex-owned transport refresh and one-shot 401 recovery 5. [openai/codex#30295](https://github.com/openai/codex/pull/30295) — login/logout transaction serialization 6. [openai/codex#30296](https://github.com/openai/codex/pull/30296) — diagnostic-only Auto store drift reporting **This PR is layer 2.** ## Why `Auto` is keyring-first with a File fallback, but re-evaluating that policy during transport reconstruction or persistence can make one MCP client read from one store and later write to another. With rotating refresh tokens, the second store may contain an older token. This layer makes the source selected at client startup explicit and keeps that authority stable for the client lifecycle. ## What this PR does - Keeps `resolve_oauth_tokens_from_store_policy` as the single configured-policy entry point and returns both credentials and the concrete File or Keyring source that supplied them. - Puts exact `load`, `save`, and `delete` operations on `ResolvedOAuthCredentialStore`, making “resolve configured policy” and “use the selected authority” distinct at call sites. - Pins the first concrete source in `pinned_credential_store` in the transport recipe, so initialization retries and session reconstruction cannot re-evaluate `Auto` and adopt another store. - Gives `OAuthPersistor` the resolved store and keeps subsequent persistence and removal on that authority. - Uses a typed keyring-load error to distinguish aggregate-store coordination failures from ordinary backend failures; a coordination failure is surfaced instead of triggering File fallback. - Keeps login-time `Auto` behavior unchanged: prefer Keyring, fall back to File when unavailable, and clean up legacy File state after a successful keyring save. - Adds structured server/backend context when fallback cleanup fails. ## Explicit decisions and non-goals - The selection is lifecycle-local and in memory. This PR does not add a durable backend selector, migration, reconciliation registry, or global source of truth outside `CODEX_HOME`. - `Auto` may choose File at the start of a later process if keyring availability changes. Once this client resolves, a selected-store failure is returned instead of hot-switching. - Different `CODEX_HOME` instances remain independent even when they can access the same Direct keyring credential. - Cross-process refresh serialization is intentionally not part of this layer. ## Safe stopping point This PR can merge alone. A single MCP client no longer hot-switches credential stores across transport rebuilds or persistence. Two processes can still refresh the same selected credential concurrently until layer 3. ## Review size The net layer is 9 files, +668/−144. The production change remains focused on store resolution and lifecycle pinning; the largest follow-up is integration coverage that drives real session recovery. ## Validation - `just test -p codex-rmcp-client` (99 passed; 5 expected skips) - Real-client 404 recovery coverage with different Keyring and File tokens; captured bearer headers prove the stale File token is never sent - Mutation check: removing the lifecycle pin makes that integration regression fail by observing the stale File token