Skip to content

feat(keychain): refactor credential management and enhance API key retrieval#54

Merged
cooper (czxtm) merged 3 commits intomainfrom
scott/keychain
Apr 29, 2026
Merged

feat(keychain): refactor credential management and enhance API key retrieval#54
cooper (czxtm) merged 3 commits intomainfrom
scott/keychain

Conversation

@scottmcmaster
Copy link
Copy Markdown
Contributor

@scottmcmaster Scott McMaster (scottmcmaster) commented Apr 26, 2026

Summary

Refactor credential management by introducing a new credential_store module that enhances API key retrieval with environment variable precedence for better local-dev and CI experience. Migrate from keyring to tauri-plugin-keyring for improved password management and error handling, i.e. no longer store plaintext API keys in settings.json. Migrate legacy settings API keys to the Keychain.

Also fixes another issue I found where vLLM API key errors throw back 500's instead of 400's which cause us to do a misleading error message.

For local development
Keychain access control is based on application identity, which for a production build is app identity and signing.

But for local dev, you're always rebuilding and not signing and therefore your keychain access needs to be refreshed all the time. If you prefer to not have to frequently type your password, then you can set one of the environment variables:

VLLM_API_KEY or OPENROUTER_API_KEY or OPENAI_API_KEY as appropriate

and those take priority so that we can skip keychain access. Note that we previously supported env vars (albeit via some code that was badly in need of refactoring) but they were the last priority location for API keys. Now they are the first priority.

Test Plan

Added unit tests for new functionality, and ran through manual tests of various scenarios including:

  1. Env var skips keychain for local-dev/CI support.
  2. No env var prompts (once) for keychain access and Always Allow, then you aren't prompted again and the secrets get stored there.
  3. Insert plain-text secret in settings.json and verify it gets migrated on startup.

Docs

  • Docs updated
  • No docs update needed

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

Warnings
⚠️ Please assign this PR to someone (usually yourself).
⚠️ ❗ Big PR (779 lines changed). Consider splitting it into smaller, focused changes.
Messages
📖 No docs update needed — acknowledged.

📋 PR Overview

Lines changed 779 (+688 / -91)
Files 1 added, 9 modified, 0 deleted
Draft / WIP no
Has Test Plan yes
New UI components no
New Storybook stories no
New Rust modules yes (1)
New TS source files no
New tests no
package.json touched no
Cargo.toml touched yes
Infra / CI touched no

Generated by 🚫 dangerJS against 0be60f2

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors native credential handling to move API keys out of settings.json and into an OS keychain-backed store, while adding env-var-first resolution to improve local dev and CI workflows.

Changes:

  • Introduces a credential_store abstraction with lazy migration/cleanup from legacy plaintext settings into the keychain.
  • Updates provider construction (summary + evolve paths) to use “effective” credentials with environment-variable precedence.
  • Enhances provider error classification by normalizing certain misleading 5xx auth-like failures to 401.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
apps/native/src-tauri/src/store.rs Adds env-first “effective” credential getters and keychain-backed secret preference helpers with lazy migration.
apps/native/src-tauri/src/credential_store.rs New module implementing keychain + legacy settings stores and migration/cleanup helpers.
apps/native/src-tauri/src/providers/mod.rs Switches provider creation to use effective credentials and centralized base URL constants.
apps/native/src-tauri/src/evolve/mod.rs Uses effective credentials for evolve provider selection and removes duplicated base URL constants.
apps/native/src-tauri/src/commands.rs Updates UI prefs retrieval to use effective (env-first) API key getters.
apps/native/src-tauri/src/provider_errors.rs Adds status normalization to remap auth-like 5xx responses to 401, with tests.
apps/native/src-tauri/src/main.rs Initializes tauri-plugin-keyring in both CLI and GUI modes.
apps/native/src-tauri/capabilities/default.json Grants keyring permissions (get/set/delete/ping).
apps/native/src-tauri/Cargo.toml Adds tauri-plugin-keyring dependency.
Cargo.lock Locks transitive deps introduced by tauri-plugin-keyring.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/native/src-tauri/src/store.rs Outdated
Comment thread apps/native/src-tauri/src/store.rs
Comment thread apps/native/src-tauri/src/credential_store.rs Outdated
Comment thread apps/native/src-tauri/src/providers/mod.rs Outdated
Copy link
Copy Markdown
Contributor

@CasLinden Cas Linden (CasLinden) left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have comments on the code but I pulled this and tested this:

  • Plant dummy key in settings.json

  • Migration put it in keychain.

  • Then I tried to set a different dummy key and validation was rejected.

  • A free openrouter key was accepted,

  • The free model failed but tried an evolve

  • Couldn't verify the free key in keychain (security thing doing its job?)

  • I could however verify the dummy key (from the migration) in keychain. And this also passed the validation, unlike if I had put it into the input. But I am not sure if that is important.

Copy link
Copy Markdown
Contributor

cooper (czxtm) commented Apr 29, 2026

Merge activity

  • Apr 29, 12:46 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 29, 12:47 AM UTC: Graphite rebased this pull request as part of a merge.
  • Apr 29, 12:56 AM UTC: cooper (@czxtm) merged this pull request with Graphite.

- Added a new `credential_store` module to handle API key storage and retrieval.
- Introduced functions to get effective API keys with environment variable precedence for OpenRouter, OpenAI, and vLLM.
- Updated existing functions in `store.rs` to utilize the new credential management system.
- Refactored `generate_evolution` and `create_provider` functions to use the new API key retrieval methods.
- Removed legacy API key retrieval logic and constants for OpenRouter and OpenAI from various modules.
- Improved error handling and logging for credential access and migration.

Co-authored-by: Copilot <copilot@github.com>
… management

- Updated Cargo.toml to replace `keyring` with `tauri-plugin-keyring`.
- Modified default.json to include keyring capabilities for password management.
- Refactored credential_store.rs to utilize tauri-plugin-keyring for getting, setting, and deleting passwords.
- Enhanced main.rs to initialize tauri-plugin-keyring in both CLI and GUI modes.
- Improved error handling in provider_errors.rs to remap misleading 500 errors to 401 for authentication issues.
- Simplified store.rs to resolve secrets with environment variable overrides, ensuring smoother integration with keychain.
- Added tests for new functionality and ensured existing tests are updated accordingly.

Co-authored-by: Copilot <copilot@github.com>
…alues in credential management per AI code review comments

Co-authored-by: Copilot <copilot@github.com>
@czxtm cooper (czxtm) merged commit 0796f1d into main Apr 29, 2026
2 of 3 checks passed
@scottmcmaster Scott McMaster (scottmcmaster) deleted the scott/keychain branch April 29, 2026 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants