mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:40:43 +00:00
fix(diffs): refresh live tool config
This commit is contained in:
@@ -192,6 +192,138 @@ describe("PlaywrightDiffScreenshotter", () => {
|
||||
});
|
||||
|
||||
describe("diffs plugin registration", () => {
|
||||
it("uses live runtime tool config through the registered tool factory", async () => {
|
||||
type RegisteredTool = {
|
||||
execute?: (toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
|
||||
};
|
||||
type HttpRouteHandler = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
) => boolean | Promise<boolean>;
|
||||
type RegisteredHttpRouteParams = Parameters<OpenClawPluginApi["registerHttpRoute"]>[0];
|
||||
|
||||
let registeredToolFactory:
|
||||
| ((ctx: OpenClawPluginToolContext) => RegisteredTool | RegisteredTool[] | null | undefined)
|
||||
| undefined;
|
||||
let registeredHttpRouteHandler: HttpRouteHandler | undefined;
|
||||
let configFile: OpenClawConfig = {
|
||||
gateway: {
|
||||
port: 18789,
|
||||
bind: "loopback",
|
||||
},
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
config: {
|
||||
viewerBaseUrl: "https://startup.example.com/openclaw",
|
||||
defaults: {
|
||||
mode: "view",
|
||||
theme: "light",
|
||||
background: false,
|
||||
layout: "split",
|
||||
showLineNumbers: false,
|
||||
diffIndicators: "classic",
|
||||
lineSpacing: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const api = createTestPluginApi({
|
||||
id: "diffs",
|
||||
name: "Diffs",
|
||||
description: "Diffs",
|
||||
source: "test",
|
||||
config: {
|
||||
gateway: {
|
||||
port: 18789,
|
||||
bind: "loopback",
|
||||
},
|
||||
},
|
||||
pluginConfig: {
|
||||
viewerBaseUrl: "https://startup.example.com/openclaw",
|
||||
defaults: {
|
||||
mode: "view",
|
||||
theme: "light",
|
||||
background: false,
|
||||
layout: "split",
|
||||
showLineNumbers: false,
|
||||
diffIndicators: "classic",
|
||||
lineSpacing: 2,
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
config: {
|
||||
loadConfig: () => configFile,
|
||||
},
|
||||
} as never,
|
||||
registerTool(tool: Parameters<OpenClawPluginApi["registerTool"]>[0]) {
|
||||
registeredToolFactory = typeof tool === "function" ? tool : () => tool;
|
||||
},
|
||||
registerHttpRoute(params: RegisteredHttpRouteParams) {
|
||||
registeredHttpRouteHandler = params.handler as HttpRouteHandler;
|
||||
},
|
||||
on: vi.fn(),
|
||||
});
|
||||
|
||||
registerDiffsPlugin(api as unknown as OpenClawPluginApi);
|
||||
|
||||
configFile = {
|
||||
...configFile,
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
config: {
|
||||
viewerBaseUrl: "https://live.example.com/gateway",
|
||||
defaults: {
|
||||
mode: "view",
|
||||
theme: "dark",
|
||||
background: true,
|
||||
layout: "unified",
|
||||
showLineNumbers: true,
|
||||
diffIndicators: "bars",
|
||||
lineSpacing: 1.6,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const registeredTool = registeredToolFactory?.({
|
||||
agentId: "main",
|
||||
sessionId: "session-456",
|
||||
messageChannel: "discord",
|
||||
agentAccountId: "default",
|
||||
}) as RegisteredTool | undefined;
|
||||
const result = await registeredTool?.execute?.("tool-1", {
|
||||
before: "one\n",
|
||||
after: "two\n",
|
||||
});
|
||||
const details = (result as { details?: Record<string, unknown> } | undefined)?.details;
|
||||
const viewerPath = String(details?.viewerPath);
|
||||
const res = createMockServerResponse();
|
||||
const handled = await registeredHttpRouteHandler?.(
|
||||
localReq({
|
||||
method: "GET",
|
||||
url: viewerPath,
|
||||
}),
|
||||
res,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(String(details?.viewerUrl)).toContain("https://live.example.com/gateway");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(String(res.body)).toContain('body data-theme="dark"');
|
||||
expect(String(res.body)).toContain('"backgroundEnabled":true');
|
||||
expect(String(res.body)).toContain('"diffStyle":"unified"');
|
||||
expect(String(res.body)).toContain('"disableLineNumbers":false');
|
||||
expect(String(res.body)).toContain('"diffIndicators":"bars"');
|
||||
expect(String(res.body)).toContain("--diffs-line-height: 24px;");
|
||||
});
|
||||
|
||||
it("uses live runtime viewer-access config through the registered HTTP handler", async () => {
|
||||
type RegisteredTool = {
|
||||
execute?: (toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
|
||||
@@ -299,12 +431,6 @@ describe("diffs plugin registration", () => {
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(String(res.body)).toContain('body data-theme="light"');
|
||||
expect(String(res.body)).toContain('"backgroundEnabled":false');
|
||||
expect(String(res.body)).toContain('"diffStyle":"split"');
|
||||
expect(String(res.body)).toContain('"disableLineNumbers":true');
|
||||
expect(String(res.body)).toContain('"diffIndicators":"classic"');
|
||||
expect(String(res.body)).toContain("--diffs-line-height: 30px;");
|
||||
expect((result as { details?: Record<string, unknown> } | undefined)?.details?.context).toEqual(
|
||||
{
|
||||
agentId: "main",
|
||||
@@ -344,6 +470,107 @@ describe("diffs plugin registration", () => {
|
||||
expect(proxiedHandled).toBe(true);
|
||||
expect(proxiedRes.statusCode).toBe(404);
|
||||
});
|
||||
|
||||
it("fails closed for remote viewer access when the live diffs plugin entry is removed", async () => {
|
||||
type RegisteredTool = {
|
||||
execute?: (toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
|
||||
};
|
||||
type HttpRouteHandler = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
) => boolean | Promise<boolean>;
|
||||
type RegisteredHttpRouteParams = Parameters<OpenClawPluginApi["registerHttpRoute"]>[0];
|
||||
|
||||
let registeredToolFactory:
|
||||
| ((ctx: OpenClawPluginToolContext) => RegisteredTool | RegisteredTool[] | null | undefined)
|
||||
| undefined;
|
||||
let registeredHttpRouteHandler: HttpRouteHandler | undefined;
|
||||
let configFile: OpenClawConfig = {
|
||||
gateway: {
|
||||
port: 18789,
|
||||
bind: "loopback",
|
||||
},
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
config: {
|
||||
security: {
|
||||
allowRemoteViewer: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const api = createTestPluginApi({
|
||||
id: "diffs",
|
||||
name: "Diffs",
|
||||
description: "Diffs",
|
||||
source: "test",
|
||||
config: {
|
||||
gateway: {
|
||||
port: 18789,
|
||||
bind: "loopback",
|
||||
},
|
||||
},
|
||||
pluginConfig: {
|
||||
security: {
|
||||
allowRemoteViewer: true,
|
||||
},
|
||||
},
|
||||
runtime: {
|
||||
config: {
|
||||
loadConfig: () => configFile,
|
||||
},
|
||||
} as never,
|
||||
registerTool(tool: Parameters<OpenClawPluginApi["registerTool"]>[0]) {
|
||||
registeredToolFactory = typeof tool === "function" ? tool : () => tool;
|
||||
},
|
||||
registerHttpRoute(params: RegisteredHttpRouteParams) {
|
||||
registeredHttpRouteHandler = params.handler as HttpRouteHandler;
|
||||
},
|
||||
on: vi.fn(),
|
||||
});
|
||||
|
||||
registerDiffsPlugin(api as unknown as OpenClawPluginApi);
|
||||
|
||||
const registeredTool = registeredToolFactory?.({
|
||||
agentId: "main",
|
||||
sessionId: "session-789",
|
||||
messageChannel: "discord",
|
||||
agentAccountId: "default",
|
||||
}) as RegisteredTool | undefined;
|
||||
const result = await registeredTool?.execute?.("tool-1", {
|
||||
before: "one\n",
|
||||
after: "two\n",
|
||||
});
|
||||
const viewerPath = String(
|
||||
(result as { details?: Record<string, unknown> } | undefined)?.details?.viewerPath,
|
||||
);
|
||||
|
||||
configFile = {
|
||||
...configFile,
|
||||
plugins: {
|
||||
entries: {},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const proxiedRes = createMockServerResponse();
|
||||
const proxiedHandled = await registeredHttpRouteHandler?.(
|
||||
localReq({
|
||||
method: "GET",
|
||||
url: viewerPath,
|
||||
headers: {
|
||||
"x-forwarded-for": "203.0.113.10",
|
||||
},
|
||||
}),
|
||||
proxiedRes,
|
||||
);
|
||||
|
||||
expect(proxiedHandled).toBe(true);
|
||||
expect(proxiedRes.statusCode).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
function createConfig(): OpenClawConfig {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import path from "node:path";
|
||||
import { resolvePluginConfigObject } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { resolvePreferredOpenClawTmpDir, type OpenClawPluginApi } from "../api.js";
|
||||
import {
|
||||
resolveDiffsPluginDefaults,
|
||||
@@ -12,24 +12,38 @@ import { DiffArtifactStore } from "./store.js";
|
||||
import { createDiffsTool } from "./tool.js";
|
||||
|
||||
export function registerDiffsPlugin(api: OpenClawPluginApi): void {
|
||||
const defaults = resolveDiffsPluginDefaults(api.pluginConfig);
|
||||
const viewerBaseUrl = resolveDiffsPluginViewerBaseUrl(api.pluginConfig);
|
||||
const store = new DiffArtifactStore({
|
||||
rootDir: path.join(resolvePreferredOpenClawTmpDir(), "openclaw-diffs"),
|
||||
logger: api.logger,
|
||||
});
|
||||
const resolveCurrentPluginConfig = () =>
|
||||
resolveLivePluginConfigObject(
|
||||
api.runtime.config?.loadConfig,
|
||||
"diffs",
|
||||
api.pluginConfig as Record<string, unknown>,
|
||||
) ?? {};
|
||||
const resolveCurrentAccessConfig = () => {
|
||||
const currentConfig = api.runtime.config?.loadConfig?.() ?? api.config;
|
||||
const pluginConfig = resolvePluginConfigObject(currentConfig, "diffs") ?? api.pluginConfig;
|
||||
const pluginConfig = resolveCurrentPluginConfig();
|
||||
return {
|
||||
allowRemoteViewer: resolveDiffsPluginSecurity(pluginConfig).allowRemoteViewer,
|
||||
trustedProxies: currentConfig.gateway?.trustedProxies,
|
||||
allowRealIpFallback: currentConfig.gateway?.allowRealIpFallback === true,
|
||||
};
|
||||
};
|
||||
const initialAccessConfig = resolveCurrentAccessConfig();
|
||||
|
||||
api.registerTool(
|
||||
(ctx) => createDiffsTool({ api, store, defaults, viewerBaseUrl, context: ctx }),
|
||||
(ctx) => {
|
||||
const pluginConfig = resolveCurrentPluginConfig();
|
||||
return createDiffsTool({
|
||||
api,
|
||||
store,
|
||||
defaults: resolveDiffsPluginDefaults(pluginConfig),
|
||||
viewerBaseUrl: resolveDiffsPluginViewerBaseUrl(pluginConfig),
|
||||
context: ctx,
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "diffs",
|
||||
},
|
||||
@@ -41,9 +55,9 @@ export function registerDiffsPlugin(api: OpenClawPluginApi): void {
|
||||
handler: createDiffsHttpHandler({
|
||||
store,
|
||||
logger: api.logger,
|
||||
allowRemoteViewer: resolveDiffsPluginSecurity(api.pluginConfig).allowRemoteViewer,
|
||||
trustedProxies: api.config.gateway?.trustedProxies,
|
||||
allowRealIpFallback: api.config.gateway?.allowRealIpFallback === true,
|
||||
allowRemoteViewer: initialAccessConfig.allowRemoteViewer,
|
||||
trustedProxies: initialAccessConfig.trustedProxies,
|
||||
allowRealIpFallback: initialAccessConfig.allowRealIpFallback,
|
||||
resolveAccessConfig: resolveCurrentAccessConfig,
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user