Commit Graph

9 Commits

Author SHA1 Message Date
kshitijk4poor
80d8d28392 fix(auth): route the borrowed-root add_entry write through the token-base boundary
The profile-claims-its-own-credential branch of add_entry wrote the
profile store directly, so the newly owned rows had no recorded token
base until the next pre-refresh sync, and a stale peer could not be told
apart from an unknown one on the first later flush. Pass the current bases
and reseed from the written rows, mirroring _persist().
2026-09-24 15:44:48 +05:30
JoaoMarcos44
d2f54de2cc fix(auth): bind stale pool writes to token generation
(cherry picked from commit 1f5c7bcd076cd6184fb048ea1a57c4549f5f4991)
2026-09-24 15:44:48 +05:30
teknium1
2632229bcf fix(auth): named profiles read the root auth.json again (revert #111724)
Reverts 93889b770d ("named profiles no longer inherit the root
profile's auth.json"). After the Desktop update every bot profile that had
relied on the root OpenAI Codex login failed with "No Codex credentials
stored. Run `hermes -p <bot> auth add openai-codex --type oauth`", and users
had to re-run the device-code flow once per bot (5-6 times in the field
report). Sharing one grant across profiles is the intended design: OAuth
refresh tokens are single-use, so ONE grant lives at the root, profiles
resolve it read-only, and a refresh under a profile writes the rotated chain
back to root (Codex / xAI write-through, borrowed-row pool bookkeeping,
forked-grant heal) — never a per-profile copy.

Restored: `_global_auth_file_path` / `_load_global_auth_store` fallback in
`_load_provider_state*` / `read_credential_pool` / `_provider_state_transaction`,
Codex + xAI root write-through, `credential_pool` borrowed-root persistence,
`heal_forked_single_use_oauth_grants`, `share_auth` on profile creation
(Desktop create dialog checkbox), and the docs. `profile_credential_audit.py`
(the `hermes update` "profiles without a provider" notice) is removed with it.

Kept from after #111724: `_save_codex_tokens(set_active=...)` for image gen,
the plugin-auth `status` dispatch and the external-login notice in
`hermes auth list`, and the registry-derived env-var hint in agent_init.
2026-09-21 09:55:40 -07:00
teknium1
a564f77746 fix(auth): hermes auth reset survives a live session's next pool flush
A running gateway/chat holds the credential pool in memory. When the CLI
resets a still-binding cooldown from another process, the reset row on
disk has no status at all, so the recency merge in write_credential_pool
(which ranks by last_status_at) could not tell "reset after my cooldown"
from "never had a status" and let the live pool's stale EXHAUSTED entry
win on its next ordinary flush - a rotation, a token refresh, a sibling
429. `hermes auth reset` printed success and the cooldown came back
(#89415, step B in the thread). status_cleared_ids only protects the
resetting write itself.

reset_status/reset_statuses now stamp status_cleared_at on the cleared
row. The disk-cooldown merge adopts the disk row whenever the in-memory
entry is DEAD/EXHAUSTED and that marker postdates its last_status_at, and
_resync_stale_entry lifts the in-memory cooldown from the same marker, so
the live session serves the credential again without a restart. The
marker is sticky but only outranks OLDER statuses: a fresh exhaustion
after the reset stamps a newer last_status_at and still binds.

Live probe (temp HERMES_HOME, fake Codex entry, process A = live pool,
process B = real auth_reset_command): before, disk read `exhausted`
again after A's flush and A re-selected None; after, disk stays clear and
A re-selects the entry (mem ok). Control: reset then a new 402 stays
exhausted through flush and re-select.
2026-09-19 09:40:56 -07:00
KoNit-K
fb358d4379 fix(agent): scope Anthropic 429 cooldowns to model 2026-09-16 17:16:06 -07:00
teknium1
93889b770d fix(auth): named profiles no longer inherit the root profile's auth.json (#111724)
A named profile with no credentials of its own silently resolved the root
profile's provider state and credential pool, and a token refresh inside
that profile (xAI, Codex, Anthropic PKCE, Nous) wrote the rotated chain back
into the root store. An isolated service profile therefore acted, and
rotated tokens, as the owner with no way to switch it off.

Maintainer ruling: profiles without credentials are asked to set a provider,
never handed another profile's auth. Profiles are independent islands.

What changes
- `hermes_cli/auth.py`: `_load_provider_state*`, `read_credential_pool` and
  `_provider_state_transaction` read the active store only; the global-root
  resolver, its mtime memo and `_persist_provider_state_to_store` are gone.
- xAI / Codex / Nous-guest / pool refresh paths persist to the active store;
  the root write-through, the borrowed-row bookkeeping
  (`_borrowed_root_ids`, `persist_pool_entries`, `_update_root_pool_rows`)
  and the forked-grant heal are removed. `_write_hermes_oauth_credentials`
  loses its root `target`.
- `resolve_provider` / `agent_init` name the profile in the
  no-provider error and print `hermes -p <name> model` guidance.
- `hermes update` prints a one-time notice listing every named profile that
  has no provider of its own (`hermes_cli/profile_credential_audit.py`) so a
  bot never goes quiet unannounced.
- Desktop create dialog: the "Share keys & accounts" checkbox described the
  removed inheritance; it now mirrors API keys (`mirror_credentials`) and
  says OAuth logins need a sign-in. `share_auth` is accepted from older
  clients and ignored; `ProfileMirrored.auth` is a bool again.
- Docs: profiles.md, multi-profile-gateways.md isolation table,
  hermes_cli/AGENTS.md.

The fallback was added in 33bf5f62 so kanban/cron workers under a named
profile did not die with "No LLM provider configured" when the credential
lived only at root; that convenience is exactly the isolation hole the
ruling closes, and `--clone` / dashboard mirroring still copy API keys.

Tests: fallback/write-through/heal pins deleted; 4 invariants proven red on
base (profile never reads root; profile refresh never writes root; Nous
connector gate reads only the profile store; Anthropic pool never borrows or
rotates the root grant, root control still refreshes).
2026-09-16 14:34:59 -07:00
Brian Le
1a4bb74a40 feat: choose pooled credential priority from the CLI 2026-09-07 08:06:48 -07:00
Brian Le
53221df05f feat: reset one pooled credential without clearing sibling cooldowns 2026-09-07 08:06:48 -07:00
Teknium
12ad29a48a refactor: isolate credential pool administration methods 2026-09-07 08:06:48 -07:00