HERMES-GIELIE/api
Nathan Esquenazi b34ce63c97 fix(oauth): honor cancel during Codex device-token exchange (follow-up to #1652)
The Codex OAuth onboarding worker introduced in #1652 had a cancel-vs-worker
race: a `cancel_onboarding_oauth_flow` request that arrived while the worker
was mid-network-call (between the `live = dict(...)` snapshot and the next
status check) would be silently overridden:

  1. User clicks Cancel → server sets flow.status = "cancelled" and drops
     sensitive lifecycle fields under the lock.
  2. Worker is mid-`_poll_codex_authorization` / `_exchange_codex_authorization`
     using the local `live` snapshot it captured before the cancel.
  3. Worker calls `_persist_codex_credentials(...)` — auth.json gets written.
  4. Worker calls `_set_flow_status(flow_id, "success")` — overrides the
     cancelled status.

Net effect: the user's explicit cancel is ignored, credentials are persisted,
and the UI reports success. Reproduced with a behavioural harness that drove
a real worker thread against patched network helpers and confirmed:

  pre-fix : flow status `success`, auth.json written despite cancel
  post-fix: flow status `cancelled`, auth.json NOT written

The fix re-checks the flow status under `_OAUTH_FLOWS_LOCK` after the token
exchange completes and before persisting. If the status is no longer
`pending`, the worker exits without persisting credentials and without
overwriting the terminal status.

Regression test `test_cancel_during_token_exchange_does_not_persist_credentials`
drives the worker against threading.Event-gated network stubs to reproduce
the race deterministically and lock the new invariant.

Trace verified against fresh hermes-agent tarball — credential_pool entry
shape (`auth_type=oauth`, `source=manual:device_code`, `priority=0`, base_url)
remains compatible with `agent.credential_pool.load_pool("openai-codex")` and
the agent CLI's `_save_codex_tokens` legacy fallback path.

Tests:
- 10/10 in tests/test_issue1362_codex_oauth_onboarding.py
- Full suite: 4230 passed, 57 skipped, 3 xpassed, 0 failed in 33.82s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 14:49:38 -07:00
..
__init__.py Hermes Web UI — Sprints 11-14: multi-provider models, settings, session QoL, alerts, polish 2026-03-31 07:02:47 +00:00
agent_sessions.py fix: keep cross-source continuations separate in sidebar 2026-05-04 09:30:47 +02:00
auth.py fix: keep frontend routes under subpath mounts 2026-05-04 00:06:58 -07:00
background.py feat(commands): /background, /btw slash commands + undo button + reasoning chip 2026-04-24 01:24:51 +00:00
clarify.py feat(clarify): SSE long-connection for real-time clarify notifications (#1355) 2026-04-30 21:32:51 +00:00
commands.py feat: slash command parity + skill autocomplete — v0.50.91 (PR #711) 2026-04-19 05:37:44 +00:00
config.py Stage 296: PR #1648 — session save mode config (closes #1406) by @Michaelyklam 2026-05-04 21:26:52 +00:00
extensions.py Opus pre-release follow-ups for PR #1445 2026-05-02 03:49:40 +00:00
gateway_watcher.py release: v0.50.241 (#1293) 2026-04-29 19:54:07 -07:00
helpers.py v0.50.255: Opus follow-ups (4 fixes) + CHANGELOG 2026-05-01 17:19:53 +00:00
metering.py fix: show TPS in assistant message headers 2026-05-04 21:26:43 +00:00
models.py feat: add session save mode config 2026-05-04 14:05:49 -07:00
oauth.py fix(oauth): honor cancel during Codex device-token exchange (follow-up to #1652) 2026-05-04 14:49:38 -07:00
onboarding.py feat: add Codex OAuth onboarding flow 2026-05-04 14:07:16 -07:00
profiles.py Apply Opus pre-release SHOULD-FIX + NITs (in-PR per release policy) 2026-05-04 16:17:26 +00:00
providers.py test: cover provider config cleanup path 2026-05-04 09:04:07 -07:00
rollback.py v0.50.255: Opus follow-ups (4 fixes) + CHANGELOG 2026-05-01 17:19:53 +00:00
routes.py Stage 296: PR #1650 — Codex OAuth onboarding flow (refs #1362) by @Michaelyklam 2026-05-04 21:26:52 +00:00
session_ops.py Show profile home in /status command (refs #463) (#1380) 2026-05-01 04:46:37 +00:00
session_recovery.py fix: absorb Opus advisor doc-only SHOULD-FIX nits 2026-05-03 20:54:02 +00:00
startup.py fix: P0 hotfixes — API regression, code block parser, chmod override 2026-05-01 12:10:48 +00:00
state_sync.py security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354) 2026-04-13 11:11:56 -07:00
streaming.py Stage 296: PR #1648 — session save mode config (closes #1406) by @Michaelyklam 2026-05-04 21:26:52 +00:00
terminal.py absorb: address Opus review findings (security + correctness) 2026-04-29 05:06:34 +00:00
updates.py chore(release): stamp v0.50.293 — 3-PR batch + 2 Opus follow-ups absorbed 2026-05-04 16:33:57 +00:00
upload.py Merge remote-tracking branch 'refs/remotes/pr/1229' into stage/batch-v0.50.238 2026-04-29 15:17:57 +00:00
workspace.py fix: batch v0.50.234-235 — XSS hardening, workspace validation, profile switch fixes (#1206) 2026-04-27 21:39:30 -07:00