mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:50:43 +00:00
fix(secrets): resolve plugin env metadata cold
This commit is contained in:
@@ -33,6 +33,22 @@ vi.mock("../plugins/manifest-registry.js", async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../plugins/manifest-registry-installed.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../plugins/manifest-registry-installed.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadPluginManifestRegistryForInstalledIndex: loadPluginManifestRegistry,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../plugins/plugin-registry.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadPluginRegistrySnapshot: () => ({ plugins: [] }),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./cli-runner.js", () => ({
|
||||
runCliAgent: runCliAgentMock,
|
||||
}));
|
||||
|
||||
@@ -61,6 +61,12 @@ vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
resolveManifestContractOwnerPluginId,
|
||||
}));
|
||||
vi.mock("../plugins/manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: loadPluginManifestRegistry,
|
||||
}));
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: () => ({ plugins: [] }),
|
||||
}));
|
||||
vi.mock("../plugins/provider-runtime.js", () => ({
|
||||
resolveProviderSyntheticAuthWithPlugin,
|
||||
}));
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadPluginManifestRegistry = vi.hoisted(() => vi.fn());
|
||||
const pluginRegistryMocks = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: vi.fn(),
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
vi.mock("../plugins/manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex:
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: pluginRegistryMocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
import { resolveProviderIdForAuth } from "./provider-auth-aliases.js";
|
||||
|
||||
describe("provider auth aliases", () => {
|
||||
it("treats deprecated auth choice ids as provider auth aliases", () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "openai",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "../plugins/manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import {
|
||||
isWorkspacePluginAllowedByConfig,
|
||||
normalizePluginConfigId,
|
||||
} from "../plugins/plugin-config-trust.js";
|
||||
import type { PluginOrigin } from "../plugins/plugin-origin.types.js";
|
||||
import { loadPluginRegistrySnapshot } from "../plugins/plugin-registry.js";
|
||||
import { normalizeProviderId } from "./provider-id.js";
|
||||
|
||||
export type ProviderAuthAliasLookupParams = {
|
||||
@@ -83,11 +84,18 @@ function setPreferredAlias(params: {
|
||||
export function resolveProviderAuthAliasMap(
|
||||
params?: ProviderAuthAliasLookupParams,
|
||||
): Record<string, string> {
|
||||
const registry = loadPluginManifestRegistry({
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
});
|
||||
const registry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.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) {
|
||||
|
||||
@@ -9,23 +9,37 @@ type MockManifestRegistry = {
|
||||
diagnostics: unknown[];
|
||||
};
|
||||
|
||||
const loadPluginManifestRegistry = vi.hoisted(() =>
|
||||
vi.fn<() => MockManifestRegistry>(() => ({ plugins: [], diagnostics: [] })),
|
||||
);
|
||||
const pluginRegistryMocks = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: vi.fn<() => MockManifestRegistry>(() => ({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
})),
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
vi.mock("../plugins/manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex:
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: pluginRegistryMocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
describe("channel env vars dynamic manifest metadata", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
loadPluginManifestRegistry.mockReset();
|
||||
loadPluginManifestRegistry.mockReturnValue({ plugins: [], diagnostics: [] });
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReset();
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReset();
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
|
||||
});
|
||||
|
||||
it("includes later-installed plugin env vars without a bundled generated map", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-mattermost",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "../plugins/manifest-registry-installed.js";
|
||||
import { loadPluginRegistrySnapshot } from "../plugins/plugin-registry.js";
|
||||
export { isSafeChannelEnvVarTriggerName } from "./channel-env-var-names.js";
|
||||
|
||||
type ChannelEnvVarLookupParams = {
|
||||
@@ -32,11 +33,18 @@ function appendUniqueEnvVarCandidates(
|
||||
export function resolveChannelEnvVars(
|
||||
params?: ChannelEnvVarLookupParams,
|
||||
): Record<string, readonly string[]> {
|
||||
const registry = loadPluginManifestRegistry({
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
});
|
||||
const registry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const candidates: Record<string, string[]> = {};
|
||||
for (const plugin of registry.plugins) {
|
||||
if (!plugin.channelEnvVars) {
|
||||
|
||||
@@ -25,23 +25,37 @@ type MockManifestRegistry = {
|
||||
diagnostics: unknown[];
|
||||
};
|
||||
|
||||
const loadPluginManifestRegistry = vi.hoisted(() =>
|
||||
vi.fn<() => MockManifestRegistry>(() => ({ plugins: [], diagnostics: [] })),
|
||||
);
|
||||
const pluginRegistryMocks = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: vi.fn<() => MockManifestRegistry>(() => ({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
})),
|
||||
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/manifest-registry.js", () => ({
|
||||
loadPluginManifestRegistry,
|
||||
vi.mock("../plugins/manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex:
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/plugin-registry.js", () => ({
|
||||
loadPluginRegistrySnapshot: pluginRegistryMocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
describe("provider env vars dynamic manifest metadata", () => {
|
||||
beforeEach(() => {
|
||||
loadPluginManifestRegistry.mockReset();
|
||||
loadPluginManifestRegistry.mockReturnValue({ plugins: [], diagnostics: [] });
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReset();
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [],
|
||||
diagnostics: [],
|
||||
});
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReset();
|
||||
pluginRegistryMocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
|
||||
__testing.resetProviderEnvVarCachesForTests();
|
||||
});
|
||||
|
||||
it("includes later-installed plugin env vars without a bundled generated map", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-fireworks",
|
||||
@@ -64,7 +78,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("includes setup provider env vars without loading setup runtime", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-model-studio",
|
||||
@@ -88,7 +102,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("appends setup provider env vars after explicit provider auth env vars", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-fireworks",
|
||||
@@ -113,7 +127,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("keeps lazy manifest-backed exports cold until accessed and resolves them once", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-fireworks",
|
||||
@@ -126,19 +140,22 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
expect(loadPluginManifestRegistry).not.toHaveBeenCalled();
|
||||
expect(pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex).not.toHaveBeenCalled();
|
||||
expect(PROVIDER_ENV_VARS.fireworks).toEqual(["FIREWORKS_ALT_API_KEY"]);
|
||||
expect(PROVIDER_AUTH_ENV_VAR_CANDIDATES.fireworks).toEqual(["FIREWORKS_ALT_API_KEY"]);
|
||||
const initialLoads = loadPluginManifestRegistry.mock.calls.length;
|
||||
const initialLoads =
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mock.calls.length;
|
||||
expect(initialLoads).toBeGreaterThan(0);
|
||||
|
||||
void PROVIDER_ENV_VARS.fireworks;
|
||||
void PROVIDER_AUTH_ENV_VAR_CANDIDATES.fireworks;
|
||||
expect(loadPluginManifestRegistry).toHaveBeenCalledTimes(initialLoads);
|
||||
expect(pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledTimes(
|
||||
initialLoads,
|
||||
);
|
||||
});
|
||||
|
||||
it("reuses the lazy default lookup cache for repeated provider env var reads", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "external-fireworks",
|
||||
@@ -152,14 +169,17 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
expect(getProviderEnvVars("fireworks")).toEqual(["FIREWORKS_ALT_API_KEY"]);
|
||||
const initialLoads = loadPluginManifestRegistry.mock.calls.length;
|
||||
const initialLoads =
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mock.calls.length;
|
||||
expect(initialLoads).toBeGreaterThan(0);
|
||||
expect(getProviderEnvVars("fireworks")).toEqual(["FIREWORKS_ALT_API_KEY"]);
|
||||
expect(loadPluginManifestRegistry).toHaveBeenCalledTimes(initialLoads);
|
||||
expect(pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledTimes(
|
||||
initialLoads,
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps workspace plugin env vars in default lookups", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-audio",
|
||||
@@ -179,7 +199,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("excludes untrusted workspace plugin env vars when requested", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-audio",
|
||||
@@ -229,7 +249,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("keeps explicitly trusted workspace plugin env vars when requested", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-audio",
|
||||
@@ -257,7 +277,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("does not trust arbitrary workspace plugin ids from the context engine slot", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-audio",
|
||||
@@ -287,7 +307,7 @@ describe("provider env vars dynamic manifest metadata", () => {
|
||||
});
|
||||
|
||||
it("keeps selected workspace context engine env vars when requested", async () => {
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-engine",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { resolveProviderAuthAliasMap } from "../agents/provider-auth-aliases.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "../plugins/manifest-registry-installed.js";
|
||||
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import {
|
||||
isWorkspacePluginAllowedByConfig,
|
||||
normalizePluginConfigId,
|
||||
} from "../plugins/plugin-config-trust.js";
|
||||
import { loadPluginRegistrySnapshot } from "../plugins/plugin-registry.js";
|
||||
import { hasKind } from "../plugins/slots.js";
|
||||
|
||||
const CORE_PROVIDER_AUTH_ENV_VAR_CANDIDATES = {
|
||||
@@ -76,11 +77,18 @@ function appendUniqueEnvVarCandidates(
|
||||
function resolveManifestProviderAuthEnvVarCandidates(
|
||||
params?: ProviderEnvVarLookupParams,
|
||||
): Record<string, string[]> {
|
||||
const registry = loadPluginManifestRegistry({
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
});
|
||||
const registry = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params?.config,
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env: params?.env,
|
||||
includeDisabled: true,
|
||||
});
|
||||
const candidates: Record<string, string[]> = {};
|
||||
for (const plugin of registry.plugins) {
|
||||
if (!shouldUsePluginProviderEnvVars(plugin, params)) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
loadPluginManifestRegistry,
|
||||
type PluginManifestRecord,
|
||||
} from "../plugins/manifest-registry.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 { loadBundledChannelSecretContractApi } from "./channel-contract-api.js";
|
||||
import type { SecretTargetRegistryEntry } from "./target-registry-types.js";
|
||||
|
||||
@@ -51,7 +50,11 @@ function hasWebProviderContract(
|
||||
|
||||
function listBundledWebProviderSecretTargetRegistryEntries(): SecretTargetRegistryEntry[] {
|
||||
const entries: SecretTargetRegistryEntry[] = [];
|
||||
for (const record of loadPluginManifestRegistry({}).plugins) {
|
||||
const index = loadPluginRegistrySnapshot({});
|
||||
for (const record of loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
includeDisabled: true,
|
||||
}).plugins) {
|
||||
if (record.origin !== "bundled") {
|
||||
continue;
|
||||
}
|
||||
@@ -70,7 +73,11 @@ function listBundledWebProviderSecretTargetRegistryEntries(): SecretTargetRegist
|
||||
function listChannelSecretTargetRegistryEntries(): SecretTargetRegistryEntry[] {
|
||||
const entries: SecretTargetRegistryEntry[] = [];
|
||||
|
||||
for (const record of loadPluginManifestRegistry({}).plugins) {
|
||||
const index = loadPluginRegistrySnapshot({});
|
||||
for (const record of loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
includeDisabled: true,
|
||||
}).plugins) {
|
||||
if (record.origin !== "bundled") {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user