fix(approvals): gate /approve by gateway scopes
This commit is contained in:
committed by
Peter Steinberger
parent
66d8117d44
commit
efe2a464af
@@ -79,4 +79,23 @@ describe("/approve command", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects gateway clients without approvals scope", async () => {
|
||||
const cfg = {
|
||||
commands: { text: true },
|
||||
} as OpenClawConfig;
|
||||
const params = buildParams("/approve abc allow-once", cfg, {
|
||||
Provider: "webchat",
|
||||
Surface: "webchat",
|
||||
GatewayClientScopes: ["operator.write"],
|
||||
});
|
||||
|
||||
const mockCallGateway = vi.mocked(callGateway);
|
||||
mockCallGateway.mockResolvedValueOnce({ ok: true });
|
||||
|
||||
const result = await handleCommands(params);
|
||||
expect(result.shouldContinue).toBe(false);
|
||||
expect(result.reply?.text).toContain("requires operator.approvals");
|
||||
expect(mockCallGateway).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import type { CommandHandler } from "./commands-types.js";
|
||||
import { callGateway } from "../../gateway/call.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
|
||||
import {
|
||||
GATEWAY_CLIENT_MODES,
|
||||
GATEWAY_CLIENT_NAMES,
|
||||
isInternalMessageChannel,
|
||||
} from "../../utils/message-channel.js";
|
||||
|
||||
const COMMAND = "/approve";
|
||||
|
||||
@@ -82,6 +86,20 @@ export const handleApproveCommand: CommandHandler = async (params, allowTextComm
|
||||
return { shouldContinue: false, reply: { text: parsed.error } };
|
||||
}
|
||||
|
||||
if (isInternalMessageChannel(params.command.channel)) {
|
||||
const scopes = params.ctx.GatewayClientScopes ?? [];
|
||||
const hasApprovals = scopes.includes("operator.approvals") || scopes.includes("operator.admin");
|
||||
if (!hasApprovals) {
|
||||
logVerbose("Ignoring /approve from gateway client missing operator.approvals.");
|
||||
return {
|
||||
shouldContinue: false,
|
||||
reply: {
|
||||
text: "❌ /approve requires operator.approvals for gateway clients.",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedBy = buildResolvedByLabel(params);
|
||||
try {
|
||||
await callGateway({
|
||||
|
||||
@@ -101,6 +101,8 @@ export type MsgContext = {
|
||||
CommandAuthorized?: boolean;
|
||||
CommandSource?: "text" | "native";
|
||||
CommandTargetSessionKey?: string;
|
||||
/** Gateway client scopes when the message originates from the gateway. */
|
||||
GatewayClientScopes?: string[];
|
||||
/** Thread identifier (Telegram topic id or Matrix thread event id). */
|
||||
MessageThreadId?: string | number;
|
||||
/** Telegram forum supergroup marker. */
|
||||
|
||||
@@ -470,6 +470,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
SenderId: clientInfo?.id,
|
||||
SenderName: clientInfo?.displayName,
|
||||
SenderUsername: clientInfo?.displayName,
|
||||
GatewayClientScopes: client?.connect?.scopes,
|
||||
};
|
||||
|
||||
const agentId = resolveSessionAgentId({
|
||||
|
||||
Reference in New Issue
Block a user