Skip to content

feat(plugins): support plugin-owned connection fields and secrets - #629

Merged
debba merged 2 commits into
mainfrom
feat/plugin-connection-fields
Oct 18, 2026
Merged

debba merged 2 commits into
mainfrom
feat/plugin-connection-fields

Conversation

@debba

@debba debba commented Aug 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Optional per-plugin presentation overrides for the common connection fields (connection_fields: hide, relabel or set a placeholder for host, port, username, password, database).
  • Plugin-owned connection secrets stored in the OS keychain (<connectionId>:plugin:<driver>:<key>).
  • UI extensions only see secret metadata (hasStoredValue, dirty) and send tri-state changes through setSecretField; stored values are never returned to the frontend.
  • Secrets are hydrated into params.extra[key] only for runtime driver calls and never written to connections.json or config.json.
  • The secret lifecycle is preserved across save, update, test, Load Databases, duplicate, delete, import, export, scheduled backups and MCP.

Update

The branch was rebuilt on top of current main (it was 816 commits behind). Besides resolving the conflicts:

  • Call sites added on main since the original PR: Load Databases resolves stored and pending secrets like Test Connection; scheduled backups carry plugin secrets like passwords; re-importing a metadata-only export over the same connection keeps stored secrets; disconnect still closes pools when a secret cannot be read; MCP reads secrets in spawn_blocking.
  • Missing secrets no longer break a connection: a key missing from the keychain (connections file copied to another machine, keychain reset, downgrade) or an unreadable keychain is logged by key name and left unset, so the plugin reports the missing credential instead of every call failing. Runtime, export, backup and duplicate share one tolerant path.
  • Import: invalid keys or oversized values in an untrusted payload are skipped with a warning; keychain writes happen only after connections.json is saved, so a failed save leaves no orphaned secrets.
  • Docs: PLUGIN_GUIDE.md documents the contract and the downgrade behaviour (an older version that rewrites connections.json drops plugin_secret_keys; setting the secret again restores it).
  • connection_fields is added to plugins/tabularium-extensions.schema.json. The Tabularium driver kind already accepts it.

Compatibility

All new manifest, model, request and UI context fields are optional or defaulted. Existing manifests, saved connections, UI extensions and Password-based plugins keep their behaviour. Verified by loading every local plugin manifest with the old and new host, and by reading connections.json, export payloads and backups written by main (identical result) and the reverse (no crash, other data preserved).

Dependent plugin PR: TabularisDB/tabularis-bigquery-plugin#2

Tests

  • plugin_secrets_tests.rs, persistence_tests.rs, NewConnectionModal.test.tsx, schema contract test.
  • cargo test --all-targets, pnpm build, vitest, pnpm lint, plugin-api build and check:sync pass.

Comment thread src-tauri/src/mcp/mod.rs Outdated

