




















@@ -4,6 +4,11 @@ import path from "node:path";
44import { installedPluginRoot } from "openclaw/plugin-sdk/test-fixtures";
55import { afterEach, beforeEach, describe, expect, it } from "vitest";
66import type { OpenClawConfig } from "../config/config.js";
7+import {
8+listOfficialExternalPluginCatalogEntries,
9+resolveOfficialExternalPluginId,
10+resolveOfficialExternalPluginInstall,
11+} from "../plugins/official-external-plugin-catalog.js";
712import {
813applyExclusiveSlotSelection,
914buildPluginSnapshotReport,
@@ -35,6 +40,19 @@ const CLI_STATE_ROOT = "/tmp/openclaw-state";
3540const ORIGINAL_OPENCLAW_STATE_DIR = process.env.OPENCLAW_STATE_DIR;
3641const PROFILE_STATE_ROOT = "/tmp/openclaw-ledger-profile";
374243+const OFFICIAL_EXTERNAL_NPM_INSTALLS_WITHOUT_INTEGRITY = listOfficialExternalPluginCatalogEntries()
44+.map((entry) => {
45+const pluginId = resolveOfficialExternalPluginId(entry);
46+const install = resolveOfficialExternalPluginInstall(entry);
47+const npmSpec = install?.npmSpec?.trim();
48+if (!pluginId || !npmSpec || install?.expectedIntegrity) {
49+return null;
50+}
51+return { pluginId, npmSpec };
52+})
53+.filter((entry): entry is { pluginId: string; npmSpec: string } => Boolean(entry))
54+.toSorted((left, right) => left.pluginId.localeCompare(right.pluginId));
55+3856function cliInstallPath(pluginId: string): string {
3957return installedPluginRoot(CLI_STATE_ROOT, pluginId);
4058}
@@ -714,6 +732,41 @@ describe("plugins cli install", () => {
714732);
715733});
716734735+it.each(OFFICIAL_EXTERNAL_NPM_INSTALLS_WITHOUT_INTEGRITY)(
736+"keeps official external npm installs trusted without integrity for $pluginId",
737+async ({ pluginId, npmSpec }) => {
738+const cfg = createEmptyPluginConfig();
739+const enabledCfg = createEnabledPluginConfig(pluginId);
740+loadConfig.mockReturnValue(cfg);
741+findBundledPluginSourceMock.mockReturnValue(undefined);
742+installPluginFromNpmSpec.mockResolvedValue(createNpmPluginInstallResult(pluginId));
743+enablePluginInConfig.mockReturnValue({ config: enabledCfg });
744+applyExclusiveSlotSelection.mockReturnValue({
745+config: enabledCfg,
746+warnings: [],
747+});
748+749+await runPluginsCommand(["plugins", "install", pluginId]);
750+751+expect(findBundledPluginSourceMock).toHaveBeenCalledWith({
752+lookup: { kind: "pluginId", value: pluginId },
753+});
754+expect(installPluginFromClawHub).not.toHaveBeenCalled();
755+expect(installPluginFromNpmSpec).toHaveBeenCalledWith(
756+expect.objectContaining({
757+spec: npmSpec,
758+expectedPluginId: pluginId,
759+trustedSourceLinkedOfficialInstall: true,
760+}),
761+);
762+expect(installPluginFromNpmSpec).toHaveBeenCalledWith(
763+expect.not.objectContaining({
764+expectedIntegrity: expect.any(String),
765+}),
766+);
767+},
768+);
769+717770it("passes official external catalog integrity to hook-pack fallback", async () => {
718771loadConfig.mockReturnValue(createEmptyPluginConfig());
719772findBundledPluginSourceMock.mockReturnValue(undefined);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。