Files
openclaw/src/plugins/plugin-lookup-table.ts
Peter Steinberger b61619e03c fix(gateway): dev mode suppresses ambient channel env auto-configuration (#112011)
Channel plugins declare package env triggers in manifests, and ambient
environment variables count as "channel configured". A dev gateway
(gateway run --dev) inherits the operator's shell, so real channel
credentials silently configured channels and could connect development
instances to live services (observed with reef and a Telegram-range
connection during isolated stress testing).

Dev mode now drops presence signals whose only sources are env or
manifest-env across activation planning, auto-enable, autostart, health
recovery, readiness, reloads, and startup warnings. Explicit
channels.<id> config still works, --dev-ambient-channels restores the
old behavior, and startup logs the suppressed channel ids once. Non-dev
gateways are unchanged.
2026-07-20 19:28:07 -07:00

120 lines
4.1 KiB
TypeScript

/** Builds plugin lookup tables keyed by manifest ids, channels, providers, and commands. */
import type { AmbientEnvTriggerPolicy } from "../channels/config-presence.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import {
createGatewayStartupMetadataPluginIdScope,
isMetadataSnapshotScopedForGatewayStartup,
resolveGatewayStartupPluginPlanFromRegistry,
type GatewayStartupPluginPlan,
} from "./channel-plugin-ids.js";
import {
isPluginMetadataSnapshotCompatible,
resolvePluginMetadataSnapshot,
type PluginMetadataSnapshot,
} from "./plugin-metadata-snapshot.js";
import type { PluginRegistrySnapshot } from "./plugin-registry-snapshot.js";
import { normalizeWorkerProviderIds } from "./worker-provider-registry.js";
type PluginLookUpTableMetrics = PluginMetadataSnapshot["metrics"] & {
startupPlanMs: number;
startupPluginCount: number;
deferredChannelPluginCount: number;
};
export type PluginLookUpTable = PluginMetadataSnapshot & {
startup: GatewayStartupPluginPlan;
workerProviderIds: readonly string[];
metrics: PluginLookUpTableMetrics;
};
type LoadPluginLookUpTableParams = {
config: OpenClawConfig;
activationSourceConfig?: OpenClawConfig;
workspaceDir?: string;
env: NodeJS.ProcessEnv;
index?: PluginRegistrySnapshot;
metadataSnapshot?: PluginMetadataSnapshot;
workerProviderIds?: readonly string[];
ambientEnvTriggers?: AmbientEnvTriggerPolicy;
};
const lookupTableMemoBySnapshot = new WeakMap<
PluginMetadataSnapshot,
Map<string, PluginLookUpTable>
>();
export function loadPluginLookUpTable(params: LoadPluginLookUpTableParams): PluginLookUpTable {
const requestedSnapshotConfig = params.activationSourceConfig ?? params.config;
const workerProviderIds = normalizeWorkerProviderIds(params.workerProviderIds ?? []);
const pluginIdScope = createGatewayStartupMetadataPluginIdScope({
config: params.config,
...(params.activationSourceConfig !== undefined
? { activationSourceConfig: params.activationSourceConfig }
: {}),
env: params.env,
workerProviderIds,
ambientEnvTriggers: params.ambientEnvTriggers,
});
const metadataSnapshot =
params.metadataSnapshot &&
isPluginMetadataSnapshotCompatible({
snapshot: params.metadataSnapshot,
config: requestedSnapshotConfig,
env: params.env,
allowScopedSnapshot: true,
workspaceDir: params.workspaceDir,
index: params.index,
}) &&
isMetadataSnapshotScopedForGatewayStartup({
metadataSnapshot: params.metadataSnapshot,
pluginIdScope,
})
? params.metadataSnapshot
: resolvePluginMetadataSnapshot({
config: requestedSnapshotConfig,
workspaceDir: params.workspaceDir,
env: params.env,
allowWorkspaceScopedCurrent: params.workspaceDir === undefined,
...(params.index ? { index: params.index } : {}),
pluginIdScope,
});
const memoKey = pluginIdScope.key;
const memo = lookupTableMemoBySnapshot.get(metadataSnapshot)?.get(memoKey);
if (memo) {
return memo;
}
const { index, manifestRegistry } = metadataSnapshot;
const startupPlanStartedAt = performance.now();
const startup = resolveGatewayStartupPluginPlanFromRegistry({
config: params.config,
...(params.activationSourceConfig !== undefined
? { activationSourceConfig: params.activationSourceConfig }
: {}),
env: params.env,
index,
manifestRegistry,
workerProviderIds,
ambientEnvTriggers: params.ambientEnvTriggers,
});
const startupPlanMs = performance.now() - startupPlanStartedAt;
const table: PluginLookUpTable = {
...metadataSnapshot,
startup,
workerProviderIds,
metrics: {
...metadataSnapshot.metrics,
startupPlanMs,
totalMs: metadataSnapshot.metrics.totalMs + startupPlanMs,
startupPluginCount: startup.pluginIds.length,
deferredChannelPluginCount: startup.configuredDeferredChannelPluginIds.length,
},
};
let memoByKey = lookupTableMemoBySnapshot.get(metadataSnapshot);
if (!memoByKey) {
memoByKey = new Map();
lookupTableMemoBySnapshot.set(metadataSnapshot, memoByKey);
}
memoByKey.set(memoKey, table);
return table;
}