mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:50:43 +00:00
fix(plugins): isolate legacy runtime stores
This commit is contained in:
@@ -40,7 +40,7 @@ describe("createPluginRuntimeStore", () => {
|
||||
expect(rightStore.tryGetRuntime()).toBeNull();
|
||||
});
|
||||
|
||||
test("keeps legacy string callers working", () => {
|
||||
test("keeps legacy string callers isolated per store", () => {
|
||||
const firstStore = createPluginRuntimeStore<{ value: string }>(
|
||||
"legacy runtime not initialized",
|
||||
);
|
||||
@@ -51,7 +51,8 @@ describe("createPluginRuntimeStore", () => {
|
||||
firstStore.clearRuntime();
|
||||
firstStore.setRuntime({ value: "legacy" });
|
||||
|
||||
expect(secondStore.getRuntime()).toEqual({ value: "legacy" });
|
||||
expect(firstStore.getRuntime()).toEqual({ value: "legacy" });
|
||||
expect(secondStore.tryGetRuntime()).toBeNull();
|
||||
});
|
||||
|
||||
test("still supports explicit custom store keys", () => {
|
||||
|
||||
@@ -64,12 +64,18 @@ export function createPluginRuntimeStore<T>(options: string | PluginRuntimeStore
|
||||
getRuntime: () => T;
|
||||
} {
|
||||
const resolved = resolvePluginRuntimeStoreOptions(options);
|
||||
const registry = getPluginRuntimeStoreRegistry();
|
||||
let slot = registry.get(resolved.key);
|
||||
if (!slot) {
|
||||
slot = { runtime: null };
|
||||
registry.set(resolved.key, slot);
|
||||
}
|
||||
const slot =
|
||||
typeof options === "string"
|
||||
? { runtime: null }
|
||||
: (() => {
|
||||
const registry = getPluginRuntimeStoreRegistry();
|
||||
let existingSlot = registry.get(resolved.key);
|
||||
if (!existingSlot) {
|
||||
existingSlot = { runtime: null };
|
||||
registry.set(resolved.key, existingSlot);
|
||||
}
|
||||
return existingSlot;
|
||||
})();
|
||||
|
||||
return {
|
||||
setRuntime(next: T) {
|
||||
|
||||
@@ -523,6 +523,7 @@ function createSetupEntryChannelPluginFixture(params: {
|
||||
configured: boolean;
|
||||
startupDeferConfiguredChannelFullLoadUntilAfterListen?: boolean;
|
||||
useBundledFullEntryContract?: boolean;
|
||||
bundledFullEntryId?: string;
|
||||
useBundledSetupEntryContract?: boolean;
|
||||
splitBundledSetupSecrets?: boolean;
|
||||
bundledSetupRuntimeMarker?: string;
|
||||
@@ -580,7 +581,7 @@ function createSetupEntryChannelPluginFixture(params: {
|
||||
? `require("node:fs").writeFileSync(${JSON.stringify(fullMarker)}, "loaded", "utf-8");
|
||||
module.exports = {
|
||||
kind: "bundled-channel-entry",
|
||||
id: ${JSON.stringify(params.id)},
|
||||
id: ${JSON.stringify(params.bundledFullEntryId ?? params.id)},
|
||||
name: ${JSON.stringify(params.label)},
|
||||
description: ${JSON.stringify(params.fullBlurb)},
|
||||
loadChannelPlugin: () => {
|
||||
@@ -592,12 +593,12 @@ module.exports = {
|
||||
: ""
|
||||
}
|
||||
return {
|
||||
id: ${JSON.stringify(params.id)},
|
||||
id: ${JSON.stringify(params.bundledFullEntryId ?? params.id)},
|
||||
meta: {
|
||||
id: ${JSON.stringify(params.id)},
|
||||
id: ${JSON.stringify(params.bundledFullEntryId ?? params.id)},
|
||||
label: ${JSON.stringify(params.label)},
|
||||
selectionLabel: ${JSON.stringify(params.label)},
|
||||
docsPath: ${JSON.stringify(`/channels/${params.id}`)},
|
||||
docsPath: ${JSON.stringify(`/channels/${params.bundledFullEntryId ?? params.id}`)},
|
||||
blurb: ${JSON.stringify(params.fullBlurb)},
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"] },
|
||||
@@ -3589,6 +3590,39 @@ module.exports = {
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects mismatched bundled runtime plugin ids during setup-runtime merge", () => {
|
||||
const built = createSetupEntryChannelPluginFixture({
|
||||
id: "setup-runtime-mismatch-test",
|
||||
bundledFullEntryId: "wrong-runtime-id",
|
||||
label: "Setup Runtime Mismatch Test",
|
||||
packageName: "@openclaw/setup-runtime-mismatch-test",
|
||||
fullBlurb: "full runtime plugin",
|
||||
setupBlurb: "setup runtime override",
|
||||
configured: false,
|
||||
useBundledFullEntryContract: true,
|
||||
useBundledSetupEntryContract: true,
|
||||
bundledFullRuntimeMarker: path.join(makeTempDir(), "setup-runtime-mismatch.txt"),
|
||||
});
|
||||
|
||||
const registry = loadOpenClawPlugins({
|
||||
cache: false,
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [built.pluginDir] },
|
||||
allow: ["setup-runtime-mismatch-test"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
registry.plugins.find((entry) => entry.id === "setup-runtime-mismatch-test")?.status,
|
||||
).toBe("error");
|
||||
expect(
|
||||
registry.plugins.find((entry) => entry.id === "setup-runtime-mismatch-test")?.error,
|
||||
).toContain('runtime export uses "wrong-runtime-id"');
|
||||
expect(registry.channels).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("isolates loadSetupPlugin errors as per-plugin diagnostics instead of crashing registry load", () => {
|
||||
useNoBundledPlugins();
|
||||
const pluginDir = makeTempDir();
|
||||
|
||||
@@ -1889,6 +1889,15 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
continue;
|
||||
}
|
||||
if (runtimePluginRegistration.plugin) {
|
||||
if (
|
||||
runtimePluginRegistration.plugin.id &&
|
||||
runtimePluginRegistration.plugin.id !== record.id
|
||||
) {
|
||||
pushPluginLoadError(
|
||||
`plugin id mismatch (config uses "${record.id}", runtime export uses "${runtimePluginRegistration.plugin.id}")`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
mergedSetupRegistration = {
|
||||
...setupRegistration,
|
||||
plugin: mergeSetupRuntimeChannelPlugin(
|
||||
|
||||
Reference in New Issue
Block a user