mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:50:49 +00:00
fix: guard plugin metadata snapshot reuse
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveInstalledPluginIndexPolicyHash } from "./installed-plugin-index-policy.js";
|
||||
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { PluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
|
||||
@@ -47,13 +48,16 @@ function createManifestRecord(
|
||||
};
|
||||
}
|
||||
|
||||
function createIndex(plugins: readonly PluginManifestRecord[]): PluginRegistrySnapshot {
|
||||
function createIndex(
|
||||
plugins: readonly PluginManifestRecord[],
|
||||
params: { policyHash?: string } = {},
|
||||
): PluginRegistrySnapshot {
|
||||
return {
|
||||
version: 1,
|
||||
hostContractVersion: "test",
|
||||
compatRegistryVersion: "test",
|
||||
migrationVersion: 1,
|
||||
policyHash: "policy",
|
||||
policyHash: params.policyHash ?? "policy",
|
||||
generatedAtMs: 1,
|
||||
installRecords: {},
|
||||
diagnostics: [],
|
||||
@@ -194,6 +198,15 @@ describe("loadPluginLookUpTable", () => {
|
||||
}),
|
||||
];
|
||||
const index = createIndex(plugins);
|
||||
const config = {
|
||||
channels: {
|
||||
telegram: { token: "configured" },
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const compatibleIndex = {
|
||||
...index,
|
||||
policyHash: resolveInstalledPluginIndexPolicyHash(config),
|
||||
};
|
||||
const manifestRegistry: PluginManifestRegistry = {
|
||||
plugins,
|
||||
diagnostics: [],
|
||||
@@ -203,22 +216,14 @@ describe("loadPluginLookUpTable", () => {
|
||||
const { loadPluginLookUpTable } = await import("./plugin-lookup-table.js");
|
||||
|
||||
const metadataSnapshot = loadPluginMetadataSnapshot({
|
||||
config: {
|
||||
channels: {
|
||||
telegram: { token: "configured" },
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
config,
|
||||
env: {},
|
||||
index,
|
||||
index: compatibleIndex,
|
||||
});
|
||||
loadPluginManifestRegistryForInstalledIndex.mockClear();
|
||||
|
||||
const table = loadPluginLookUpTable({
|
||||
config: {
|
||||
channels: {
|
||||
telegram: { token: "configured" },
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
config,
|
||||
env: {},
|
||||
metadataSnapshot,
|
||||
});
|
||||
@@ -229,4 +234,59 @@ describe("loadPluginLookUpTable", () => {
|
||||
expect(table.metrics.indexPluginCount).toBe(1);
|
||||
expect(table.metrics.manifestPluginCount).toBe(1);
|
||||
});
|
||||
|
||||
it("rebuilds when a provided metadata snapshot has a stale plugin policy", async () => {
|
||||
const plugins = [
|
||||
createManifestRecord({
|
||||
id: "telegram",
|
||||
origin: "bundled",
|
||||
channels: ["telegram"],
|
||||
}),
|
||||
];
|
||||
const snapshotConfig = {
|
||||
plugins: {
|
||||
allow: ["telegram"],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const requestedConfig = {
|
||||
plugins: {
|
||||
allow: ["other-plugin"],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const snapshotIndex = createIndex(plugins, {
|
||||
policyHash: resolveInstalledPluginIndexPolicyHash(snapshotConfig),
|
||||
});
|
||||
const requestedIndex = createIndex(plugins, {
|
||||
policyHash: resolveInstalledPluginIndexPolicyHash(requestedConfig),
|
||||
});
|
||||
const manifestRegistry: PluginManifestRegistry = {
|
||||
plugins,
|
||||
diagnostics: [],
|
||||
};
|
||||
loadPluginManifestRegistryForInstalledIndex.mockReturnValue(manifestRegistry);
|
||||
const { loadPluginMetadataSnapshot } = await import("./plugin-metadata-snapshot.js");
|
||||
const { loadPluginLookUpTable } = await import("./plugin-lookup-table.js");
|
||||
|
||||
const metadataSnapshot = loadPluginMetadataSnapshot({
|
||||
config: snapshotConfig,
|
||||
env: {},
|
||||
index: snapshotIndex,
|
||||
});
|
||||
loadPluginManifestRegistryForInstalledIndex.mockClear();
|
||||
|
||||
loadPluginLookUpTable({
|
||||
config: requestedConfig,
|
||||
env: {},
|
||||
index: requestedIndex,
|
||||
metadataSnapshot,
|
||||
});
|
||||
|
||||
expect(loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledOnce();
|
||||
expect(loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
index: requestedIndex,
|
||||
config: requestedConfig,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "./channel-plugin-ids.js";
|
||||
import { hashJson } from "./installed-plugin-index-hash.js";
|
||||
import {
|
||||
isPluginMetadataSnapshotCompatible,
|
||||
loadPluginMetadataSnapshot,
|
||||
type PluginMetadataSnapshot,
|
||||
type PluginMetadataSnapshotOwnerMaps,
|
||||
@@ -52,14 +53,21 @@ export type LoadPluginLookUpTableParams = {
|
||||
};
|
||||
|
||||
export function loadPluginLookUpTable(params: LoadPluginLookUpTableParams): PluginLookUpTable {
|
||||
const requestedSnapshotConfig = params.activationSourceConfig ?? params.config;
|
||||
const metadataSnapshot =
|
||||
params.metadataSnapshot ??
|
||||
loadPluginMetadataSnapshot({
|
||||
config: params.config,
|
||||
params.metadataSnapshot &&
|
||||
isPluginMetadataSnapshotCompatible({
|
||||
snapshot: params.metadataSnapshot,
|
||||
config: requestedSnapshotConfig,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
...(params.index ? { index: params.index } : {}),
|
||||
});
|
||||
})
|
||||
? params.metadataSnapshot
|
||||
: loadPluginMetadataSnapshot({
|
||||
config: requestedSnapshotConfig,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
...(params.index ? { index: params.index } : {}),
|
||||
});
|
||||
const { index, manifestRegistry } = metadataSnapshot;
|
||||
const startupPlanStartedAt = performance.now();
|
||||
const channelPluginIds = resolveChannelPluginIdsFromRegistry({ manifestRegistry });
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveInstalledPluginIndexPolicyHash } from "./installed-plugin-index-policy.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { PluginDiagnostic } from "./manifest-types.js";
|
||||
@@ -30,6 +31,8 @@ export type PluginMetadataSnapshotMetrics = {
|
||||
};
|
||||
|
||||
export type PluginMetadataSnapshot = {
|
||||
policyHash: string;
|
||||
workspaceDir?: string;
|
||||
index: PluginRegistrySnapshot;
|
||||
registryDiagnostics: readonly PluginRegistrySnapshotDiagnostic[];
|
||||
manifestRegistry: PluginManifestRegistry;
|
||||
@@ -48,6 +51,17 @@ export type LoadPluginMetadataSnapshotParams = {
|
||||
index?: PluginRegistrySnapshot;
|
||||
};
|
||||
|
||||
export function isPluginMetadataSnapshotCompatible(params: {
|
||||
snapshot: Pick<PluginMetadataSnapshot, "policyHash" | "workspaceDir">;
|
||||
config: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
}): boolean {
|
||||
return (
|
||||
params.snapshot.policyHash === resolveInstalledPluginIndexPolicyHash(params.config) &&
|
||||
(params.snapshot.workspaceDir ?? "") === (params.workspaceDir ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
function appendOwner(owners: Map<string, string[]>, ownedId: string, pluginId: string): void {
|
||||
const existing = owners.get(ownedId);
|
||||
if (existing) {
|
||||
@@ -149,6 +163,8 @@ export function loadPluginMetadataSnapshot(
|
||||
const totalMs = performance.now() - totalStartedAt;
|
||||
|
||||
return {
|
||||
policyHash: index.policyHash,
|
||||
...(params.workspaceDir ? { workspaceDir: params.workspaceDir } : {}),
|
||||
index,
|
||||
registryDiagnostics: registryResult.diagnostics,
|
||||
manifestRegistry,
|
||||
|
||||
Reference in New Issue
Block a user