mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:30:44 +00:00
fix(doctor): repair allow-only official plugins
This commit is contained in:
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
detectPluginAutoEnableCandidates: vi.fn(),
|
||||
getOfficialExternalPluginCatalogEntry: vi.fn(),
|
||||
repairMissingPluginInstallsForIds: vi.fn(),
|
||||
resolveProviderInstallCatalogEntries: vi.fn(),
|
||||
}));
|
||||
@@ -14,6 +15,14 @@ vi.mock("../../../plugins/provider-install-catalog.js", () => ({
|
||||
resolveProviderInstallCatalogEntries: mocks.resolveProviderInstallCatalogEntries,
|
||||
}));
|
||||
|
||||
vi.mock(import("../../../plugins/official-external-plugin-catalog.js"), async (importOriginal) => {
|
||||
const actual = await importOriginal();
|
||||
return {
|
||||
...actual,
|
||||
getOfficialExternalPluginCatalogEntry: mocks.getOfficialExternalPluginCatalogEntry,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./missing-configured-plugin-install.js", () => ({
|
||||
repairMissingPluginInstallsForIds: mocks.repairMissingPluginInstallsForIds,
|
||||
}));
|
||||
@@ -22,6 +31,7 @@ describe("configured plugin install release step", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.detectPluginAutoEnableCandidates.mockReturnValue([]);
|
||||
mocks.getOfficialExternalPluginCatalogEntry.mockReturnValue(undefined);
|
||||
mocks.resolveProviderInstallCatalogEntries.mockReturnValue([]);
|
||||
mocks.repairMissingPluginInstallsForIds.mockResolvedValue({
|
||||
changes: [],
|
||||
@@ -372,4 +382,53 @@ describe("configured plugin install release step", () => {
|
||||
touchedConfig: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("includes allow-only official plugin ids in the repair set", async () => {
|
||||
mocks.getOfficialExternalPluginCatalogEntry.mockImplementation((pluginId: string) => {
|
||||
if (pluginId === "lobster") {
|
||||
return { name: "@openclaw/lobster" };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const { collectReleaseConfiguredPluginIds } =
|
||||
await import("./release-configured-plugin-installs.js");
|
||||
const result = collectReleaseConfiguredPluginIds({
|
||||
cfg: {
|
||||
plugins: {
|
||||
allow: ["lobster", "unofficial-custom"],
|
||||
},
|
||||
},
|
||||
env: {},
|
||||
});
|
||||
|
||||
expect(result.pluginIds).toEqual(["lobster"]);
|
||||
expect(result.channelIds).toEqual([]);
|
||||
});
|
||||
|
||||
it("skips allow-only plugin ids that already have material plugin entries", async () => {
|
||||
mocks.getOfficialExternalPluginCatalogEntry.mockImplementation((pluginId: string) => {
|
||||
if (pluginId === "lobster") {
|
||||
return { name: "@openclaw/lobster" };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const { collectReleaseConfiguredPluginIds } =
|
||||
await import("./release-configured-plugin-installs.js");
|
||||
const result = collectReleaseConfiguredPluginIds({
|
||||
cfg: {
|
||||
plugins: {
|
||||
allow: ["lobster"],
|
||||
entries: {
|
||||
lobster: { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
env: {},
|
||||
});
|
||||
|
||||
expect(result.pluginIds).toEqual(["lobster"]);
|
||||
expect(mocks.getOfficialExternalPluginCatalogEntry).not.toHaveBeenCalledWith("lobster");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { detectPluginAutoEnableCandidates } from "../../../config/plugin-auto-en
|
||||
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
|
||||
import { compareOpenClawVersions } from "../../../config/version.js";
|
||||
import { isTruthyEnvValue } from "../../../infra/env.js";
|
||||
import { getOfficialExternalPluginCatalogEntry } from "../../../plugins/official-external-plugin-catalog.js";
|
||||
import { resolveProviderInstallCatalogEntries } from "../../../plugins/provider-install-catalog.js";
|
||||
import { resolveWebSearchInstallCatalogEntry } from "../../../plugins/web-search-install-catalog.js";
|
||||
import { VERSION } from "../../../version.js";
|
||||
@@ -214,6 +215,27 @@ function collectAcpRuntimePluginIds(cfg: OpenClawConfig): string[] {
|
||||
return ["acpx"];
|
||||
}
|
||||
|
||||
function collectAllowOnlyOfficialPluginIds(cfg: OpenClawConfig): string[] {
|
||||
const allow = cfg.plugins?.allow;
|
||||
if (!Array.isArray(allow) || allow.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const materialEntryIds = new Set(
|
||||
collectMaterialPluginEntryIds(cfg).map((id) => id.toLowerCase()),
|
||||
);
|
||||
const ids: string[] = [];
|
||||
for (const rawPluginId of allow) {
|
||||
const pluginId = normalizeId(rawPluginId);
|
||||
if (!pluginId || materialEntryIds.has(pluginId.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
if (getOfficialExternalPluginCatalogEntry(pluginId)) {
|
||||
ids.push(pluginId);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
function addEligiblePluginId(cfg: OpenClawConfig, pluginIds: Set<string>, pluginId: string): void {
|
||||
const normalized = pluginId.trim();
|
||||
if (!normalized || isDenied(cfg, normalized) || isDisabled(cfg, normalized)) {
|
||||
@@ -274,6 +296,9 @@ export function collectReleaseConfiguredPluginIds(params: {
|
||||
for (const pluginId of collectAcpRuntimePluginIds(params.cfg)) {
|
||||
addEligiblePluginId(params.cfg, pluginIds, pluginId);
|
||||
}
|
||||
for (const pluginId of collectAllowOnlyOfficialPluginIds(params.cfg)) {
|
||||
addEligiblePluginId(params.cfg, pluginIds, pluginId);
|
||||
}
|
||||
for (const channelId of collectConfiguredChannelIds(params.cfg, env)) {
|
||||
if (
|
||||
!isChannelDisabled(params.cfg, channelId) &&
|
||||
|
||||
Reference in New Issue
Block a user