fix(auth): stop Codex OAuth worker on cancel, pin resolved profile - #74341
Closed
JoaoMarcos44 wants to merge 1 commit into
Closed
fix(auth): stop Codex OAuth worker on cancel, pin resolved profile#74341JoaoMarcos44 wants to merge 1 commit into
JoaoMarcos44 wants to merge 1 commit into
Conversation
…rofile Cancelling an OpenAI Codex device-code login left the background poller running, and the token-write path re-resolved the target profile lazily via _oauth_session_profile(), which returned None once cancel popped the session and silently fell back to whatever profile was "current". Adds a per-session threading.Event set by the cancel endpoint. The codex worker now pins its target profile once at start (before the session can be popped), checks the cancel event before each poll iteration and again before exchanging the code and before writing tokens, and aborts without writing if cancelled.
Collaborator
Duplicate of #73914: both patches add cancellation checks through the Codex device-code worker and pin its session profile to prevent post-cancel credential persistence. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#00f0ff', 'mainBkg': '#0a0a16', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#ff007f', 'lineColor': '#00f0ff'}}}%% graph TD A[🔒 Cancel Request] --> B{Old Behavior} A --> C{Fixed Behavior} B --> D[⚠️ Session Removed] D --> E[🐛 Worker Keeps Polling] E --> F[🐛 Code Approved Late] F --> G[💀 Profile Lookup Returns None] G --> H[💀 Tokens Written To Wrong Profile] C --> I[⚡ Cancel Event Set] I --> J[🚀 Worker Checks Event] J --> K[✅ Safe Abort - No Write] style B fill:#3a0a12,stroke:#ff007f style D fill:#3a0a12,stroke:#ff007f style E fill:#3a0a12,stroke:#ff007f style F fill:#3a0a12,stroke:#ff007f style G fill:#3a0a12,stroke:#ff007f style H fill:#3a0a12,stroke:#ff007f style C fill:#0a2a2f,stroke:#00f0ff style I fill:#0a2a2f,stroke:#00f0ff style J fill:#0a2a2f,stroke:#00f0ff style K fill:#0a2a2f,stroke:#00f0ffSummary
threading.Eventthat the cancel endpoint sets, and wires it into every checkpoint of the Codex device-code worker (poll loop, code exchange, token write).Root Cause
In
hermes_cli/web_server.py:_codex_full_login_worker's poll loop (while time.monotonic() < deadline: time.sleep(poll_interval); poll = client.post(...)) never checked any cancellation signal — it ran to completion regardless of whether the dashboard had cancelled the session.DELETE /api/providers/oauth/sessions/{session_id}only did_oauth_sessions.pop(session_id, None)— it removed the session bookkeeping but never signalled the worker thread to stop._oauth_session_profile(session_id). Once the session had been popped by cancellation, that lookup returnedNone, and_profile_scope(None)silently fell back to whatever profile was currently active — not the profile the session was originally started for.Net effect: cancel a Codex login, then approve the device code late (or race the cancel against an in-flight approval) → the worker kept running, "succeeded", and wrote OAuth tokens into the wrong profile with no user-visible error.
Fix
_new_oauth_sessionnow stores athreading.Event()(cancel_event) alongside each session.DELETE /api/providers/oauth/sessions/{session_id}sets that event before popping the session from_oauth_sessions._codex_full_login_worker:cancel_eventand the resolvedtarget_profileonce, at the very start, while the session entry is still guaranteed to exist.cancel_event.is_set()before and after each poll-loop sleep, before exchanging the device code for tokens, and immediately before calling_save_codex_tokens.target_profilefor the write instead of re-resolving_oauth_session_profile(session_id), so even a raced write always lands on the originally-intended profile — and only happens if the session was never cancelled.The other device-code pollers (Nous, MiniMax, xAI) are unchanged — this fix is scoped to the Codex flow reported in the issue, since it's the only one that inlines its own poll loop directly in
web_server.py.Test Plan
test_codex_dashboard_worker_aborts_after_cancelintests/hermes_cli/test_web_oauth_dispatch.py: starts a Codex session, cancels it via the realDELETE /api/providers/oauth/sessions/{id}endpoint from inside a monkeypatchedtime.sleep(simulating "user clicks Cancel while the worker is paused between polls"), then lets the poll "succeed" and code-exchange "succeed" — asserts_save_codex_tokenswas never called and the session stays removed.pytest tests/hermes_cli/test_web_oauth_dispatch.py -v→ 25 passed (new test + all pre-existing OAuth dispatch tests, including the two pre-existing Codex worker tests, confirming no regression).python -m py_compile hermes_cli/web_server.py→ compiles cleanly.test_dashboard_oauth_write_uses_owner_only_permissionsfailure intest_web_server_oauth_write.pyis pre-existing (fails identically onmainbefore this change) — Windows file-mode semantics, unrelated to this fix.Closes #74308