
























@@ -6,6 +6,7 @@ const mocks = vi.hoisted(() => ({
66ensurePluginRegistryLoaded: vi.fn(),
77resolveActivatableProviderOwnerPluginIds: vi.fn(),
88resolveBundledProviderCompatPluginIds: vi.fn(),
9+resolveManifestActivationPlan: vi.fn(),
910resolveOwningPluginIdsForProvider: vi.fn(),
1011}));
1112@@ -20,14 +21,41 @@ vi.mock("../../plugins/providers.js", () => ({
2021resolveOwningPluginIdsForProviderRef: mocks.resolveOwningPluginIdsForProvider,
2122}));
222324+vi.mock("../../plugins/activation-planner.js", () => ({
25+resolveManifestActivationPlan: mocks.resolveManifestActivationPlan,
26+}));
27+2328describe("ensureSelectedAgentHarnessPlugin", () => {
2429let ensureSelectedAgentHarnessPlugin: typeof import("./runtime-plugin.js").ensureSelectedAgentHarnessPlugin;
25302631beforeEach(async () => {
2732mocks.ensurePluginRegistryLoaded.mockReset();
2833mocks.resolveActivatableProviderOwnerPluginIds.mockReset();
2934mocks.resolveBundledProviderCompatPluginIds.mockReset();
35+mocks.resolveManifestActivationPlan.mockReset();
3036mocks.resolveOwningPluginIdsForProvider.mockReset();
37+mocks.resolveManifestActivationPlan.mockImplementation(
38+({
39+ trigger,
40+ config,
41+}: {
42+trigger: { kind: "agentHarness"; runtime: string };
43+config?: OpenClawConfig;
44+}) => {
45+const pluginId = trigger.runtime;
46+const allow = config?.plugins?.allow ?? [];
47+if (
48+config?.plugins?.entries?.[pluginId]?.enabled === false ||
49+(allow.length > 0 && !allow.includes(pluginId))
50+) {
51+return { entries: [] };
52+}
53+return {
54+entries:
55+pluginId === "codex" || pluginId === "copilot" ? [{ pluginId, origin: "bundled" }] : [],
56+};
57+},
58+);
3159mocks.resolveOwningPluginIdsForProvider.mockImplementation(
3260({ provider }: { provider: string }) => (provider === "openai" ? ["openai"] : undefined),
3361);
@@ -132,6 +160,54 @@ describe("ensureSelectedAgentHarnessPlugin", () => {
132160);
133161});
134162163+it("loads a manifest-owned custom harness runtime before selection", async () => {
164+mocks.resolveManifestActivationPlan.mockReturnValueOnce({
165+entries: [{ pluginId: "custom-harness-plugin", origin: "workspace" }],
166+});
167+168+await ensureSelectedAgentHarnessPlugin({
169+provider: "custom-provider",
170+modelId: "custom-model",
171+config: {
172+plugins: {
173+entries: {
174+"custom-harness-plugin": { enabled: true },
175+},
176+},
177+} as OpenClawConfig,
178+agentHarnessRuntimeOverride: "custom-harness",
179+workspaceDir: "/tmp/workspace",
180+});
181+182+expect(mocks.resolveManifestActivationPlan).toHaveBeenCalledWith({
183+trigger: { kind: "agentHarness", runtime: "custom-harness" },
184+config: expect.any(Object),
185+workspaceDir: "/tmp/workspace",
186+});
187+expect(mocks.ensurePluginRegistryLoaded).toHaveBeenCalledWith(
188+expect.objectContaining({
189+scope: "all",
190+workspaceDir: "/tmp/workspace",
191+onlyPluginIds: ["custom-harness-plugin", "memory-core"],
192+}),
193+);
194+});
195+196+it("does not activate an untrusted workspace harness from manifest metadata alone", async () => {
197+mocks.resolveManifestActivationPlan.mockReturnValueOnce({
198+entries: [{ pluginId: "custom-harness-plugin", origin: "workspace" }],
199+});
200+201+await ensureSelectedAgentHarnessPlugin({
202+provider: "custom-provider",
203+modelId: "custom-model",
204+agentHarnessRuntimeOverride: "custom-harness",
205+workspaceDir: "/tmp/workspace",
206+});
207+208+expect(mocks.ensurePluginRegistryLoaded).not.toHaveBeenCalled();
209+});
210+135211it("does not bypass a restrictive allowlist that omits a configured Copilot harness", async () => {
136212// A configured harness can request loading, but explicit plugin allowlists
137213// remain the operator's boundary and are not widened implicitly.
@@ -158,21 +234,7 @@ describe("ensureSelectedAgentHarnessPlugin", () => {
158234workspaceDir: "/tmp/workspace",
159235});
160236161-expect(mocks.ensurePluginRegistryLoaded).toHaveBeenCalledWith(
162-expect.objectContaining({
163-scope: "all",
164-workspaceDir: "/tmp/workspace",
165-onlyPluginIds: ["copilot"],
166-config: expect.objectContaining({
167-plugins: expect.objectContaining({
168-allow: ["telegram"],
169-entries: expect.not.objectContaining({
170-copilot: expect.anything(),
171-}),
172-}),
173-}),
174-}),
175-);
237+expect(mocks.ensurePluginRegistryLoaded).not.toHaveBeenCalled();
176238});
177239178240it("widens a scoped harness allowlist with the provider owner for openai models", async () => {
@@ -337,22 +399,7 @@ describe("ensureSelectedAgentHarnessPlugin", () => {
337399expect(mocks.resolveOwningPluginIdsForProvider).not.toHaveBeenCalled();
338400expect(mocks.resolveBundledProviderCompatPluginIds).not.toHaveBeenCalled();
339401expect(mocks.resolveActivatableProviderOwnerPluginIds).not.toHaveBeenCalled();
340-expect(mocks.ensurePluginRegistryLoaded).toHaveBeenCalledWith(
341-expect.objectContaining({
342-scope: "all",
343-workspaceDir: "/tmp/workspace",
344-onlyPluginIds: ["codex"],
345-config: expect.objectContaining({
346-plugins: expect.objectContaining({
347-allow: ["telegram"],
348-entries: expect.not.objectContaining({
349-codex: expect.anything(),
350-openai: expect.anything(),
351-}),
352-}),
353-}),
354-}),
355-);
402+expect(mocks.ensurePluginRegistryLoaded).not.toHaveBeenCalled();
356403});
357404358405it("keeps real bundled memory-core in a Codex scoped load when the provider has no owner plugin", async () => {
@@ -417,5 +464,6 @@ describe("ensureSelectedAgentHarnessPlugin", () => {
417464418465expect(mocks.ensurePluginRegistryLoaded).not.toHaveBeenCalled();
419466expect(mocks.resolveOwningPluginIdsForProvider).not.toHaveBeenCalled();
467+expect(mocks.resolveManifestActivationPlan).not.toHaveBeenCalled();
420468});
421469});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。