refactor: share command config resolution

This commit is contained in:
Peter Steinberger
2026-04-06 07:40:23 +01:00
parent bb01e49192
commit f7833376ea
8 changed files with 150 additions and 46 deletions

View File

@@ -0,0 +1,82 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
resolveCommandSecretRefsViaGateway: vi.fn(),
applyPluginAutoEnable: vi.fn(),
}));
vi.mock("./command-secret-gateway.js", () => ({
resolveCommandSecretRefsViaGateway: mocks.resolveCommandSecretRefsViaGateway,
}));
vi.mock("../config/plugin-auto-enable.js", () => ({
applyPluginAutoEnable: mocks.applyPluginAutoEnable,
}));
import { resolveCommandConfigWithSecrets } from "./command-config-resolution.js";
describe("resolveCommandConfigWithSecrets", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("logs diagnostics and preserves resolved config when auto-enable is off", async () => {
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as const;
const config = { channels: {} };
const resolvedConfig = { channels: { telegram: {} } };
const targetIds = new Set(["channels.telegram.token"]);
mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({
resolvedConfig,
diagnostics: ["resolved channels.telegram.token"],
});
const result = await resolveCommandConfigWithSecrets({
config,
commandName: "status",
targetIds,
mode: "read_only_status",
runtime,
});
expect(mocks.resolveCommandSecretRefsViaGateway).toHaveBeenCalledWith({
config,
commandName: "status",
targetIds,
mode: "read_only_status",
});
expect(runtime.log).toHaveBeenCalledWith("[secrets] resolved channels.telegram.token");
expect(mocks.applyPluginAutoEnable).not.toHaveBeenCalled();
expect(result).toEqual({
resolvedConfig,
effectiveConfig: resolvedConfig,
diagnostics: ["resolved channels.telegram.token"],
});
});
it("returns auto-enabled config when requested", async () => {
const resolvedConfig = { channels: {} };
const effectiveConfig = { channels: {}, plugins: { allow: ["telegram"] } };
mocks.resolveCommandSecretRefsViaGateway.mockResolvedValue({
resolvedConfig,
diagnostics: [],
});
mocks.applyPluginAutoEnable.mockReturnValue({
config: effectiveConfig,
changes: ["enabled telegram"],
});
const result = await resolveCommandConfigWithSecrets({
config: resolvedConfig,
commandName: "message",
targetIds: new Set(["channels.telegram.token"]),
autoEnable: true,
env: { OPENCLAW_AUTO_ENABLE: "1" } as NodeJS.ProcessEnv,
});
expect(mocks.applyPluginAutoEnable).toHaveBeenCalledWith({
config: resolvedConfig,
env: { OPENCLAW_AUTO_ENABLE: "1" },
});
expect(result.effectiveConfig).toBe(effectiveConfig);
});
});

View File

@@ -0,0 +1,46 @@
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
import type { OpenClawConfig } from "../config/types.js";
import type { RuntimeEnv } from "../runtime.js";
import {
type CommandSecretResolutionMode,
resolveCommandSecretRefsViaGateway,
} from "./command-secret-gateway.js";
export async function resolveCommandConfigWithSecrets<TConfig extends OpenClawConfig>(params: {
config: TConfig;
commandName: string;
targetIds: Set<string>;
mode?: CommandSecretResolutionMode;
allowedPaths?: Set<string>;
runtime?: RuntimeEnv;
autoEnable?: boolean;
env?: NodeJS.ProcessEnv;
}): Promise<{
resolvedConfig: TConfig;
effectiveConfig: TConfig;
diagnostics: string[];
}> {
const { resolvedConfig, diagnostics } = await resolveCommandSecretRefsViaGateway({
config: params.config,
commandName: params.commandName,
targetIds: params.targetIds,
...(params.mode ? { mode: params.mode } : {}),
...(params.allowedPaths ? { allowedPaths: params.allowedPaths } : {}),
});
if (params.runtime) {
for (const entry of diagnostics) {
params.runtime.log(`[secrets] ${entry}`);
}
}
const effectiveConfig = params.autoEnable
? applyPluginAutoEnable({
config: resolvedConfig,
env: params.env ?? process.env,
}).config
: resolvedConfig;
return {
resolvedConfig: resolvedConfig as TConfig,
effectiveConfig: effectiveConfig as TConfig,
diagnostics,
};
}