diff --git a/src/channels/plugins/catalog.test.ts b/src/channels/plugins/catalog.test.ts index d9c11823b07..d26f05d92d9 100644 --- a/src/channels/plugins/catalog.test.ts +++ b/src/channels/plugins/catalog.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { getChannelPluginCatalogEntry } from "./catalog.js"; describe("channel plugin catalog", () => { - it("keeps third-party official channel ids mapped to their published plugin ids", () => { + it("keeps third-party channel ids mapped with catalog install trust", () => { const options = { workspaceDir: "/tmp/openclaw-channel-catalog-empty-workspace", env: {}, diff --git a/src/cli/plugins-cli.install.test.ts b/src/cli/plugins-cli.install.test.ts index 68da54a32cb..c3e21744aa8 100644 --- a/src/cli/plugins-cli.install.test.ts +++ b/src/cli/plugins-cli.install.test.ts @@ -734,7 +734,7 @@ describe("plugins cli install", () => { expect(writeConfigFile).toHaveBeenCalledWith(enabledCfg); }); - it("passes official external catalog integrity to npm installs", async () => { + it("passes third-party external catalog integrity with catalog install trust", async () => { const cfg = createEmptyPluginConfig(); const enabledCfg = createEnabledPluginConfig("wecom-openclaw-plugin"); loadConfig.mockReturnValue(cfg); @@ -796,7 +796,7 @@ describe("plugins cli install", () => { }, ); - it("passes official external catalog integrity to hook-pack fallback", async () => { + it("passes third-party external catalog integrity to hook-pack fallback", async () => { loadConfig.mockReturnValue(createEmptyPluginConfig()); findBundledPluginSourceMock.mockReturnValue(undefined); installPluginFromNpmSpec.mockResolvedValue({ @@ -992,6 +992,38 @@ describe("plugins cli install", () => { expect(installPluginFromClawHub).not.toHaveBeenCalled(); }); + it("marks catalog npm package installs with alternate selectors as trusted", async () => { + const cfg = createEmptyPluginConfig(); + const enabledCfg = createEnabledPluginConfig("wecom-openclaw-plugin"); + + loadConfig.mockReturnValue(cfg); + installPluginFromNpmSpec.mockResolvedValue( + createNpmPluginInstallResult("wecom-openclaw-plugin"), + ); + enablePluginInConfig.mockReturnValue({ config: enabledCfg }); + recordPluginInstall.mockReturnValue(enabledCfg); + applyExclusiveSlotSelection.mockReturnValue({ + config: enabledCfg, + warnings: [], + }); + + await runPluginsCommand(["plugins", "install", "@wecom/wecom-openclaw-plugin@latest"]); + + expect(installPluginFromNpmSpec).toHaveBeenCalledWith( + expect.objectContaining({ + spec: "@wecom/wecom-openclaw-plugin@latest", + expectedPluginId: "wecom-openclaw-plugin", + trustedSourceLinkedOfficialInstall: true, + }), + ); + expect(installPluginFromNpmSpec).toHaveBeenCalledWith( + expect.not.objectContaining({ + expectedIntegrity: expect.any(String), + }), + ); + expect(installPluginFromClawHub).not.toHaveBeenCalled(); + }); + it("passes the active profile extensions dir to npm installs", async () => { const extensionsDir = useProfileExtensionsDir(); const cfg = createEmptyPluginConfig(); diff --git a/src/cli/plugins-install-command.ts b/src/cli/plugins-install-command.ts index ee7593898cd..796c705139e 100644 --- a/src/cli/plugins-install-command.ts +++ b/src/cli/plugins-install-command.ts @@ -64,7 +64,7 @@ function resolveInstallSafetyOverrides(overrides: InstallSafetyOverrides): Insta }; } -function findTrustedOfficialExternalPackageInstall(packageName: string): +function findTrustedCatalogPackageInstall(packageName: string): | { pluginId: string; npmSpec?: string; @@ -72,7 +72,7 @@ function findTrustedOfficialExternalPackageInstall(packageName: string): } | undefined { const entry = getOfficialExternalPluginCatalogEntryForPackage(packageName); - if (entry?.source !== "official") { + if (!entry) { return undefined; } const pluginId = resolveOfficialExternalPluginId(entry); @@ -723,7 +723,7 @@ export async function runPluginInstallCommand(params: { } const officialNpmTrust = resolveOfficialExternalNpmPackageTrust({ npmSpec: npmPrefixSpec, - findOfficialExternalPackage: findTrustedOfficialExternalPackageInstall, + findOfficialExternalPackage: findTrustedCatalogPackageInstall, }); const npmPrefixResult = await tryInstallPluginOrHookPackFromNpmSpec({ snapshot, @@ -870,7 +870,7 @@ export async function runPluginInstallCommand(params: { const officialNpmTrust = resolveOfficialExternalNpmPackageTrust({ npmSpec: raw, - findOfficialExternalPackage: findTrustedOfficialExternalPackageInstall, + findOfficialExternalPackage: findTrustedCatalogPackageInstall, }); const npmResult = await tryInstallPluginOrHookPackFromNpmSpec({ snapshot,