if !conn.plugin_secret_keys.is_empty() {
let cache = credential_cache::CredentialCache::default();
crate::plugin_secrets::hydrate_connection(&cache, &mut conn).map_err(|message| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Plugin secret hydration runs blocking keychain I/O on the async runtime thread.

The adjacent DB-password (line 255) and connection-URI (line 286) reads in this same function both wrap their keychain access in tokio::task::spawn_blocking. hydrate_connection → get_plugin_secret_cached → keychain_utils::get_plugin_secret performs synchronous keychain reads directly on the async worker thread, which can stall the MCP server's runtime — notably on platforms where keychain access is slow or requires an unlock prompt. Mirror the surrounding pattern and move the hydration into spawn_blocking (one read per secret key, like the URI path does).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

The previous WARNING (blocking keychain I/O during plugin secret hydration in src-tauri/src/mcp/mod.rs) is resolved: hydration now runs inside tokio::task::spawn_blocking. The new commit (fix(plugins): tolerate missing plugin secrets) makes secret hydration lenient (missing or unreadable keys are logged by name only and left unset), routes export, duplicate and driver calls through one shared read path, and defers imported secret keychain writes until connections.json is saved. I found no bugs, secret leaks or regressions in the changed code.

Files Reviewed (7 files in the latest commit)
  • plugins/PLUGIN_GUIDE.md
  • src-tauri/src/commands.rs
  • src-tauri/src/credential_cache.rs
  • src-tauri/src/mcp/mod.rs
  • src-tauri/src/plugin_secrets.rs
  • src-tauri/src/plugin_secrets_tests.rs
  • src-tauri/src/plugins/tests.rs
Previous Review Summary (commit d7cb728)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit d7cb728)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src-tauri/src/mcp/mod.rs 302 Plugin secret hydration performs blocking keychain I/O on the async runtime thread; adjacent password/URI reads use spawn_blocking.
Files Reviewed (38 files)
  • packages/create-plugin/src/cli.ts - 0 issues
  • packages/plugin-api/README.md - 0 issues
  • packages/plugin-api/package.json - 0 issues
  • packages/plugin-api/src/slots.ts - 0 issues
  • packages/plugin-api/src/version.ts - 0 issues
  • plugins/PLUGIN_GUIDE.md - 0 issues
  • plugins/manifest.schema.json - 0 issues
  • src-tauri/src/commands.rs - 0 issues
  • src-tauri/src/connection_cache_tests.rs - 0 issues
  • src-tauri/src/connection_import/analyzer.rs - 0 issues
  • src-tauri/src/connection_import/convert.rs - 0 issues
  • src-tauri/src/connection_import/tabularis.rs - 0 issues
  • src-tauri/src/connection_tags.rs - 0 issues
  • src-tauri/src/credential_cache.rs - 0 issues
  • src-tauri/src/drivers/driver_trait.rs - 0 issues
  • src-tauri/src/drivers/mysql/mod.rs - 0 issues
  • src-tauri/src/drivers/postgres/mod.rs - 0 issues
  • src-tauri/src/drivers/sqlite/mod.rs - 0 issues
  • src-tauri/src/export_import_tests.rs - 0 issues
  • src-tauri/src/keychain_utils.rs - 0 issues
  • src-tauri/src/lib.rs - 0 issues
  • src-tauri/src/mcp/mod.rs - 1 issue
  • src-tauri/src/models.rs - 0 issues
  • src-tauri/src/models_tests.rs - 0 issues
  • src-tauri/src/persistence.rs - 0 issues
  • src-tauri/src/plugin_secrets.rs - 0 issues
  • src-tauri/src/plugins/commands.rs - 0 issues
  • src-tauri/src/plugins/driver.rs - 0 issues
  • src-tauri/src/plugins/manager.rs - 0 issues
  • src-tauri/src/plugins/tests.rs - 0 issues
  • src-tauri/src/sqlite_database.rs - 0 issues
  • src/components/modals/NewConnectionModal.tsx - 0 issues
  • src/contexts/DatabaseContext.ts - 0 issues
  • src/contexts/PluginSlotProvider.tsx - 0 issues
  • src/types/pluginSlots.ts - 0 issues
  • src/types/plugins.ts - 0 issues
  • src/utils/credentials.ts - 0 issues
  • tests/components/modals/NewConnectionModal.test.tsx - 0 issues

Fix these issues in Kilo Cloud


Reviewed by claude-sonnet-5.5 · Input: 252 · Output: 2.2K · Cached: 383.1K

Review guidance: REVIEW.md from base branch main

@debba

debba commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

@NewtTheWolf please can you check the tabularium part?

@NewtTheWolf

Copy link
Copy Markdown
Collaborator

I also checked the live Tabularium registry schema: connection_fields is still not present in the driver kind schema there. Please add it on the Tabularium side too, otherwise plugins using this field still cannot be published even though the Tabularis host side is ready.

debba added 2 commits October 18, 2026 10:39
Driver plugins can now adapt the host connection inputs and keep their
own credentials in the OS keychain.

- Manifest `connection_fields`: optional hidden/label/placeholder
  overrides for host, port, username, password and database. A hidden
  database input is no longer required, and hiding host also hides the
  Load databases action. Declared in manifest.schema.json and in the
  Tabularium extension schema.
- `connection-modal.extra_fields` slot: optional `secretFields` (metadata
  only: value typed in this session, hasStoredValue, dirty) and
  `setSecretField(key, value)`; an empty value clears the secret.
- Secrets are stored under `<id>:plugin:<driver>:<key>` and only their
  names are persisted (`plugin_secret_keys`). They are resolved into
  `params.extra[key]` in memory for every driver call, Test Connection,
  Load Databases and the MCP server, and never written to
  connections.json or returned to the frontend.
- Lifecycle: save, update (driver switch drops the old secrets), duplicate,
  delete, group delete, export with credentials and backups, import (a
  metadata-only re-import keeps the stored secrets).
- Disconnect and export no longer fail when a stored plugin secret
  cannot be read.
- PLUGIN_GUIDE documents both contracts; @tabularis/plugin-api exposes
  the typed slot context and `PluginSecretFieldState`.

Existing manifests, saved connections and UI extensions keep their
behaviour: every new field is optional.
A plugin secret listed in `plugin_secret_keys` but missing from the OS
keychain (synced connections file, keychain reset, downgrade) made every
driver call of the connection fail, along with DDL, dump, MCP and
duplicate.

- Hydration is lenient everywhere: an invalid, missing or unreadable key
  (including a locked keychain or denied access) is logged by name, never
  by value, and left unset so the plugin reports the missing credential.
  Driver calls, Test Connection, Load Databases, export, backups and
  duplicate share one read path.
- Duplicate copies only the values that can be read and lists only those
  keys on the copy.
- Import skips invalid secret keys and oversized values with a warning
  instead of rejecting the payload, and writes plugin secrets to the
  keychain only after connections.json has been saved, so a failed save
  leaves no orphaned entries.
- PLUGIN_GUIDE documents the unset-secret behaviour and what happens
  after a downgrade drops `plugin_secret_keys`.
@debba
debba force-pushed the feat/plugin-connection-fields branch from d7cb728 to 02d65fb Compare October 18, 2026 11:02
@github-actions

Copy link
Copy Markdown
Contributor

Preview build

The preview build of commit 02d65fb failed (skipped). See the workflow run for logs.

@debba debba changed the title feat: support plugin-owned connection fields and secrets feat(plugins): support plugin-owned connection fields and secrets Oct 18, 2026
@debba
debba merged commit 6b28df2 into main Oct 18, 2026
13 checks passed
@debba
debba deleted the feat/plugin-connection-fields branch October 18, 2026 15:09
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.

2 participants