mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 18:12:52 +00:00
hardening: bound plugin loader cache
This commit is contained in:
@@ -623,6 +623,47 @@ describe("loadOpenClawPlugins", () => {
|
||||
expect(third).toBe(second);
|
||||
});
|
||||
|
||||
it("evicts least recently used registries when the loader cache exceeds its cap", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "cache-eviction",
|
||||
filename: "cache-eviction.cjs",
|
||||
body: `module.exports = { id: "cache-eviction", register() {} };`,
|
||||
});
|
||||
const stateDirs = Array.from({ length: __testing.maxPluginRegistryCacheEntries + 1 }, () =>
|
||||
makeTempDir(),
|
||||
);
|
||||
|
||||
const loadWithStateDir = (stateDir: string) =>
|
||||
loadOpenClawPlugins({
|
||||
env: {
|
||||
...process.env,
|
||||
OPENCLAW_STATE_DIR: stateDir,
|
||||
OPENCLAW_BUNDLED_PLUGINS_DIR: "/nonexistent/bundled/plugins",
|
||||
},
|
||||
config: {
|
||||
plugins: {
|
||||
allow: ["cache-eviction"],
|
||||
load: {
|
||||
paths: [plugin.file],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const first = loadWithStateDir(stateDirs[0] ?? makeTempDir());
|
||||
const second = loadWithStateDir(stateDirs[1] ?? makeTempDir());
|
||||
|
||||
expect(loadWithStateDir(stateDirs[0] ?? makeTempDir())).toBe(first);
|
||||
|
||||
for (const stateDir of stateDirs.slice(2)) {
|
||||
loadWithStateDir(stateDir);
|
||||
}
|
||||
|
||||
expect(loadWithStateDir(stateDirs[0] ?? makeTempDir())).toBe(first);
|
||||
expect(loadWithStateDir(stateDirs[1] ?? makeTempDir())).not.toBe(second);
|
||||
});
|
||||
|
||||
it("normalizes bundled plugin env overrides against the provided env", () => {
|
||||
const bundledDir = makeTempDir();
|
||||
const homeDir = path.dirname(bundledDir);
|
||||
|
||||
@@ -49,6 +49,7 @@ export type PluginLoadOptions = {
|
||||
mode?: "full" | "validate";
|
||||
};
|
||||
|
||||
const MAX_PLUGIN_REGISTRY_CACHE_ENTRIES = 32;
|
||||
const registryCache = new Map<string, PluginRegistry>();
|
||||
|
||||
export function clearPluginLoaderCache(): void {
|
||||
@@ -171,8 +172,34 @@ export const __testing = {
|
||||
listPluginSdkExportedSubpaths,
|
||||
resolvePluginSdkAliasCandidateOrder,
|
||||
resolvePluginSdkAliasFile,
|
||||
maxPluginRegistryCacheEntries: MAX_PLUGIN_REGISTRY_CACHE_ENTRIES,
|
||||
};
|
||||
|
||||
function getCachedPluginRegistry(cacheKey: string): PluginRegistry | undefined {
|
||||
const cached = registryCache.get(cacheKey);
|
||||
if (!cached) {
|
||||
return undefined;
|
||||
}
|
||||
// Refresh insertion order so frequently reused registries survive eviction.
|
||||
registryCache.delete(cacheKey);
|
||||
registryCache.set(cacheKey, cached);
|
||||
return cached;
|
||||
}
|
||||
|
||||
function setCachedPluginRegistry(cacheKey: string, registry: PluginRegistry): void {
|
||||
if (registryCache.has(cacheKey)) {
|
||||
registryCache.delete(cacheKey);
|
||||
}
|
||||
registryCache.set(cacheKey, registry);
|
||||
while (registryCache.size > MAX_PLUGIN_REGISTRY_CACHE_ENTRIES) {
|
||||
const oldestKey = registryCache.keys().next().value;
|
||||
if (!oldestKey) {
|
||||
break;
|
||||
}
|
||||
registryCache.delete(oldestKey);
|
||||
}
|
||||
}
|
||||
|
||||
function buildCacheKey(params: {
|
||||
workspaceDir?: string;
|
||||
plugins: NormalizedPluginsConfig;
|
||||
@@ -503,7 +530,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
});
|
||||
const cacheEnabled = options.cache !== false;
|
||||
if (cacheEnabled) {
|
||||
const cached = registryCache.get(cacheKey);
|
||||
const cached = getCachedPluginRegistry(cacheKey);
|
||||
if (cached) {
|
||||
activatePluginRegistry(cached, cacheKey);
|
||||
return cached;
|
||||
@@ -863,7 +890,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
});
|
||||
|
||||
if (cacheEnabled) {
|
||||
registryCache.set(cacheKey, registry);
|
||||
setCachedPluginRegistry(cacheKey, registry);
|
||||
}
|
||||
activatePluginRegistry(registry, cacheKey);
|
||||
return registry;
|
||||
|
||||
Reference in New Issue
Block a user