fix: respect approval request filters in ambiguity checks

This commit is contained in:
Gustavo Madeira Santana
2026-04-03 13:53:41 -04:00
parent 4bbd67c21e
commit e588a363f9
4 changed files with 168 additions and 16 deletions

View File

@@ -455,7 +455,7 @@ describe("matrix exec approvals", () => {
).toBe(false);
});
it("ignores disabled matrix accounts when checking foreign-channel ambiguity", () => {
it("uses request filters when checking foreign-channel matrix ambiguity", () => {
const cfg = {
channels: {
matrix: {
@@ -467,16 +467,17 @@ describe("matrix exec approvals", () => {
execApprovals: {
enabled: true,
approvers: ["@owner:example.org"],
agentFilter: ["ops-agent"],
},
},
ops: {
enabled: false,
homeserver: "https://matrix.example.org",
userId: "@bot-ops:example.org",
accessToken: "tok-ops",
execApprovals: {
enabled: true,
approvers: ["@owner:example.org"],
agentFilter: ["other-agent"],
},
},
},
@@ -511,4 +512,61 @@ describe("matrix exec approvals", () => {
}),
).toBe(false);
});
it("ignores disabled matrix accounts when checking foreign-channel ambiguity", () => {
const cfg = {
channels: {
matrix: {
accounts: {
default: {
homeserver: "https://matrix.example.org",
userId: "@bot-default:example.org",
accessToken: "tok-default",
execApprovals: {
enabled: true,
approvers: ["@owner:example.org"],
},
},
ops: {
enabled: false,
homeserver: "https://matrix.example.org",
userId: "@bot-ops:example.org",
accessToken: "tok-ops",
execApprovals: {
enabled: true,
approvers: ["@owner:example.org"],
},
},
},
},
},
} as OpenClawConfig;
const request = {
id: "req-7",
request: {
command: "echo hi",
agentId: "ops-agent",
sessionKey: "agent:ops-agent:missing",
turnSourceChannel: "slack",
turnSourceTo: "channel:C123",
},
createdAtMs: 0,
expiresAtMs: 1000,
};
expect(
shouldHandleMatrixExecApprovalRequest({
cfg,
accountId: "default",
request,
}),
).toBe(true);
expect(
shouldHandleMatrixExecApprovalRequest({
cfg,
accountId: "ops",
request,
}),
).toBe(false);
});
});

View File

@@ -3,6 +3,7 @@ import {
getExecApprovalReplyMetadata,
isChannelExecApprovalClientEnabledFromConfig,
isChannelExecApprovalTargetRecipient,
matchesApprovalRequestFilters,
resolveApprovalRequestChannelAccountId,
resolveApprovalApprovers,
} from "openclaw/plugin-sdk/approval-runtime";
@@ -40,16 +41,30 @@ function resolveMatrixExecApprovalConfig(params: {
};
}
function countMatrixExecApprovalHandlerAccounts(cfg: OpenClawConfig): number {
return listMatrixAccountIds(cfg).filter((accountId) => {
function countMatrixExecApprovalEligibleAccounts(params: {
cfg: OpenClawConfig;
request: ApprovalRequest;
}): number {
return listMatrixAccountIds(params.cfg).filter((accountId) => {
const account = resolveMatrixAccount({ cfg, accountId });
if (!account.enabled || !account.configured) {
return false;
}
return isChannelExecApprovalClientEnabledFromConfig({
enabled: resolveMatrixExecApprovalConfig({ cfg, accountId }).enabled,
approverCount: getMatrixExecApprovalApprovers({ cfg, accountId }).length,
const config = resolveMatrixExecApprovalConfig({
cfg: params.cfg,
accountId,
});
return (
isChannelExecApprovalClientEnabledFromConfig({
enabled: config.enabled,
approverCount: getMatrixExecApprovalApprovers({ cfg: params.cfg, accountId }).length,
}) &&
matchesApprovalRequestFilters({
request: params.request.request,
agentFilter: config.agentFilter,
sessionFilter: config.sessionFilter,
})
);
}).length;
}
@@ -65,7 +80,12 @@ function matchesMatrixRequestAccount(params: {
channel: "matrix",
});
if (turnSourceChannel && turnSourceChannel !== "matrix" && !boundAccountId) {
return countMatrixExecApprovalHandlerAccounts(params.cfg) <= 1;
return (
countMatrixExecApprovalEligibleAccounts({
cfg: params.cfg,
request: params.request,
}) <= 1
);
}
return (
!boundAccountId ||

View File

@@ -292,6 +292,59 @@ describe("telegram exec approvals", () => {
).toBe(false);
});
it("uses request filters when checking foreign-channel telegram ambiguity", () => {
const cfg = {
channels: {
telegram: {
accounts: {
default: {
botToken: "tok-default",
execApprovals: {
enabled: true,
approvers: ["123"],
agentFilter: ["ops"],
},
},
ops: {
botToken: "tok-ops",
execApprovals: {
enabled: true,
approvers: ["123"],
agentFilter: ["other"],
},
},
},
},
},
} as OpenClawConfig;
const request = {
id: "req-5",
request: {
command: "echo hi",
sessionKey: "agent:ops:missing",
turnSourceChannel: "slack",
turnSourceTo: "channel:C123",
},
createdAtMs: 0,
expiresAtMs: 1000,
};
expect(
shouldHandleTelegramExecApprovalRequest({
cfg,
accountId: "default",
request,
}),
).toBe(true);
expect(
shouldHandleTelegramExecApprovalRequest({
cfg,
accountId: "ops",
request,
}),
).toBe(false);
});
it("ignores disabled telegram accounts when checking foreign-channel ambiguity", () => {
const cfg = {
channels: {
@@ -317,7 +370,7 @@ describe("telegram exec approvals", () => {
},
} as OpenClawConfig;
const request = {
id: "req-5",
id: "req-6",
request: {
command: "echo hi",
sessionKey: "agent:ops:missing",

View File

@@ -2,6 +2,7 @@ import {
createChannelExecApprovalProfile,
isChannelExecApprovalClientEnabledFromConfig,
isChannelExecApprovalTargetRecipient,
matchesApprovalRequestFilters,
resolveApprovalRequestChannelAccountId,
resolveApprovalApprovers,
} from "openclaw/plugin-sdk/approval-runtime";
@@ -73,16 +74,31 @@ export function isTelegramExecApprovalTargetRecipient(params: {
});
}
function countTelegramExecApprovalHandlerAccounts(cfg: OpenClawConfig): number {
return listTelegramAccountIds(cfg).filter((accountId) => {
const account = resolveTelegramAccount({ cfg, accountId });
function countTelegramExecApprovalEligibleAccounts(params: {
cfg: OpenClawConfig;
request: ExecApprovalRequest | PluginApprovalRequest;
}): number {
return listTelegramAccountIds(params.cfg).filter((accountId) => {
const account = resolveTelegramAccount({ cfg: params.cfg, accountId });
if (!account.enabled || account.tokenSource === "none") {
return false;
}
return isChannelExecApprovalClientEnabledFromConfig({
enabled: resolveTelegramExecApprovalConfig({ cfg, accountId })?.enabled,
approverCount: getTelegramExecApprovalApprovers({ cfg, accountId }).length,
const config = resolveTelegramExecApprovalConfig({
cfg: params.cfg,
accountId,
});
return (
isChannelExecApprovalClientEnabledFromConfig({
enabled: config?.enabled,
approverCount: getTelegramExecApprovalApprovers({ cfg: params.cfg, accountId }).length,
}) &&
matchesApprovalRequestFilters({
request: params.request.request,
agentFilter: config?.agentFilter,
sessionFilter: config?.sessionFilter,
fallbackAgentIdFromSessionKey: true,
})
);
}).length;
}
@@ -98,7 +114,12 @@ function matchesTelegramRequestAccount(params: {
channel: "telegram",
});
if (turnSourceChannel && turnSourceChannel !== "telegram" && !boundAccountId) {
return countTelegramExecApprovalHandlerAccounts(params.cfg) <= 1;
return (
countTelegramExecApprovalEligibleAccounts({
cfg: params.cfg,
request: params.request,
}) <= 1
);
}
return (
!boundAccountId ||