openclaw / src /plugins /bundled-capability-runtime.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
fcd8223 verified
Raw History Blame Contribute Delete
8.29 kB
import fs from "node:fs";
import path from "node:path";
import { afterAll, afterEach, assert, describe, expect, it } from "vitest";
import { loadBundledCapabilityRuntimeRegistry } from "./bundled-capability-runtime.js";
import { setGatewayPluginMetadataSnapshot } from "./current-plugin-metadata-snapshot.js";
import type { PluginDiscoveryResult } from "./discovery.js";
import {
cleanupPluginLoaderFixturesForTest,
makePluginLoaderTempDir,
resetPluginLoaderTestStateForTest,
type TempPlugin,
writePlugin,
} from "./loader.test-fixtures.js";
import { createPluginCache, withPluginCache } from "./plugin-cache.js";
import {
completePluginMetadataSnapshot,
loadPluginMetadataSnapshot,
} from "./plugin-metadata-snapshot.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import {
captureActivePluginRegistrySnapshot,
getActivePluginRegistry,
getPluginRegistrationContext,
listImportedRuntimePluginIds,
setActivePluginRegistry,
} from "./runtime.js";
afterEach(resetPluginLoaderTestStateForTest);
afterAll(cleanupPluginLoaderFixturesForTest);
function discoveryFor(...plugins: TempPlugin[]): PluginDiscoveryResult {
return {
candidates: plugins.map((plugin) => ({
idHint: plugin.id,
rootDir: plugin.dir,
source: plugin.file,
origin: "bundled",
})),
diagnostics: [],
};
}
function writeChannelCapabilityPlugin(id: string): TempPlugin {
const plugin = writePlugin({
id,
body: `module.exports = {
id: ${JSON.stringify(id)},
register(api) {
if (api.registrationMode === "discovery") {
api.registerTranscriptSourceProvider({
id: ${JSON.stringify(`${id}-voice`)},
name: "Voice transcripts",
sourceKinds: ["meeting"],
});
}
},
};`,
});
fs.writeFileSync(
path.join(plugin.dir, "openclaw.plugin.json"),
JSON.stringify(
{
id,
channels: [id],
configSchema: { type: "object", additionalProperties: false, properties: {} },
},
null,
2,
),
);
return plugin;
}
describe("loadBundledCapabilityRuntimeRegistry", () => {
it("retains the bundled owner under an external shadow without rediscovering changed manifests", () => {
const root = makePluginLoaderTempDir();
const bundledRoot = path.join(root, "bundled");
const target = writePlugin({
id: "shadowed-capability",
dir: path.join(bundledRoot, "shadowed-capability"),
registration: `api.registerProvider({ id: "bundled-capability", label: "Bundled owner", auth: [] });`,
});
fs.writeFileSync(
path.join(target.dir, "package.json"),
JSON.stringify({
name: "@fixture/shadowed-capability",
openclaw: { extensions: ["./shadowed-capability.cjs"] },
}),
);
const shadow = writePlugin({
id: target.id,
body: 'throw new Error("external shadow imported");',
});
const config = { plugins: { load: { paths: [shadow.dir] } } };
const env = {
OPENCLAW_HOME: path.join(root, "home"),
OPENCLAW_BUNDLED_PLUGINS_DIR: bundledRoot,
};
const snapshot = completePluginMetadataSnapshot({
snapshot: loadPluginMetadataSnapshot({ config, env, preferPersisted: false }),
config,
env,
});
assert(snapshot);
expect(snapshot.byPluginId.get(target.id)?.origin).toBe("config");
expect(
snapshot.bundledManifestRegistry?.plugins.find((plugin) => plugin.id === target.id)?.origin,
).toBe("bundled");
setGatewayPluginMetadataSnapshot(snapshot, { config, env });
fs.writeFileSync(path.join(target.dir, "openclaw.plugin.json"), "{}");
const registry = loadBundledCapabilityRuntimeRegistry({ pluginIds: [target.id], config, env });
expect(registry.providers.map((entry) => entry.provider.id)).toEqual(["bundled-capability"]);
expect(registry.plugins.find((plugin) => plugin.id === target.id)?.origin).toBe("bundled");
const loadExplicitDiscovery = () =>
loadBundledCapabilityRuntimeRegistry({
pluginIds: [target.id],
config,
env,
discovery: discoveryFor(target),
});
expect(loadExplicitDiscovery().providers.map((entry) => entry.provider.id)).toEqual([
"bundled-capability",
]);
const freshRegistry = withPluginCache(createPluginCache(), loadExplicitDiscovery);
expect(freshRegistry.providers).toEqual([]);
expect(freshRegistry.diagnostics).toEqual(
expect.arrayContaining([
expect.objectContaining({ pluginId: target.id, message: "plugin manifest requires id" }),
]),
);
expect(
loadBundledCapabilityRuntimeRegistry({ pluginIds: [target.id], config, env }).providers.map(
(entry) => entry.provider.id,
),
).toEqual(["bundled-capability"]);
});
it("loads only the requested bundled plugin without replacing the active registry", () => {
const target = writePlugin({
id: "capability-target",
registration: `if (api.registrationMode === "discovery") {
api.registerProvider({ id: "capability-target", label: "Target", auth: [] });
}
if (api.registrationMode === "full") {
api.registerProvider({ id: "full-only", label: "Full only", auth: [] });
}`,
});
const unscoped = writePlugin({
id: "capability-unscoped",
body: `module.exports = {
id: "capability-unscoped",
register() { throw new Error("unscoped plugin loaded"); },
};`,
});
const active = createEmptyPluginRegistry();
setActivePluginRegistry(active, "existing-registry");
const activeSnapshotBefore = captureActivePluginRegistrySnapshot();
const registrationContextBefore = getPluginRegistrationContext();
const registry = loadBundledCapabilityRuntimeRegistry({
pluginIds: [target.id],
discovery: discoveryFor(target, unscoped),
});
expect(registry.plugins.map((plugin) => plugin.id)).toEqual([target.id]);
expect(registry.plugins[0]?.status).toBe("loaded");
expect(registry.providers.map((entry) => entry.provider.id)).toEqual([target.id]);
expect(getActivePluginRegistry()).toBe(active);
expect(captureActivePluginRegistrySnapshot()).toEqual(activeSnapshotBefore);
expect(getPluginRegistrationContext()).toBe(registrationContextBefore);
expect(listImportedRuntimePluginIds()).toContain(target.id);
});
it.each([
{
name: "explicitly disabled",
plugins: { entries: { "blocked-capability": { enabled: false } } },
},
{ name: "denylisted", plugins: { deny: ["blocked-capability"] } },
{ name: "outside the restrictive allowlist", plugins: { allow: ["allowed-capability"] } },
{ name: "blocked by global plugin disablement", plugins: { enabled: false } },
])("never imports a $name plugin through bundled capability capture", ({ plugins }) => {
const blocked = writePlugin({
id: "blocked-capability",
registration: `api.registerProvider({ id: "blocked-capability", label: "Blocked", auth: [] });`,
});
const registry = loadBundledCapabilityRuntimeRegistry({
pluginIds: [blocked.id],
config: { plugins },
discovery: discoveryFor(blocked),
});
expect(registry.providers).toEqual([]);
expect(listImportedRuntimePluginIds()).not.toContain(blocked.id);
});
it("registers channel capabilities during discovery without replacing the active registry", () => {
const target = writeChannelCapabilityPlugin("capability-channel");
const active = createEmptyPluginRegistry();
setActivePluginRegistry(active, "existing-channel-registry");
const registry = loadBundledCapabilityRuntimeRegistry({
pluginIds: [target.id],
discovery: discoveryFor(target),
});
const plugin = registry.plugins.find((entry) => entry.id === target.id);
expect(
plugin?.status,
JSON.stringify({ plugin, diagnostics: registry.diagnostics }, null, 2),
).toBe("loaded");
expect(plugin?.transcriptSourceProviderIds).toEqual([`${target.id}-voice`]);
expect(registry.transcriptSourceProviders.map((entry) => entry.provider.id)).toEqual([
`${target.id}-voice`,
]);
expect(registry.typedHooks).toEqual([]);
expect(getActivePluginRegistry()).toBe(active);
});
});