6.2 KiB
Local credential parity: aliases, identity, status, and credential tester integration
Summary
Gives local API key credentials (Brave Search, GitHub, Exa, Stripe, etc.) the same feature set as Aden OAuth credentials: named aliases, identity metadata, status tracking, CRUD management, and full visibility in the credential tester.
Fixes a bug where credentials configured with the existing store_credential MCP tool were invisible in the credential tester account picker.
Changes
New: core/framework/credentials/local/
models.py — LocalAccountInfo dataclass mirroring AdenIntegrationInfo:
- Fields:
credential_id,alias,status(active/failed/unknown),identity,last_validated,created_at storage_idproperty returns"{credential_id}/{alias}"(e.g.brave_search/work)to_account_dict()returns same shape as Aden account dicts — feeds account picker without changes
registry.py — LocalCredentialRegistry, the core engine:
save_account(credential_id, alias, api_key)— runs health check, extracts identity, stores at{credential_id}/{alias}inEncryptedFileStoragelist_accounts(credential_id=None)— reads all{x}/{y}entries from storageget_key(credential_id, alias)— returns raw secretdelete_account(credential_id, alias)— removes entryvalidate_account(credential_id, alias)— re-runs health check, updates_statusandlast_refreshedin-placedefault()classmethod — uses~/.hive/credentials
Storage convention: {credential_id}/{alias} as CredentialObject.id. Legacy flat entries (brave_search, no slash) continue to work — env var fallback is unchanged.
Modified: tools/src/aden_tools/credentials/store_adapter.py
get(name, account=None)— addedaccount=param for per-call routing to a named local account; mirrors Adenaccount=routingactivate_local_account(credential_id, alias)— injects a named account's key intoos.environ[spec.env_var]for session-level activationlist_local_accounts(credential_id=None)— delegates toLocalCredentialRegistry
Modified: core/framework/credentials/__init__.py
Exports LocalAccountInfo and LocalCredentialRegistry.
Modified: core/framework/agents/credential_tester/agent.py
Full rewrite of account listing and configuration:
_list_aden_accounts()— extracted from oldlist_connected_accounts()_list_local_accounts()— usesLocalCredentialRegistry_list_env_fallback_accounts()— detects credentials configured via env var or in old flat encrypted format; fixes the invisible-credential buglist_connected_accounts()— combines all three, deduplicatesconfigure_for_account()— branches onsourcefield:"aden"→ addsget_account_infotool, prompts withaccount="alias""local"→ calls_activate_local_account(), prompt has noaccount=param
_activate_local_account()— handles three cases: named registry entry, old flat encrypted entry, env var already set; also handles grouped credentials (e.g.google_custom_searchsets bothGOOGLE_API_KEYandGOOGLE_CSE_ID)get_tools_for_provider()— fixed to match bothcredential_idANDcredential_group
Modified: core/framework/builder/package_generator.py
store_credential(name, value, alias="default", ...)— addedaliasparam; now delegates toLocalCredentialRegistry.save_account()with auto health check; returnsstatusandidentitylist_stored_credentials()— delegates toLocalCredentialRegistry.list_accounts(); returnscredential_id,alias,status,identity,last_validateddelete_stored_credential(name, alias="default")— addedaliasparamvalidate_credential(name, alias="default")— new tool — re-runs health check viaLocalCredentialRegistry.validate_account(), returns updated status and identity
Modified: core/framework/tui/screens/account_selection.py
- Aden accounts rendered first, local accounts second
- Local accounts display a
[local]badge - Identity label shows email, username, or workspace when available
New: core/framework/tui/screens/add_local_credential.py
Two-phase modal for adding a named local API key:
- Type selection — filtered list of all
direct_api_key_supported=Truecredentials - Form — alias input + password input → "Test & Save" runs health check inline, shows identity result, auto-dismisses on success
Exported from core/framework/tui/screens/__init__.py.
Bug fix
Credential tester not showing configured credentials (e.g. Brave Search stored via store_credential):
_list_env_fallback_accounts()previously usedCredentialStoreAdapter.with_env_storage(), which only checkedos.environ. Credentials stored inEncryptedFileStoragewith the old flat format (brave_search, no slash) were invisible._activate_local_account()early-returned whenalias == "default", assuming the env var was already set. Old flat encrypted credentials are not inos.environ.
Fix: _list_env_fallback_accounts() now also reads EncryptedFileStorage.list_all() and treats any flat entry (no /) as configured. _activate_local_account() now falls through to load from the flat encrypted entry when the env var is not set and the registry has no named entry.
Test plan
store_credential("brave_search", "BSA-xxx", alias="work")→ health check runs, identity shown, stored asbrave_search/worklist_stored_credentials()→ showscredential_id,alias,status,identity,last_validatedvalidate_credential("brave_search", "work")→ re-runs health check, updates statusdelete_stored_credential("brave_search", alias="work")→ removes entry- Credential tester account picker shows local accounts with
[local]badge alongside Aden accounts - Selecting a local account activates the key and tools work without
account=param - Selecting a legacy flat credential (stored before this PR) activates it correctly
AddLocalCredentialScreen— select type, enter alias + key, health check runs inline, screen closes on successCredentialStoreAdapter.get("brave_search", account="work")returns key from registry