fix(approvals): require explicit chat exec enablement

This commit is contained in:
Vincent Koc
2026-04-23 11:50:22 -07:00
parent 7651a03424
commit 527d7211e0
6 changed files with 25 additions and 9 deletions

View File

@@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Approvals/security: require explicit chat exec-approval enablement instead of auto-enabling approval clients just because approvers resolve from config or owner allowlists. (#70715) Thanks @vincentkoc.
- Discord/security: keep native slash-command channel policy from bypassing configured owner or member restrictions, while preserving channel-policy fallback when no stricter access rule exists. (#70711) Thanks @vincentkoc.
- Android/security: stop `ASK_OPENCLAW` intents from auto-sending injected prompts, so external app actions only prefill the draft instead of dispatching it immediately. (#70714) Thanks @vincentkoc.
- Control UI/chat: queue Stop-button aborts across Gateway reconnects so a disconnected active run is canceled on reconnect instead of only clearing local UI state. (#70673) Thanks @chinar-amrutkar.

View File

@@ -22,7 +22,7 @@ function buildConfig(
}
describe("discord exec approvals", () => {
it("auto-enables when owner approvers resolve and disables only when forced off", () => {
it("requires explicit enablement even when owner approvers resolve", () => {
expect(isDiscordExecApprovalClientEnabled({ cfg: buildConfig() })).toBe(false);
expect(
isDiscordExecApprovalClientEnabled({
@@ -33,7 +33,7 @@ describe("discord exec approvals", () => {
isDiscordExecApprovalClientEnabled({
cfg: buildConfig({ approvers: ["123"] }),
}),
).toBe(true);
).toBe(false);
expect(
isDiscordExecApprovalClientEnabled({
cfg: {
@@ -41,6 +41,11 @@ describe("discord exec approvals", () => {
commands: { ownerAllowFrom: ["discord:789"] },
} as OpenClawConfig,
}),
).toBe(false);
expect(
isDiscordExecApprovalClientEnabled({
cfg: buildConfig({ enabled: "auto", approvers: ["123"] }),
}),
).toBe(true);
expect(
isDiscordExecApprovalClientEnabled({

View File

@@ -29,7 +29,7 @@ function buildConfig(
}
describe("slack exec approvals", () => {
it("auto-enables when owner approvers resolve and disables only when forced off", () => {
it("requires explicit enablement even when owner approvers resolve", () => {
expect(isSlackExecApprovalClientEnabled({ cfg: buildConfig() })).toBe(false);
expect(
isSlackExecApprovalClientEnabled({
@@ -40,7 +40,7 @@ describe("slack exec approvals", () => {
isSlackExecApprovalClientEnabled({
cfg: buildConfig({ approvers: ["U123"] }),
}),
).toBe(true);
).toBe(false);
expect(
isSlackExecApprovalClientEnabled({
cfg: {
@@ -48,6 +48,11 @@ describe("slack exec approvals", () => {
commands: { ownerAllowFrom: ["slack:U123OWNER"] },
} as OpenClawConfig,
}),
).toBe(false);
expect(
isSlackExecApprovalClientEnabled({
cfg: buildConfig({ enabled: "auto", approvers: ["U123"] }),
}),
).toBe(true);
expect(
isSlackExecApprovalClientEnabled({

View File

@@ -110,7 +110,7 @@ function makeForeignChannelApprovalRequest(params: {
}
describe("telegram exec approvals", () => {
it("auto-enables when approvers resolve and disables only when forced off", () => {
it("requires explicit enablement even when approvers resolve", () => {
expect(isTelegramExecApprovalClientEnabled({ cfg: buildConfig() })).toBe(false);
expect(
isTelegramExecApprovalClientEnabled({
@@ -121,11 +121,16 @@ describe("telegram exec approvals", () => {
isTelegramExecApprovalClientEnabled({
cfg: buildConfig(undefined, { allowFrom: ["123"] }),
}),
).toBe(true);
).toBe(false);
expect(
isTelegramExecApprovalClientEnabled({
cfg: buildConfig({ approvers: ["123"] }),
}),
).toBe(false);
expect(
isTelegramExecApprovalClientEnabled({
cfg: buildConfig({ enabled: "auto", approvers: ["123"] }),
}),
).toBe(true);
expect(
isTelegramExecApprovalClientEnabled({

View File

@@ -77,12 +77,12 @@ describe("createChannelExecApprovalProfile", () => {
matchesRequestAccount: ({ accountId }) => accountId !== "other",
});
it("treats unset enabled as auto and false as disabled", () => {
it("requires explicit enablement when approvers exist", () => {
expect(
isChannelExecApprovalClientEnabledFromConfig({
approverCount: 1,
}),
).toBe(true);
).toBe(false);
expect(
isChannelExecApprovalClientEnabledFromConfig({
enabled: "auto",

View File

@@ -44,7 +44,7 @@ export function isChannelExecApprovalClientEnabledFromConfig(params: {
if (params.approverCount <= 0) {
return false;
}
return params.enabled !== false;
return params.enabled === true || params.enabled === "auto";
}
export function isChannelExecApprovalTargetRecipient(params: {