mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 07:43:55 +00:00
Authorize plugin gateway methods against the exact registry attached to dispatch, preserving fallback behavior for dynamic methods and deleting one-off repro scripts. Fixes #92044. Co-authored-by: wangmiao0668000666 <wang.miao86@xydigit.com>
66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
|
|
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
|
import {
|
|
createGatewayMethodRegistry,
|
|
createPluginGatewayMethodDescriptor,
|
|
} from "./methods/registry.js";
|
|
import { handleGatewayRequest } from "./server-methods.js";
|
|
import type { GatewayRequestHandler } from "./server-methods/types.js";
|
|
|
|
const METHOD = "workboard.cards.dispatch";
|
|
|
|
afterEach(() => {
|
|
setActivePluginRegistry(createEmptyPluginRegistry());
|
|
});
|
|
|
|
describe("gateway method authorization", () => {
|
|
async function dispatch(scopes: string[]) {
|
|
const handler: GatewayRequestHandler = ({ respond }) => respond(true, { ok: true });
|
|
const methodRegistry = createGatewayMethodRegistry([
|
|
createPluginGatewayMethodDescriptor({
|
|
pluginId: "workboard",
|
|
name: METHOD,
|
|
handler,
|
|
scope: "operator.write",
|
|
}),
|
|
]);
|
|
const respond = vi.fn();
|
|
|
|
// Reproduce a request whose attached dispatch registry is newer than the global runtime state.
|
|
setActivePluginRegistry(createEmptyPluginRegistry());
|
|
await handleGatewayRequest({
|
|
req: { type: "req", id: "req-1", method: METHOD },
|
|
respond,
|
|
client: {
|
|
connId: "conn-1",
|
|
connect: {
|
|
role: "operator",
|
|
scopes,
|
|
client: { id: "test", version: "1", platform: "test", mode: "test" },
|
|
minProtocol: 1,
|
|
maxProtocol: 1,
|
|
},
|
|
} as Parameters<typeof handleGatewayRequest>[0]["client"],
|
|
isWebchatConnect: () => false,
|
|
context: { logGateway: { warn: vi.fn() } } as unknown as Parameters<
|
|
typeof handleGatewayRequest
|
|
>[0]["context"],
|
|
methodRegistry,
|
|
});
|
|
return respond;
|
|
}
|
|
|
|
it("authorizes from the attached registry used for dispatch", async () => {
|
|
const allowed = await dispatch(["operator.write"]);
|
|
const denied = await dispatch(["operator.read"]);
|
|
|
|
expect(allowed).toHaveBeenCalledWith(true, { ok: true });
|
|
expect(denied).toHaveBeenCalledWith(
|
|
false,
|
|
undefined,
|
|
expect.objectContaining({ message: "missing scope: operator.write" }),
|
|
);
|
|
});
|
|
});
|