Skip to content

fix(auth): preserve fallback routes and OAuth state (salvage #65264) - #65656

Merged
teknium1 merged 4 commits into
mainfrom
salvage/65264-auth-fallback-oauth-state
Jul 16, 2026
Merged

fix(auth): preserve fallback routes and OAuth state (salvage #65264)#65656
teknium1 merged 4 commits into
mainfrom
salvage/65264-auth-fallback-oauth-state

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Setup-time auth fallback now switches provider and model as a pair on the TUI/desktop and cron surfaces (matching the CLI), and profile OAuth write-through to the global auth store is serialized under a lock keyed to the target store — so a failed Codex route becomes the configured OpenRouter/GLM route instead of OpenRouter + the original GPT model, and concurrent refreshes can no longer erase other providers' credentials.

Salvages #65264 by @dschnurbusch — all four commits cherry-picked onto current main, authorship preserved. Related: supersedes #47460 (xAI-only subset) and overlaps the TUI half of #43861.

Root cause

  • tui_gateway/server.py and cron/scheduler.py fallback loops carried only provider through the chain, keeping the primary model. hermes_cli/cli_agent_setup_mixin.py already switched both — TUI/cron were the divergent siblings (gateway was already correct).
  • _write_through_*_to_global_root in hermes_cli/auth.py and agent/credential_pool.py loaded the global auth.json, mutated one provider, and rewrote the whole file holding only the profile's lock — a lost-update window on the global store.
  • Lock reentrancy used one module-global threading.local, so a mid-thread profile switch could inherit another store's lock depth and skip its kernel flock.

Changes

  • tui_gateway/server.py, cron/scheduler.py: fallback resolves provider+model atomically; provider-only entries are skipped (CLI semantics); cron drift guard compares pre-fallback snapshots so a legitimate fallback doesn't trip a false drift-skip
  • hermes_cli/auth.py: _persist_provider_state_to_store() centralizes target-store-locked merges; _auth_lock_holder_for() keys reentrancy by canonical resolved path; auth → global → Nous-shared lock order preserved
  • agent/credential_pool.py: write-through routed through the locked helper
  • Tests: deterministic lost-update concurrency regression, profile-switch lock isolation, TUI/resumed-session routing, cron fallback provider/model snapshots

Validation

Before After
TUI/cron fallback after AuthError fallback provider + primary model configured provider+model pair
concurrent profile write-through lost update possible 8-way concurrent E2E: zero loss, pre-existing providers intact
lock reentrancy after profile switch shared depth, flock skipped keyed per canonical store path (E2E verified)

581/581 targeted tests (test_credential_pool_oauth_writethrough, test_scheduler, test_auth_profile_fallback, test_tui_gateway_server); tests fail on main without the fix (verified during review); live E2E of lock keying + concurrent write-through against a temp HERMES_HOME; ruff clean.

Note: provider-only fallback entries now fail closed on TUI/cron (consistent with the CLI) — worth a release-note line.

Closes #65264.

Infographic

auth-fallback-oauth-state

Switch provider and model together after setup-time auth failure. Serialize global auth-store merges under target-specific locks and preserve auth-to-shared lock ordering for profile OAuth refreshes.
Skip provider-only setup fallbacks, keep fallback selection explicit for resumed sessions, preserve configured primary identity for cron drift checks, and make the auth lost-update regression deterministic.
Only fallback resolution needs an explicit target model. Keep the primary resolver call compatible with existing callers and test doubles while retaining atomic provider/model fallback selection.
Remove the dynamic active-store holder so a profile context switch cannot inherit another auth store's lock depth and skip its kernel lock.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/cron Cron scheduler and job management area/auth Authentication, OAuth, credential pools P1 High — major feature broken, no workaround sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 16, 2026
@teknium1
teknium1 merged commit a7a0502 into main Jul 16, 2026
33 checks passed
@teknium1
teknium1 deleted the salvage/65264-auth-fallback-oauth-state branch July 16, 2026 13:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management comp/tui Terminal UI (ui-tui/ + tui_gateway/) P1 High — major feature broken, no workaround sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants