Summary
hermes auth remove does not fully remove manually added OAuth credentials whose source is manual:device_code / manual:hermes_pkce. After removal, the next load_pool() call re-seeds a fresh singleton OAuth entry from the underlying auth store, so the credential appears to come back immediately.
Affected files
hermes_cli/auth_commands.py:317-352
agent/credential_pool.py:1132-1190
- tests demonstrating the current failure:
tests/hermes_cli/test_auth_commands.py:239-329
Why this is a bug
auth_remove_command() only clears the underlying singleton auth source when removed.source is exactly device_code, hermes_pkce, or claude_code.
However, hermes auth add writes manual OAuth entries with prefixed sources such as:
manual:device_code (hermes_cli/auth_commands.py:224,243)
manual:hermes_pkce (hermes_cli/auth_commands.py:194)
load_pool() later re-imports singleton OAuth credentials from the auth store using the unprefixed source names (device_code, hermes_pkce), so removing a manual entry does not actually prevent the credential from returning.
Minimal reproduction / evidence
Focused tests currently fail on main:
source venv/bin/activate
pytest -q tests/hermes_cli/test_auth_commands.py -k 'auth_remove_accepts_label_target or auth_remove_prefers_exact_numeric_label_over_index' -q
Observed failures:
test_auth_remove_accepts_label_target expects 1 remaining credential but gets 2 because a fresh device_code entry is re-seeded.
test_auth_remove_prefers_exact_numeric_label_over_index expects ['first', 'third'] but gets an extra device_code entry.
Expected behavior
Removing a manually added OAuth credential should also clear or suppress the corresponding singleton credential source, so the removed credential does not reappear on the next pool load.
Actual behavior
The visible pool entry is removed, but the underlying auth store remains intact, and load_pool() silently re-seeds a new singleton OAuth credential.
Suggested investigation direction
Normalize manual:* sources before the cleanup branch in auth_remove_command(), or otherwise treat manual:device_code / manual:hermes_pkce as aliases of the singleton source they originated from.
Summary
hermes auth removedoes not fully remove manually added OAuth credentials whose source ismanual:device_code/manual:hermes_pkce. After removal, the nextload_pool()call re-seeds a fresh singleton OAuth entry from the underlying auth store, so the credential appears to come back immediately.Affected files
hermes_cli/auth_commands.py:317-352agent/credential_pool.py:1132-1190tests/hermes_cli/test_auth_commands.py:239-329Why this is a bug
auth_remove_command()only clears the underlying singleton auth source whenremoved.sourceis exactlydevice_code,hermes_pkce, orclaude_code.However,
hermes auth addwrites manual OAuth entries with prefixed sources such as:manual:device_code(hermes_cli/auth_commands.py:224,243)manual:hermes_pkce(hermes_cli/auth_commands.py:194)load_pool()later re-imports singleton OAuth credentials from the auth store using the unprefixed source names (device_code,hermes_pkce), so removing a manual entry does not actually prevent the credential from returning.Minimal reproduction / evidence
Focused tests currently fail on
main:Observed failures:
test_auth_remove_accepts_label_targetexpects 1 remaining credential but gets 2 because a freshdevice_codeentry is re-seeded.test_auth_remove_prefers_exact_numeric_label_over_indexexpects['first', 'third']but gets an extradevice_codeentry.Expected behavior
Removing a manually added OAuth credential should also clear or suppress the corresponding singleton credential source, so the removed credential does not reappear on the next pool load.
Actual behavior
The visible pool entry is removed, but the underlying auth store remains intact, and
load_pool()silently re-seeds a new singleton OAuth credential.Suggested investigation direction
Normalize
manual:*sources before the cleanup branch inauth_remove_command(), or otherwise treatmanual:device_code/manual:hermes_pkceas aliases of the singleton source they originated from.