Skip to content

fix(auth): fall back to global auth.json in _load_provider_state - #33352

Merged
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/nous-provider-global-fallback-32020
May 27, 2026
Merged

fix(auth): fall back to global auth.json in _load_provider_state#33352
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kshitijk4poor:fix/nous-provider-global-fallback-32020

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Salvage of #32020 by @JohnC1009 onto current main (317 commits behind merge-base, but no overlap on _load_provider_state — plain git cherry-pick auto-merged cleanly, +123/-15 matches the original PR exactly).

Closes #32020

Summary

In profile mode, _load_provider_state returns None when a provider is absent from the profile's auth.json — even if the user has authenticated at the global root. This breaks runtime credential resolvers that read state directly (resolve_nous_access_token, resolve_nous_runtime_credentials), causing profiles without their own per-profile login to fail with "Hermes is not logged into Nous Portal" despite a valid global session.

The existing read-only global fallback is already used by get_provider_auth_state (added in #20819) and read_credential_pool for per-provider shadowing. This PR pushes that same fallback into _load_provider_state itself, so every caller benefits — and simplifies get_provider_auth_state into a thin wrapper.

Change

  • _load_provider_state now consults the global auth store as a read-only fallback when the profile has no entry for the requested provider, mirroring the per-provider shadowing semantics already used by read_credential_pool.
  • get_provider_auth_state becomes a thin wrapper since the fallback now lives one layer down. Its external contract is unchanged.
  • Writes (_save_provider_state, persist_*_credentials) are untouched — they still target the profile only. Once the user runs hermes auth login <provider> inside the profile, the profile state fully shadows the global state on the next read.
  • In classic (non-profile) mode behavior is unchanged: _load_global_auth_store() returns an empty dict, so the fallback is a no-op.

Affected callers

All 12 callers of _load_provider_state benefit transparently. The two that previously bypassed the fallback (and triggered the bug) are:

  • resolve_nous_access_token
  • resolve_nous_runtime_credentials

Verification

  • 16/16 tests pass on tests/hermes_cli/test_auth_profile_fallback.py (5 new tests in this PR + 11 pre-existing)
  • 674/0 in the broader auth/credentials sweep (41 files via scripts/run_tests.sh)
  • Ruff clean on both changed files; zero net-new lint diagnostics
  • E2E confirms all three semantics with a real isolated HERMES_HOME: profile-empty→global, profile-present→profile-wins, both-empty→None
  • get_provider_auth_state external contract preserved (same dict(state) copy semantics, same classic-mode behavior, same malformed-global tolerance, same pytest seat belt)

Pre-merge dependency

Author JohnC1009@users.noreply.github.com added to AUTHOR_MAP in #33351 — merge that first so contributor_audit.py strict mode doesn't fail when this lands.

Credit

All substantive work by @JohnC1009 in the original PR; cherry-picked here with authorship preserved.

In profile mode, _load_provider_state previously returned None when a
provider was absent from the profile's auth.json — even if the user had
authenticated at the global root. This broke runtime credential resolvers
that read state directly (resolve_nous_access_token,
resolve_nous_runtime_credentials), causing profiles without their own
nous login to fail with 'Hermes is not logged into Nous Portal' despite
a valid global session.

Push the existing read-only global fallback (already used by
get_provider_auth_state and read_credential_pool) into _load_provider_state
so every caller benefits, and simplify get_provider_auth_state into a thin
wrapper. Writes still target the profile only — profile state continues to
shadow global state on the next read after a per-profile login. Behavior in
classic (non-profile) mode is unchanged because _load_global_auth_store
returns an empty dict.

Adds 5 tests covering the new contract on _load_provider_state directly.
Existing 770 auth/credential/nous tests still pass.
@kshitijk4poor
kshitijk4poor force-pushed the fix/nous-provider-global-fallback-32020 branch from a674e0a to ce3ad89 Compare May 27, 2026 16:38
@kshitijk4poor
kshitijk4poor merged commit 414a5bc into NousResearch:main May 27, 2026
18 checks passed
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard labels May 27, 2026
@kshitijk4poor
kshitijk4poor deleted the fix/nous-provider-global-fallback-32020 branch August 5, 2026 07:08
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/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants