From cab674299aee432a58aef87f375645577fca0053 Mon Sep 17 00:00:00 2001 From: Abeautifulsnow Date: Mon, 21 Sep 2026 00:09:50 +0800 Subject: [PATCH] fix(plugins): check and update installed plugins with provenance guards --- .../components/layout/UpdateDialog.spec.ts | 27 ++ .../src/components/layout/UpdateDialog.vue | 5 +- .../plugins/PluginContributionsPanel.vue | 274 ++++++++++++++- .../PluginContributionsPanelBatch.spec.ts | 132 +++++++ .../__tests__/useComponentUpdates.spec.ts | 2 +- .../src/composables/useComponentUpdates.ts | 7 +- .../src/i18n/__tests__/backendErrors.spec.ts | 12 + apps/desktop/src/i18n/backend-errors.ts | 3 + apps/desktop/src/i18n/locales/en.ts | 24 ++ apps/desktop/src/i18n/locales/es.ts | 24 ++ apps/desktop/src/i18n/locales/it.ts | 24 ++ apps/desktop/src/i18n/locales/ja.ts | 24 ++ apps/desktop/src/i18n/locales/ko.ts | 24 ++ apps/desktop/src/i18n/locales/pt-BR.ts | 24 ++ apps/desktop/src/i18n/locales/zh-CN.ts | 24 ++ apps/desktop/src/i18n/locales/zh-TW.ts | 24 ++ apps/desktop/src/lib/plugins/pluginBatch.ts | 8 +- .../src/lib/plugins/pluginMarketplace.spec.ts | 76 +++- .../src/lib/plugins/pluginMarketplace.ts | 83 ++++- apps/desktop/src/types/database.ts | 9 + .../examples/plugin_marketplace_smoke.rs | 1 + crates/dbx-core/src/query/mod.rs | 4 + crates/dbx-core/src/schema/mod.rs | 2 + crates/dbx-plugin-runtime/src/plugins.rs | 27 +- .../src/plugins/installer.rs | 331 +++++++++++++++++- .../src/plugins/marketplace.rs | 29 +- 26 files changed, 1180 insertions(+), 44 deletions(-) diff --git a/apps/desktop/src/components/layout/UpdateDialog.spec.ts b/apps/desktop/src/components/layout/UpdateDialog.spec.ts index 1363259bf1..79b060b0c2 100644 --- a/apps/desktop/src/components/layout/UpdateDialog.spec.ts +++ b/apps/desktop/src/components/layout/UpdateDialog.spec.ts @@ -512,4 +512,31 @@ describe("UpdateDialog aggregate update center", () => { expect(installComponentUpdates).toHaveBeenCalledWith("drivers"); }); + + it("marks only a plugin whose update source changed as needing confirmation in the Plugin Center", async () => { + const listing = (id: string, provenance: Record) => ({ + key: `official:${id}`, + status: "update", + artifact: { target: "universal", url: "https://example.com/plugin.dbxp", sha256: "hash", signingKeyId: "key-a" }, + repository: { id: "official" }, + plugin: { id, latestVersion: "1.1.0", publisher: "DBX" }, + installed: { manifest: { id, version: "1.0.0" }, provenance }, + name: `${id} plugin`, + }); + await mountDialog(0, {}, undefined, { + updateInfo: null, + pluginUpdates: [listing("same", { repositoryId: "official" }), listing("moved", { repositoryId: "other-repo" })], + }); + + const pluginsTab = document.body.querySelector('[data-update-tab="plugins"]'); + pluginsTab?.click(); + await flushDialog(); + + // "Update all" skips the changed-source plugin, so the dialog has to explain why it stays. + const hint = "Confirm the change in the Plugin Center first"; + const rows = [...document.body.querySelectorAll(".rounded-md.border.p-3")]; + const rowFor = (name: string) => rows.find((row) => row.textContent?.includes(name)); + expect(rowFor("moved plugin")?.textContent).toContain(hint); + expect(rowFor("same plugin")?.textContent).not.toContain(hint); + }); }); diff --git a/apps/desktop/src/components/layout/UpdateDialog.vue b/apps/desktop/src/components/layout/UpdateDialog.vue index a98ce5a2fe..346c175e00 100644 --- a/apps/desktop/src/components/layout/UpdateDialog.vue +++ b/apps/desktop/src/components/layout/UpdateDialog.vue @@ -8,7 +8,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import type { UpdateInfo } from "@/lib/backend/api"; import type { AgentDriverInfo, McpServerStatus, UpdateDownloadSource } from "@/lib/backend/tauri"; import type { JdbcPluginStatus } from "@/types/database"; -import type { MarketplacePluginListing } from "@/lib/plugins/pluginMarketplace"; +import { pluginSourceChange, type MarketplacePluginListing } from "@/lib/plugins/pluginMarketplace"; import { mcpUpdateAvailability } from "@/lib/mcp/mcpUpdateStatus"; import { isTauriRuntime } from "@/lib/backend/tauriRuntime"; import { isUpdatePreviewMockEnabled } from "@/lib/updates/updatePreviewMock"; @@ -302,6 +302,9 @@ watch(
{{ plugin.name }}
{{ plugin.installed?.manifest.version || t("updates.notInstalled") }} → {{ plugin.plugin.latestVersion }}
+ +
{{ t("pluginPlatform.updateSourceChangeRequired") }}
{{ t("settings.updateAvailable") }} diff --git a/apps/desktop/src/components/plugins/PluginContributionsPanel.vue b/apps/desktop/src/components/plugins/PluginContributionsPanel.vue index 18160342b6..07d45f67d2 100644 --- a/apps/desktop/src/components/plugins/PluginContributionsPanel.vue +++ b/apps/desktop/src/components/plugins/PluginContributionsPanel.vue @@ -1,6 +1,6 @@