mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:20:43 +00:00
refactor: unify plugin metadata snapshot callers
This commit is contained in:
@@ -6,6 +6,20 @@ const pluginRegistryMocks = vi.hoisted(() => {
|
||||
loadPluginManifestRegistryForInstalledIndex: loadManifestRegistry,
|
||||
loadPluginManifestRegistryForPluginRegistry: loadManifestRegistry,
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
loadPluginMetadataSnapshot: vi.fn((params: unknown) => {
|
||||
const registry = loadManifestRegistry(params) ?? { plugins: [], diagnostics: [] };
|
||||
return {
|
||||
index: {
|
||||
plugins: registry.plugins.map((plugin: { id: string; origin?: string }) => ({
|
||||
pluginId: plugin.id,
|
||||
origin: plugin.origin ?? "global",
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
})),
|
||||
},
|
||||
plugins: registry.plugins,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -20,6 +34,10 @@ vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: pluginRegistryMocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot: pluginRegistryMocks.loadPluginMetadataSnapshot,
|
||||
}));
|
||||
|
||||
import {
|
||||
resetProviderAuthAliasMapCacheForTest,
|
||||
resolveProviderIdForAuth,
|
||||
@@ -32,6 +50,7 @@ describe("provider auth aliases", () => {
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForPluginRegistry.mockReset();
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReset();
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
|
||||
pluginRegistryMocks.loadPluginMetadataSnapshot.mockClear();
|
||||
});
|
||||
|
||||
it("treats deprecated auth choice ids as provider auth aliases", () => {
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
normalizePluginConfigId,
|
||||
} from "../plugins/plugin-config-trust.js";
|
||||
import { resolvePluginControlPlaneFingerprint } from "../plugins/plugin-control-plane-context.js";
|
||||
import { loadPluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
|
||||
import type { PluginOrigin } from "../plugins/plugin-origin.types.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "../plugins/plugin-registry.js";
|
||||
import { normalizeProviderId } from "./provider-id.js";
|
||||
|
||||
export type ProviderAuthAliasLookupParams = {
|
||||
@@ -118,15 +118,14 @@ export function resolveProviderAuthAliasMap(
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const registry = loadPluginManifestRegistryForPluginRegistry({
|
||||
config: params?.config,
|
||||
const snapshot = loadPluginMetadataSnapshot({
|
||||
config: params?.config ?? {},
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const preferredAliases = new Map<string, ProviderAuthAliasCandidate>();
|
||||
const aliases: Record<string, string> = Object.create(null) as Record<string, string>;
|
||||
for (const plugin of registry.plugins) {
|
||||
for (const plugin of snapshot.plugins) {
|
||||
if (!shouldUsePluginAuthAliases(plugin, params)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
68
src/channels/plugins/read-only-command-defaults.test.ts
Normal file
68
src/channels/plugins/read-only-command-defaults.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadPluginMetadataSnapshot = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../../plugins/plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot,
|
||||
}));
|
||||
|
||||
import { resolveReadOnlyChannelCommandDefaults } from "./read-only-command-defaults.js";
|
||||
|
||||
describe("resolveReadOnlyChannelCommandDefaults", () => {
|
||||
beforeEach(() => {
|
||||
loadPluginMetadataSnapshot.mockReset();
|
||||
loadPluginMetadataSnapshot.mockReturnValue({
|
||||
index: { plugins: [] },
|
||||
plugins: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves command defaults from the shared metadata snapshot", () => {
|
||||
const env = { HOME: "/home/demo" } as NodeJS.ProcessEnv;
|
||||
loadPluginMetadataSnapshot.mockReturnValue({
|
||||
index: {
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "demo",
|
||||
origin: "global",
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: "demo",
|
||||
origin: "global",
|
||||
channels: ["demo"],
|
||||
channelConfigs: {
|
||||
demo: {
|
||||
commands: {
|
||||
nativeCommandsAutoEnabled: true,
|
||||
nativeSkillsAutoEnabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveReadOnlyChannelCommandDefaults("demo", {
|
||||
config: {},
|
||||
env,
|
||||
stateDir: "/state",
|
||||
workspaceDir: "/workspace",
|
||||
}),
|
||||
).toEqual({
|
||||
nativeCommandsAutoEnabled: true,
|
||||
nativeSkillsAutoEnabled: false,
|
||||
});
|
||||
expect(loadPluginMetadataSnapshot).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
env,
|
||||
stateDir: "/state",
|
||||
workspaceDir: "/workspace",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { isBlockedObjectKey } from "../../infra/prototype-keys.js";
|
||||
import { isInstalledPluginEnabled } from "../../plugins/installed-plugin-index.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "../../plugins/manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord } from "../../plugins/manifest-registry.js";
|
||||
import { loadPluginRegistrySnapshot } from "../../plugins/plugin-registry.js";
|
||||
import { loadPluginMetadataSnapshot } from "../../plugins/plugin-metadata-snapshot.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import type { ChannelPlugin } from "./types.plugin.js";
|
||||
|
||||
@@ -65,20 +64,13 @@ export function resolveReadOnlyChannelCommandDefaults(
|
||||
if (!normalizedChannelId || !isSafeManifestChannelId(normalizedChannelId)) {
|
||||
return undefined;
|
||||
}
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
const snapshot = loadPluginMetadataSnapshot({
|
||||
config: options.config,
|
||||
stateDir: options.stateDir,
|
||||
workspaceDir: options.workspaceDir,
|
||||
env: options.env ?? process.env,
|
||||
});
|
||||
const registry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: options.config,
|
||||
workspaceDir: options.workspaceDir,
|
||||
env: options.env ?? process.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
for (const record of registry.plugins) {
|
||||
for (const record of snapshot.plugins) {
|
||||
if (!record.channels.includes(normalizedChannelId)) {
|
||||
continue;
|
||||
}
|
||||
@@ -88,7 +80,7 @@ export function resolveReadOnlyChannelCommandDefaults(
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (!isInstalledPluginEnabled(index, record.id, options.config)) {
|
||||
if (!isInstalledPluginEnabled(snapshot.index, record.id, options.config)) {
|
||||
continue;
|
||||
}
|
||||
const channelConfigValue = record.channelConfigs
|
||||
|
||||
68
src/plugins/manifest-contract-runtime.test.ts
Normal file
68
src/plugins/manifest-contract-runtime.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadPluginMetadataSnapshot = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot,
|
||||
}));
|
||||
|
||||
import { resolveManifestContractRuntimePluginResolution } from "./manifest-contract-runtime.js";
|
||||
|
||||
describe("resolveManifestContractRuntimePluginResolution", () => {
|
||||
beforeEach(() => {
|
||||
loadPluginMetadataSnapshot.mockReset();
|
||||
loadPluginMetadataSnapshot.mockReturnValue({
|
||||
index: { plugins: [] },
|
||||
plugins: [],
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves contract plugins from the shared metadata snapshot", () => {
|
||||
loadPluginMetadataSnapshot.mockReturnValue({
|
||||
index: {
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "bundled-search",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
},
|
||||
{
|
||||
pluginId: "external-search",
|
||||
origin: "global",
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: "bundled-search",
|
||||
origin: "bundled",
|
||||
contracts: { webSearchProviders: ["search"] },
|
||||
},
|
||||
{
|
||||
id: "external-search",
|
||||
origin: "global",
|
||||
contracts: { webSearchProviders: ["search"] },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveManifestContractRuntimePluginResolution({
|
||||
cfg: {},
|
||||
contract: "webSearchProviders",
|
||||
value: "search",
|
||||
}),
|
||||
).toEqual({
|
||||
pluginIds: ["bundled-search", "external-search"],
|
||||
bundledCompatPluginIds: ["bundled-search"],
|
||||
});
|
||||
expect(loadPluginMetadataSnapshot).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
env: process.env,
|
||||
preferPersisted: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,9 +3,8 @@ import {
|
||||
hasManifestContractValue,
|
||||
listAvailableManifestContractPlugins,
|
||||
} from "./manifest-contract-eligibility.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestContractListKey } from "./manifest-registry.js";
|
||||
import { loadPluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
import { loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";
|
||||
|
||||
export type ManifestContractRuntimePluginResolution = {
|
||||
pluginIds: string[];
|
||||
@@ -21,17 +20,12 @@ export function resolveManifestContractRuntimePluginResolution(params: {
|
||||
contract: PluginManifestContractListKey;
|
||||
value?: string;
|
||||
}): ManifestContractRuntimePluginResolution {
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params.cfg,
|
||||
const snapshot = loadPluginMetadataSnapshot({
|
||||
config: params.cfg ?? {},
|
||||
env: process.env,
|
||||
...DEMAND_ONLY_CONTRACT_LOOKUP_OPTIONS,
|
||||
});
|
||||
const allContractPlugins = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
includeDisabled: true,
|
||||
}).plugins.filter((plugin) =>
|
||||
const allContractPlugins = snapshot.plugins.filter((plugin) =>
|
||||
hasManifestContractValue({
|
||||
plugin,
|
||||
contract: params.contract,
|
||||
@@ -42,7 +36,7 @@ export function resolveManifestContractRuntimePluginResolution(params: {
|
||||
.filter((plugin) => plugin.origin === "bundled")
|
||||
.map((plugin) => plugin.id);
|
||||
const pluginIds = listAvailableManifestContractPlugins({
|
||||
snapshot: { index, plugins: allContractPlugins },
|
||||
snapshot: { index: snapshot.index, plugins: allContractPlugins },
|
||||
contract: params.contract,
|
||||
value: params.value,
|
||||
config: params.cfg,
|
||||
|
||||
@@ -180,7 +180,9 @@ function loadPluginMetadataSnapshotImpl(
|
||||
const registryResult = loadPluginRegistrySnapshotWithMetadata({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
...(params.stateDir ? { stateDir: params.stateDir } : {}),
|
||||
env: params.env,
|
||||
...(params.preferPersisted !== undefined ? { preferPersisted: params.preferPersisted } : {}),
|
||||
...(params.index ? { index: params.index } : {}),
|
||||
});
|
||||
const registrySnapshotMs = performance.now() - registryStartedAt;
|
||||
|
||||
@@ -55,6 +55,8 @@ export type PluginMetadataManifestView = Pick<PluginMetadataSnapshot, "index" |
|
||||
export type LoadPluginMetadataSnapshotParams = {
|
||||
config: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
stateDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
index?: InstalledPluginIndex;
|
||||
preferPersisted?: boolean;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadPluginRegistrySnapshotMock = vi.hoisted(() => vi.fn());
|
||||
const loadPluginManifestRegistryForInstalledIndexMock = vi.hoisted(() => vi.fn());
|
||||
const loadPluginMetadataSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./plugin-registry.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("./plugin-registry.js")>()),
|
||||
@@ -10,36 +11,39 @@ vi.mock("./plugin-registry.js", async (importOriginal) => ({
|
||||
vi.mock("./manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: loadPluginManifestRegistryForInstalledIndexMock,
|
||||
}));
|
||||
vi.mock("./plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot: loadPluginMetadataSnapshotMock,
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
loadPluginRegistrySnapshotMock.mockReset();
|
||||
loadPluginManifestRegistryForInstalledIndexMock.mockReset();
|
||||
loadPluginMetadataSnapshotMock.mockReset();
|
||||
});
|
||||
|
||||
describe("setup-registry runtime fallback", () => {
|
||||
it("uses bundled registry cliBackends when the setup-registry runtime is unavailable", async () => {
|
||||
loadPluginRegistrySnapshotMock.mockReturnValue({
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "openai",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
pluginId: "disabled",
|
||||
origin: "bundled",
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
pluginId: "local",
|
||||
origin: "workspace",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
loadPluginManifestRegistryForInstalledIndexMock.mockReturnValue({
|
||||
diagnostics: [],
|
||||
loadPluginMetadataSnapshotMock.mockReturnValue({
|
||||
index: {
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "openai",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
pluginId: "disabled",
|
||||
origin: "bundled",
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
pluginId: "local",
|
||||
origin: "workspace",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: "openai",
|
||||
@@ -60,25 +64,26 @@ describe("setup-registry runtime fallback", () => {
|
||||
});
|
||||
expect(resolvePluginSetupCliBackendRuntime({ backend: "local-cli" })).toBeUndefined();
|
||||
expect(resolvePluginSetupCliBackendRuntime({ backend: "disabled-cli" })).toBeUndefined();
|
||||
expect(loadPluginRegistrySnapshotMock).toHaveBeenCalledTimes(3);
|
||||
expect(loadPluginRegistrySnapshotMock).toHaveBeenCalledWith({});
|
||||
expect(loadPluginManifestRegistryForInstalledIndexMock).toHaveBeenCalledWith({
|
||||
index: expect.objectContaining({
|
||||
plugins: expect.arrayContaining([expect.objectContaining({ pluginId: "openai" })]),
|
||||
}),
|
||||
expect(loadPluginMetadataSnapshotMock).toHaveBeenCalledTimes(3);
|
||||
expect(loadPluginMetadataSnapshotMock).toHaveBeenCalledWith({
|
||||
config: {},
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves fail-closed setup lookup when the runtime module explicitly declines to resolve", async () => {
|
||||
loadPluginRegistrySnapshotMock.mockReturnValue({
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "openai",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
loadPluginMetadataSnapshotMock.mockReturnValue({
|
||||
index: {
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
pluginId: "openai",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [],
|
||||
});
|
||||
|
||||
const { __testing, resolvePluginSetupCliBackendRuntime } =
|
||||
@@ -89,6 +94,6 @@ describe("setup-registry runtime fallback", () => {
|
||||
});
|
||||
|
||||
expect(resolvePluginSetupCliBackendRuntime({ backend: "codex-cli" })).toBeUndefined();
|
||||
expect(loadPluginRegistrySnapshotMock).not.toHaveBeenCalled();
|
||||
expect(loadPluginMetadataSnapshotMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createRequire } from "node:module";
|
||||
import { normalizeProviderId } from "../agents/provider-id.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import { loadPluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
import { isInstalledPluginEnabled } from "./installed-plugin-index.js";
|
||||
import { loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";
|
||||
|
||||
type SetupRegistryRuntimeModule = Pick<
|
||||
typeof import("./setup-registry.js"),
|
||||
@@ -30,11 +30,9 @@ export const __testing = {
|
||||
};
|
||||
|
||||
function resolveBundledSetupCliBackends(): SetupCliBackendRuntimeEntry[] {
|
||||
const index = loadPluginRegistrySnapshot({});
|
||||
return loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
}).plugins.flatMap((plugin) => {
|
||||
if (plugin.origin !== "bundled") {
|
||||
const snapshot = loadPluginMetadataSnapshot({ config: {}, env: process.env });
|
||||
return snapshot.plugins.flatMap((plugin) => {
|
||||
if (plugin.origin !== "bundled" || !isInstalledPluginEnabled(snapshot.index, plugin.id)) {
|
||||
return [];
|
||||
}
|
||||
return [...plugin.cliBackends, ...(plugin.setup?.cliBackends ?? [])].map(
|
||||
|
||||
@@ -15,6 +15,21 @@ const loadPluginMetadataRegistrySnapshotMock = vi.fn();
|
||||
const loadPluginManifestRegistryForPluginRegistryMock = vi.fn();
|
||||
const loadPluginRegistrySnapshotWithMetadataMock = vi.fn();
|
||||
const loadPluginManifestRegistryForInstalledIndexMock = vi.fn();
|
||||
const loadPluginMetadataSnapshotMock = vi.fn((rawParams: unknown = {}) => {
|
||||
const params = rawParams as { index?: unknown };
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndexMock(params) ?? {
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
};
|
||||
return {
|
||||
index: params.index ?? createInstalledPluginIndexSnapshot([]),
|
||||
manifestRegistry,
|
||||
plugins: manifestRegistry.plugins,
|
||||
byPluginId: new Map(
|
||||
manifestRegistry.plugins.map((plugin: { id: string }) => [plugin.id, plugin]),
|
||||
),
|
||||
};
|
||||
});
|
||||
const applyPluginAutoEnableMock = vi.fn();
|
||||
const resolveBundledProviderCompatPluginIdsMock = vi.fn();
|
||||
const withBundledPluginAllowlistCompatMock = vi.fn();
|
||||
@@ -61,6 +76,10 @@ vi.mock("./manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndexMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("./plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot: (...args: unknown[]) => loadPluginMetadataSnapshotMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock("./providers.js", () => ({
|
||||
resolveBundledProviderCompatPluginIds: (...args: unknown[]) =>
|
||||
resolveBundledProviderCompatPluginIdsMock(...args),
|
||||
@@ -370,6 +389,7 @@ describe("plugin status reports", () => {
|
||||
loadPluginManifestRegistryForPluginRegistryMock.mockReset();
|
||||
loadPluginRegistrySnapshotWithMetadataMock.mockReset();
|
||||
loadPluginManifestRegistryForInstalledIndexMock.mockReset();
|
||||
loadPluginMetadataSnapshotMock.mockClear();
|
||||
applyPluginAutoEnableMock.mockReset();
|
||||
resolveBundledProviderCompatPluginIdsMock.mockReset();
|
||||
withBundledPluginAllowlistCompatMock.mockReset();
|
||||
|
||||
@@ -20,12 +20,11 @@ import {
|
||||
type PluginInspectShape,
|
||||
} from "./inspect-shape.js";
|
||||
import { loadOpenClawPlugins } from "./loader.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord } from "./manifest-registry.js";
|
||||
import type { PluginDiagnostic } from "./manifest-types.js";
|
||||
import { tracePluginLifecyclePhase } from "./plugin-lifecycle-trace.js";
|
||||
import { loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";
|
||||
import {
|
||||
loadPluginManifestRegistryForPluginRegistry,
|
||||
loadPluginRegistrySnapshotWithMetadata,
|
||||
type PluginRegistrySnapshotDiagnostic,
|
||||
type PluginRegistrySnapshotSource,
|
||||
@@ -230,14 +229,13 @@ export function buildPluginRegistrySnapshotReport(
|
||||
}),
|
||||
{ surface: "status" },
|
||||
);
|
||||
const manifestRegistry = loadPluginManifestRegistryForInstalledIndex({
|
||||
const metadataSnapshot = loadPluginMetadataSnapshot({
|
||||
index: result.snapshot,
|
||||
config,
|
||||
env: params?.env,
|
||||
env: params?.env ?? process.env,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const manifestByPluginId = new Map(manifestRegistry.plugins.map((plugin) => [plugin.id, plugin]));
|
||||
const manifestByPluginId = metadataSnapshot.byPluginId;
|
||||
return {
|
||||
workspaceDir: params?.workspaceDir,
|
||||
...createEmptyPluginRegistry(),
|
||||
@@ -258,12 +256,11 @@ function buildPluginReport(
|
||||
const initialWorkspaceDir =
|
||||
params?.workspaceDir ??
|
||||
resolveAgentWorkspaceDir(rawConfig, resolveDefaultAgentId(rawConfig), params?.env);
|
||||
const manifestRegistry = !loadModules
|
||||
? loadPluginManifestRegistryForPluginRegistry({
|
||||
const metadataSnapshot = !loadModules
|
||||
? loadPluginMetadataSnapshot({
|
||||
config: rawConfig,
|
||||
env: params?.env,
|
||||
env: params?.env ?? process.env,
|
||||
workspaceDir: initialWorkspaceDir,
|
||||
includeDisabled: true,
|
||||
})
|
||||
: undefined;
|
||||
const baseContext = resolvePluginRuntimeLoadContext({
|
||||
@@ -271,7 +268,7 @@ function buildPluginReport(
|
||||
env: params?.env,
|
||||
logger: params?.logger,
|
||||
workspaceDir: initialWorkspaceDir,
|
||||
manifestRegistry,
|
||||
manifestRegistry: metadataSnapshot?.manifestRegistry,
|
||||
});
|
||||
const workspaceDir =
|
||||
baseContext.workspaceDir ?? initialWorkspaceDir ?? resolveDefaultAgentWorkspaceDir();
|
||||
@@ -294,7 +291,7 @@ function buildPluginReport(
|
||||
config,
|
||||
workspaceDir,
|
||||
env: params?.env,
|
||||
manifestRegistry,
|
||||
manifestRegistry: metadataSnapshot?.manifestRegistry,
|
||||
});
|
||||
const effectiveConfig = withBundledPluginAllowlistCompat({
|
||||
config,
|
||||
@@ -344,7 +341,7 @@ function buildPluginReport(
|
||||
logger: params?.logger,
|
||||
loadModules: false,
|
||||
onlyPluginIds,
|
||||
manifestRegistry,
|
||||
manifestRegistry: metadataSnapshot?.manifestRegistry,
|
||||
runtimeContext: context,
|
||||
}),
|
||||
{ surface: "status", onlyPluginCount: onlyPluginIds?.length },
|
||||
|
||||
@@ -44,6 +44,20 @@ const pluginRegistryMocks = vi.hoisted(() => {
|
||||
loadPluginManifestRegistryForInstalledIndex: loadManifestRegistry,
|
||||
loadPluginManifestRegistryForPluginRegistry: loadManifestRegistry,
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
loadPluginMetadataSnapshot: vi.fn((params: unknown) => {
|
||||
const registry = loadManifestRegistry(params) ?? { plugins: [], diagnostics: [] };
|
||||
return {
|
||||
index: {
|
||||
plugins: registry.plugins.map((plugin) => ({
|
||||
pluginId: plugin.id,
|
||||
origin: plugin.origin,
|
||||
enabled: true,
|
||||
enabledByDefault: true,
|
||||
})),
|
||||
},
|
||||
plugins: registry.plugins,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -58,6 +72,10 @@ vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: pluginRegistryMocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-metadata-snapshot.js", () => ({
|
||||
loadPluginMetadataSnapshot: pluginRegistryMocks.loadPluginMetadataSnapshot,
|
||||
}));
|
||||
|
||||
describe("provider env vars dynamic manifest metadata", () => {
|
||||
beforeEach(() => {
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReset();
|
||||
@@ -67,6 +85,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReset();
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
|
||||
pluginRegistryMocks.loadPluginMetadataSnapshot.mockClear();
|
||||
__testing.resetProviderEnvVarCachesForTests();
|
||||
});
|
||||
|
||||
@@ -153,9 +172,9 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
source: "external cloud credentials",
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForPluginRegistry.mock.calls.at(-1)?.[0],
|
||||
).toMatchObject({ includeDisabled: false });
|
||||
expect(pluginRegistryMocks.loadPluginMetadataSnapshot.mock.calls.at(-1)?.[0]).toMatchObject({
|
||||
preferPersisted: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("excludes untrusted workspace plugin auth evidence by default", async () => {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { resolveProviderAuthAliasMap } from "../agents/provider-auth-aliases.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { isInstalledPluginEnabled } from "../plugins/installed-plugin-index.js";
|
||||
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import {
|
||||
isWorkspacePluginAllowedByConfig,
|
||||
normalizePluginConfigId,
|
||||
} from "../plugins/plugin-config-trust.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "../plugins/plugin-registry.js";
|
||||
import { loadPluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
|
||||
import { hasKind } from "../plugins/slots.js";
|
||||
|
||||
const CORE_PROVIDER_AUTH_ENV_VAR_CANDIDATES = {
|
||||
@@ -117,15 +118,14 @@ function appendUniqueAuthEvidence(
|
||||
function resolveManifestProviderAuthEnvVarCandidates(
|
||||
params?: ProviderEnvVarLookupParams,
|
||||
): Record<string, string[]> {
|
||||
const registry = loadPluginManifestRegistryForPluginRegistry({
|
||||
config: params?.config,
|
||||
const snapshot = loadPluginMetadataSnapshot({
|
||||
config: params?.config ?? {},
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
env: params?.env ?? process.env,
|
||||
preferPersisted: false,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const candidates: Record<string, string[]> = {};
|
||||
for (const plugin of registry.plugins) {
|
||||
for (const plugin of snapshot.plugins) {
|
||||
if (!shouldUsePluginProviderEnvVars(plugin, params)) {
|
||||
continue;
|
||||
}
|
||||
@@ -155,15 +155,17 @@ function resolveManifestProviderAuthEnvVarCandidates(
|
||||
function resolveManifestProviderAuthEvidence(
|
||||
params?: ProviderEnvVarLookupParams,
|
||||
): Record<string, ProviderAuthEvidence[]> {
|
||||
const registry = loadPluginManifestRegistryForPluginRegistry({
|
||||
config: params?.config,
|
||||
const snapshot = loadPluginMetadataSnapshot({
|
||||
config: params?.config ?? {},
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
env: params?.env ?? process.env,
|
||||
preferPersisted: false,
|
||||
includeDisabled: false,
|
||||
});
|
||||
const evidenceByProvider: Record<string, ProviderAuthEvidence[]> = {};
|
||||
for (const plugin of registry.plugins) {
|
||||
for (const plugin of snapshot.plugins) {
|
||||
if (!isInstalledPluginEnabled(snapshot.index, plugin.id, params?.config)) {
|
||||
continue;
|
||||
}
|
||||
if (!shouldUsePluginProviderAuthEvidence(plugin, params)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user