mirror of https://github.com/openclaw/openclaw.git
Matrix: honor action gates per resolved account
This commit is contained in:
parent
65b28384d1
commit
b4b9625914
|
|
@ -78,4 +78,44 @@ describe("matrixMessageActions", () => {
|
|||
expect(actions).toContain("set-profile");
|
||||
expect(supportsAction!({ action: "set-profile" } as never)).toBe(true);
|
||||
});
|
||||
|
||||
it("hides gated actions when the default Matrix account disables them", () => {
|
||||
const actions = matrixMessageActions.listActions!({
|
||||
cfg: {
|
||||
channels: {
|
||||
matrix: {
|
||||
defaultAccount: "assistant",
|
||||
actions: {
|
||||
messages: true,
|
||||
reactions: true,
|
||||
pins: true,
|
||||
profile: true,
|
||||
memberInfo: true,
|
||||
channelInfo: true,
|
||||
verification: true,
|
||||
},
|
||||
accounts: {
|
||||
assistant: {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "token",
|
||||
encryption: true,
|
||||
actions: {
|
||||
messages: false,
|
||||
reactions: false,
|
||||
pins: false,
|
||||
profile: false,
|
||||
memberInfo: false,
|
||||
channelInfo: false,
|
||||
verification: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as CoreConfig,
|
||||
} as never);
|
||||
|
||||
expect(actions).toEqual(["poll", "poll-vote"]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
type ChannelMessageActionName,
|
||||
type ChannelToolSend,
|
||||
} from "openclaw/plugin-sdk/matrix";
|
||||
import { resolveMatrixAccount } from "./matrix/accounts.js";
|
||||
import { resolveDefaultMatrixAccountId, resolveMatrixAccount } from "./matrix/accounts.js";
|
||||
import { handleMatrixAction } from "./tool-actions.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
|
|
@ -28,44 +28,56 @@ const MATRIX_PLUGIN_HANDLED_ACTIONS = new Set<ChannelMessageActionName>([
|
|||
"permissions",
|
||||
]);
|
||||
|
||||
function createMatrixExposedActions() {
|
||||
return new Set<ChannelMessageActionName>(["poll", ...MATRIX_PLUGIN_HANDLED_ACTIONS]);
|
||||
function createMatrixExposedActions(params: {
|
||||
gate: ReturnType<typeof createActionGate>;
|
||||
encryptionEnabled: boolean;
|
||||
}) {
|
||||
const actions = new Set<ChannelMessageActionName>(["poll", "poll-vote"]);
|
||||
if (params.gate("messages")) {
|
||||
actions.add("send");
|
||||
actions.add("read");
|
||||
actions.add("edit");
|
||||
actions.add("delete");
|
||||
}
|
||||
if (params.gate("reactions")) {
|
||||
actions.add("react");
|
||||
actions.add("reactions");
|
||||
}
|
||||
if (params.gate("pins")) {
|
||||
actions.add("pin");
|
||||
actions.add("unpin");
|
||||
actions.add("list-pins");
|
||||
}
|
||||
if (params.gate("profile")) {
|
||||
actions.add("set-profile");
|
||||
}
|
||||
if (params.gate("memberInfo")) {
|
||||
actions.add("member-info");
|
||||
}
|
||||
if (params.gate("channelInfo")) {
|
||||
actions.add("channel-info");
|
||||
}
|
||||
if (params.encryptionEnabled && params.gate("verification")) {
|
||||
actions.add("permissions");
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
export const matrixMessageActions: ChannelMessageActionAdapter = {
|
||||
listActions: ({ cfg }) => {
|
||||
const account = resolveMatrixAccount({ cfg: cfg as CoreConfig });
|
||||
const resolvedCfg = cfg as CoreConfig;
|
||||
const account = resolveMatrixAccount({
|
||||
cfg: resolvedCfg,
|
||||
accountId: resolveDefaultMatrixAccountId(resolvedCfg),
|
||||
});
|
||||
if (!account.enabled || !account.configured) {
|
||||
return [];
|
||||
}
|
||||
const gate = createActionGate((cfg as CoreConfig).channels?.["matrix"]?.actions);
|
||||
const actions = createMatrixExposedActions();
|
||||
if (gate("reactions")) {
|
||||
actions.add("react");
|
||||
actions.add("reactions");
|
||||
}
|
||||
if (gate("messages")) {
|
||||
actions.add("read");
|
||||
actions.add("edit");
|
||||
actions.add("delete");
|
||||
}
|
||||
if (gate("pins")) {
|
||||
actions.add("pin");
|
||||
actions.add("unpin");
|
||||
actions.add("list-pins");
|
||||
}
|
||||
if (gate("profile")) {
|
||||
actions.add("set-profile");
|
||||
}
|
||||
if (gate("memberInfo")) {
|
||||
actions.add("member-info");
|
||||
}
|
||||
if (gate("channelInfo")) {
|
||||
actions.add("channel-info");
|
||||
}
|
||||
if (account.config.encryption === true && gate("verification")) {
|
||||
actions.add("permissions");
|
||||
}
|
||||
const gate = createActionGate(account.config.actions);
|
||||
const actions = createMatrixExposedActions({
|
||||
gate,
|
||||
encryptionEnabled: account.config.encryption === true,
|
||||
});
|
||||
return Array.from(actions);
|
||||
},
|
||||
supportsAction: ({ action }) => MATRIX_PLUGIN_HANDLED_ACTIONS.has(action),
|
||||
|
|
|
|||
|
|
@ -281,4 +281,33 @@ describe("handleMatrixAction pollVote", () => {
|
|||
avatarPath: "/tmp/avatar.jpg",
|
||||
});
|
||||
});
|
||||
|
||||
it("respects account-scoped action overrides when gating direct tool actions", async () => {
|
||||
await expect(
|
||||
handleMatrixAction(
|
||||
{
|
||||
action: "sendMessage",
|
||||
accountId: "ops",
|
||||
to: "room:!room:example",
|
||||
content: "hello",
|
||||
},
|
||||
{
|
||||
channels: {
|
||||
matrix: {
|
||||
actions: {
|
||||
messages: true,
|
||||
},
|
||||
accounts: {
|
||||
ops: {
|
||||
actions: {
|
||||
messages: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as CoreConfig,
|
||||
),
|
||||
).rejects.toThrow("Matrix messages are disabled.");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
readStringArrayParam,
|
||||
readStringParam,
|
||||
} from "openclaw/plugin-sdk/matrix";
|
||||
import { resolveMatrixAccountConfig } from "./matrix/accounts.js";
|
||||
import {
|
||||
bootstrapMatrixVerification,
|
||||
acceptMatrixVerification,
|
||||
|
|
@ -131,7 +132,7 @@ export async function handleMatrixAction(
|
|||
): Promise<AgentToolResult<unknown>> {
|
||||
const action = readStringParam(params, "action", { required: true });
|
||||
const accountId = readStringParam(params, "accountId") ?? undefined;
|
||||
const isActionEnabled = createActionGate(cfg.channels?.["matrix"]?.actions);
|
||||
const isActionEnabled = createActionGate(resolveMatrixAccountConfig({ cfg, accountId }).actions);
|
||||
const clientOpts = accountId ? { accountId } : {};
|
||||
|
||||
if (reactionActions.has(action)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue