mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-29 19:01:44 +00:00
fix(plugins): enforce minimum host versions for installable plugins (#52094)
* fix(plugins): enforce min host versions * fix(plugins): tighten min host version validation * chore(plugins): trim dead min host version code * fix(plugins): handle malformed min host metadata * fix(plugins): key manifest cache by host version
This commit is contained in:
@@ -493,6 +493,7 @@ beforeAll(async () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe("installPluginFromArchive", () => {
|
||||
@@ -775,6 +776,95 @@ describe("installPluginFromDir", () => {
|
||||
expect(manifest.devDependencies?.vitest).toBe("^3.0.0");
|
||||
});
|
||||
|
||||
it("rejects plugins whose minHostVersion is newer than the current host", async () => {
|
||||
vi.stubEnv("OPENCLAW_VERSION", "2026.3.13");
|
||||
const { pluginDir, extensionsDir } = setupInstallPluginFromDirFixture();
|
||||
const packageJsonPath = path.join(pluginDir, "package.json");
|
||||
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
||||
openclaw?: { install?: Record<string, unknown> };
|
||||
};
|
||||
manifest.openclaw = {
|
||||
...manifest.openclaw,
|
||||
install: {
|
||||
...manifest.openclaw?.install,
|
||||
minHostVersion: ">=2026.3.14",
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(packageJsonPath, JSON.stringify(manifest), "utf-8");
|
||||
|
||||
const result = await installPluginFromDir({
|
||||
dirPath: pluginDir,
|
||||
extensionsDir,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) {
|
||||
return;
|
||||
}
|
||||
expect(result.code).toBe(PLUGIN_INSTALL_ERROR_CODE.INCOMPATIBLE_HOST_VERSION);
|
||||
expect(result.error).toContain("requires OpenClaw >=2026.3.14, but this host is 2026.3.13");
|
||||
expect(vi.mocked(runCommandWithTimeout)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects plugins with invalid minHostVersion metadata", async () => {
|
||||
const { pluginDir, extensionsDir } = setupInstallPluginFromDirFixture();
|
||||
const packageJsonPath = path.join(pluginDir, "package.json");
|
||||
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
||||
openclaw?: { install?: Record<string, unknown> };
|
||||
};
|
||||
manifest.openclaw = {
|
||||
...manifest.openclaw,
|
||||
install: {
|
||||
...manifest.openclaw?.install,
|
||||
minHostVersion: "2026.3.14",
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(packageJsonPath, JSON.stringify(manifest), "utf-8");
|
||||
|
||||
const result = await installPluginFromDir({
|
||||
dirPath: pluginDir,
|
||||
extensionsDir,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) {
|
||||
return;
|
||||
}
|
||||
expect(result.code).toBe(PLUGIN_INSTALL_ERROR_CODE.INVALID_MIN_HOST_VERSION);
|
||||
expect(result.error).toContain("invalid package.json openclaw.install.minHostVersion");
|
||||
expect(vi.mocked(runCommandWithTimeout)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports unknown host versions distinctly for minHostVersion-gated plugins", async () => {
|
||||
vi.stubEnv("OPENCLAW_VERSION", "unknown");
|
||||
const { pluginDir, extensionsDir } = setupInstallPluginFromDirFixture();
|
||||
const packageJsonPath = path.join(pluginDir, "package.json");
|
||||
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
||||
openclaw?: { install?: Record<string, unknown> };
|
||||
};
|
||||
manifest.openclaw = {
|
||||
...manifest.openclaw,
|
||||
install: {
|
||||
...manifest.openclaw?.install,
|
||||
minHostVersion: ">=2026.3.14",
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(packageJsonPath, JSON.stringify(manifest), "utf-8");
|
||||
|
||||
const result = await installPluginFromDir({
|
||||
dirPath: pluginDir,
|
||||
extensionsDir,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) {
|
||||
return;
|
||||
}
|
||||
expect(result.code).toBe(PLUGIN_INSTALL_ERROR_CODE.UNKNOWN_HOST_VERSION);
|
||||
expect(result.error).toContain("host version could not be determined");
|
||||
expect(vi.mocked(runCommandWithTimeout)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses openclaw.plugin.json id as install key when it differs from package name", async () => {
|
||||
const { pluginDir, extensionsDir } = setupManifestInstallFixture({
|
||||
manifestId: "memory-cognee",
|
||||
|
||||
Reference in New Issue
Block a user