From 17fcbcefbc5c2d9c7dbddadcf9a4ca77ec7bbe5f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Apr 2026 23:55:05 +0100 Subject: [PATCH] refactor: share plugin config trust helpers --- src/agents/provider-auth-aliases.ts | 57 +++++---------------------- src/plugins/plugin-config-trust.ts | 56 ++++++++++++++++++++++++++ src/secrets/provider-env-vars.ts | 61 ++++++----------------------- 3 files changed, 77 insertions(+), 97 deletions(-) create mode 100644 src/plugins/plugin-config-trust.ts diff --git a/src/agents/provider-auth-aliases.ts b/src/agents/provider-auth-aliases.ts index 4e8e73407ff..c3ebeb90989 100644 --- a/src/agents/provider-auth-aliases.ts +++ b/src/agents/provider-auth-aliases.ts @@ -1,8 +1,11 @@ import type { OpenClawConfig } from "../config/types.openclaw.js"; import { loadPluginManifestRegistry } from "../plugins/manifest-registry.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 { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; import { normalizeProviderId } from "./provider-id.js"; export type ProviderAuthAliasLookupParams = { @@ -17,8 +20,6 @@ type ProviderAuthAliasCandidate = { target: string; }; -type PluginEntriesConfig = NonNullable["entries"]>; - const PROVIDER_AUTH_ALIAS_ORIGIN_PRIORITY: Readonly> = { config: 0, bundled: 1, @@ -33,54 +34,16 @@ function resolveProviderAuthAliasOriginPriority(origin: PluginOrigin | undefined return PROVIDER_AUTH_ALIAS_ORIGIN_PRIORITY[origin] ?? Number.MAX_SAFE_INTEGER; } -function normalizePluginConfigId(id: unknown): string { - return normalizeOptionalLowercaseString(id) ?? ""; -} - -function hasPluginId(list: unknown, pluginId: string): boolean { - return Array.isArray(list) && list.some((entry) => normalizePluginConfigId(entry) === pluginId); -} - -function findPluginEntry( - entries: PluginEntriesConfig | undefined, - pluginId: string, -): { enabled?: boolean } | undefined { - if (!entries || typeof entries !== "object" || Array.isArray(entries)) { - return undefined; - } - for (const [key, value] of Object.entries(entries)) { - if (normalizePluginConfigId(key) !== pluginId) { - continue; - } - return value && typeof value === "object" && !Array.isArray(value) - ? (value as { enabled?: boolean }) - : {}; - } - return undefined; -} - function isWorkspacePluginTrustedForAuthAliases( plugin: PluginManifestRecord, config: OpenClawConfig | undefined, ): boolean { - const pluginsConfig = config?.plugins; - if (pluginsConfig?.enabled === false) { - return false; - } - - const pluginId = normalizePluginConfigId(plugin.id); - if (!pluginId || hasPluginId(pluginsConfig?.deny, pluginId)) { - return false; - } - - const entry = findPluginEntry(pluginsConfig?.entries, pluginId); - if (entry?.enabled === false) { - return false; - } - if (entry?.enabled === true || hasPluginId(pluginsConfig?.allow, pluginId)) { - return true; - } - return normalizePluginConfigId(pluginsConfig?.slots?.contextEngine) === pluginId; + return isWorkspacePluginAllowedByConfig({ + config, + isImplicitlyAllowed: (pluginId) => + normalizePluginConfigId(config?.plugins?.slots?.contextEngine) === pluginId, + plugin, + }); } function shouldUsePluginAuthAliases( diff --git a/src/plugins/plugin-config-trust.ts b/src/plugins/plugin-config-trust.ts new file mode 100644 index 00000000000..7ec9f6a0265 --- /dev/null +++ b/src/plugins/plugin-config-trust.ts @@ -0,0 +1,56 @@ +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; +import type { PluginManifestRecord } from "./manifest-registry.js"; + +type PluginEntriesConfig = NonNullable["entries"]>; + +export function normalizePluginConfigId(id: unknown): string { + return normalizeOptionalLowercaseString(id) ?? ""; +} + +function hasPluginConfigId(list: unknown, pluginId: string): boolean { + return Array.isArray(list) && list.some((entry) => normalizePluginConfigId(entry) === pluginId); +} + +function findPluginConfigEntry( + entries: PluginEntriesConfig | undefined, + pluginId: string, +): { enabled?: boolean } | undefined { + if (!entries || typeof entries !== "object" || Array.isArray(entries)) { + return undefined; + } + for (const [key, value] of Object.entries(entries)) { + if (normalizePluginConfigId(key) !== pluginId) { + continue; + } + return value && typeof value === "object" && !Array.isArray(value) + ? (value as { enabled?: boolean }) + : {}; + } + return undefined; +} + +export function isWorkspacePluginAllowedByConfig(params: { + config: OpenClawConfig | undefined; + isImplicitlyAllowed?: (pluginId: string) => boolean; + plugin: PluginManifestRecord; +}): boolean { + const pluginsConfig = params.config?.plugins; + if (pluginsConfig?.enabled === false) { + return false; + } + + const pluginId = normalizePluginConfigId(params.plugin.id); + if (!pluginId || hasPluginConfigId(pluginsConfig?.deny, pluginId)) { + return false; + } + + const entry = findPluginConfigEntry(pluginsConfig?.entries, pluginId); + if (entry?.enabled === false) { + return false; + } + if (entry?.enabled === true || hasPluginConfigId(pluginsConfig?.allow, pluginId)) { + return true; + } + return params.isImplicitlyAllowed?.(pluginId) ?? false; +} diff --git a/src/secrets/provider-env-vars.ts b/src/secrets/provider-env-vars.ts index f2c929339ca..82402aac36a 100644 --- a/src/secrets/provider-env-vars.ts +++ b/src/secrets/provider-env-vars.ts @@ -2,8 +2,11 @@ import { resolveProviderAuthAliasMap } from "../agents/provider-auth-aliases.js" import type { OpenClawConfig } from "../config/types.openclaw.js"; import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js"; import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; +import { + isWorkspacePluginAllowedByConfig, + normalizePluginConfigId, +} from "../plugins/plugin-config-trust.js"; import { hasKind } from "../plugins/slots.js"; -import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js"; const CORE_PROVIDER_AUTH_ENV_VAR_CANDIDATES = { anthropic: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"], @@ -25,59 +28,17 @@ export type ProviderEnvVarLookupParams = { includeUntrustedWorkspacePlugins?: boolean; }; -type PluginEntriesConfig = NonNullable["entries"]>; - -function normalizePluginConfigId(id: unknown): string { - return normalizeOptionalLowercaseString(id) ?? ""; -} - -function hasPluginId(list: unknown, pluginId: string): boolean { - return Array.isArray(list) && list.some((entry) => normalizePluginConfigId(entry) === pluginId); -} - -function findPluginEntry( - entries: PluginEntriesConfig | undefined, - pluginId: string, -): { enabled?: boolean } | undefined { - if (!entries || typeof entries !== "object" || Array.isArray(entries)) { - return undefined; - } - for (const [key, value] of Object.entries(entries)) { - if (normalizePluginConfigId(key) !== pluginId) { - continue; - } - return value && typeof value === "object" && !Array.isArray(value) - ? (value as { enabled?: boolean }) - : {}; - } - return undefined; -} - function isWorkspacePluginTrustedForProviderEnvVars( plugin: PluginManifestRecord, config: OpenClawConfig | undefined, ): boolean { - const pluginsConfig = config?.plugins; - if (pluginsConfig?.enabled === false) { - return false; - } - - const pluginId = normalizePluginConfigId(plugin.id); - if (!pluginId || hasPluginId(pluginsConfig?.deny, pluginId)) { - return false; - } - - const entry = findPluginEntry(pluginsConfig?.entries, pluginId); - if (entry?.enabled === false) { - return false; - } - if (entry?.enabled === true || hasPluginId(pluginsConfig?.allow, pluginId)) { - return true; - } - return ( - hasKind(plugin.kind, "context-engine") && - normalizePluginConfigId(pluginsConfig?.slots?.contextEngine) === pluginId - ); + return isWorkspacePluginAllowedByConfig({ + config, + isImplicitlyAllowed: (pluginId) => + hasKind(plugin.kind, "context-engine") && + normalizePluginConfigId(config?.plugins?.slots?.contextEngine) === pluginId, + plugin, + }); } function shouldUsePluginProviderEnvVars(