fix(plugins): fail strict bootstrap on plugin load errors
This commit is contained in:
parent
009f494cd9
commit
f3971571fe
@ -60,6 +60,7 @@ describe("ensurePluginRegistryLoaded", () => {
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
onlyPluginIds: [],
|
||||
throwOnLoadError: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@ -85,11 +86,14 @@ describe("ensurePluginRegistryLoaded", () => {
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(2);
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ onlyPluginIds: [] }),
|
||||
expect.objectContaining({ onlyPluginIds: [], throwOnLoadError: true }),
|
||||
);
|
||||
expect(mocks.loadOpenClawPlugins).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({ onlyPluginIds: ["telegram", "slack"] }),
|
||||
expect.objectContaining({
|
||||
onlyPluginIds: ["telegram", "slack"],
|
||||
throwOnLoadError: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -55,6 +55,7 @@ export function ensurePluginRegistryLoaded(options?: { scope?: PluginRegistrySco
|
||||
config,
|
||||
workspaceDir,
|
||||
logger,
|
||||
throwOnLoadError: true,
|
||||
...(scope === "configured-channels"
|
||||
? {
|
||||
onlyPluginIds: resolveConfiguredChannelPluginIds({
|
||||
|
||||
@ -1625,6 +1625,35 @@ module.exports = { id: "skipped-scoped-only", register() { throw new Error("skip
|
||||
expect(registry.diagnostics.some((d) => d.level === "error")).toBe(true);
|
||||
});
|
||||
|
||||
it("throws when strict plugin loading sees plugin errors", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "configurable",
|
||||
filename: "configurable.cjs",
|
||||
body: `module.exports = { id: "configurable", register() {} };`,
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
loadOpenClawPlugins({
|
||||
cache: false,
|
||||
throwOnLoadError: true,
|
||||
config: {
|
||||
plugins: {
|
||||
enabled: true,
|
||||
load: { paths: [plugin.file] },
|
||||
allow: ["configurable"],
|
||||
entries: {
|
||||
configurable: {
|
||||
enabled: true,
|
||||
config: "nope" as unknown as Record<string, unknown>,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toThrow("plugin load failed: configurable: invalid config: <root>: must be object");
|
||||
});
|
||||
|
||||
it("fails when plugin export id mismatches manifest id", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
|
||||
@ -71,8 +71,25 @@ export type PluginLoadOptions = {
|
||||
*/
|
||||
preferSetupRuntimeForChannelPlugins?: boolean;
|
||||
activate?: boolean;
|
||||
throwOnLoadError?: boolean;
|
||||
};
|
||||
|
||||
export class PluginLoadFailureError extends Error {
|
||||
readonly pluginIds: string[];
|
||||
readonly registry: PluginRegistry;
|
||||
|
||||
constructor(registry: PluginRegistry) {
|
||||
const failedPlugins = registry.plugins.filter((entry) => entry.status === "error");
|
||||
const summary = failedPlugins
|
||||
.map((entry) => `${entry.id}: ${entry.error ?? "unknown plugin load error"}`)
|
||||
.join("; ");
|
||||
super(`plugin load failed: ${summary}`);
|
||||
this.name = "PluginLoadFailureError";
|
||||
this.pluginIds = failedPlugins.map((entry) => entry.id);
|
||||
this.registry = registry;
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_PLUGIN_REGISTRY_CACHE_ENTRIES = 128;
|
||||
const registryCache = new Map<string, PluginRegistry>();
|
||||
const openAllowlistWarningCache = new Set<string>();
|
||||
@ -413,6 +430,19 @@ function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnost
|
||||
diagnostics.push(...append);
|
||||
}
|
||||
|
||||
function maybeThrowOnPluginLoadError(
|
||||
registry: PluginRegistry,
|
||||
throwOnLoadError: boolean | undefined,
|
||||
): void {
|
||||
if (!throwOnLoadError) {
|
||||
return;
|
||||
}
|
||||
if (!registry.plugins.some((entry) => entry.status === "error")) {
|
||||
return;
|
||||
}
|
||||
throw new PluginLoadFailureError(registry);
|
||||
}
|
||||
|
||||
type PathMatcher = {
|
||||
exact: Set<string>;
|
||||
dirs: string[];
|
||||
@ -1253,6 +1283,8 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
env,
|
||||
});
|
||||
|
||||
maybeThrowOnPluginLoadError(registry, options.throwOnLoadError);
|
||||
|
||||
if (cacheEnabled) {
|
||||
setCachedPluginRegistry(cacheKey, registry);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user