mirror of https://github.com/openclaw/openclaw.git
fix: harden discord ack auth and gate fallout (#60081) (thanks @FunJim)
This commit is contained in:
parent
c1741abc3c
commit
bf6bd7432a
|
|
@ -71,6 +71,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Plugins/allowlists: let explicit bundled chat channel enablement bypass `plugins.allow`, while keeping auto-enabled channel activation and startup sidecars behind restrictive allowlists. (#60233) Thanks @dorukardahan.
|
||||
- Allowlist/commands: require owner access for `/allowlist add` and `/allowlist remove` so command-authorized non-owners cannot mutate persisted allowlists. (#59836) Thanks @eleqtrizit.
|
||||
- Control UI/skills: clear stale ClawHub results immediately when the search query changes, so debounced searches cannot keep outdated install targets visible. Related #60134.
|
||||
- Discord/ack reactions: keep automatic ACK reaction auth on the active hydrated Discord account so SecretRef-backed and non-default-account reactions stop falling back to stale default config resolution. (#60081) Thanks @FunJim.
|
||||
|
||||
## 2026.4.2
|
||||
|
||||
|
|
|
|||
|
|
@ -303,14 +303,31 @@ describe("processDiscordMessage ack reactions", () => {
|
|||
|
||||
it("sends ack reactions for mention-gated guild messages when mentioned", async () => {
|
||||
const ctx = await createBaseContext({
|
||||
accountId: "ops",
|
||||
shouldRequireMention: true,
|
||||
effectiveWasMentioned: true,
|
||||
route: {
|
||||
agentId: "main",
|
||||
channel: "discord",
|
||||
accountId: "ops",
|
||||
sessionKey: "agent:main:discord:channel:c1",
|
||||
mainSessionKey: "agent:main:main",
|
||||
},
|
||||
});
|
||||
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
await processDiscordMessage(ctx as any);
|
||||
|
||||
expect(sendMocks.reactMessageDiscord.mock.calls[0]).toEqual(["c1", "m1", "👀", { rest: {}, cfg: expect.objectContaining({ messages: { ackReaction: "👀" } }) }]);
|
||||
expect(sendMocks.reactMessageDiscord.mock.calls[0]).toEqual([
|
||||
"c1",
|
||||
"m1",
|
||||
"👀",
|
||||
{
|
||||
rest: {},
|
||||
cfg: expect.objectContaining({ messages: { ackReaction: "👀" } }),
|
||||
accountId: "ops",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses preflight-resolved messageChannelId when message.channelId is missing", async () => {
|
||||
|
|
@ -332,7 +349,11 @@ describe("processDiscordMessage ack reactions", () => {
|
|||
"fallback-channel",
|
||||
"m1",
|
||||
"👀",
|
||||
{ rest: {}, cfg: expect.objectContaining({ messages: { ackReaction: "👀" } }) },
|
||||
{
|
||||
rest: {},
|
||||
cfg: expect.objectContaining({ messages: { ackReaction: "👀" } }),
|
||||
accountId: "default",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
@ -488,7 +509,21 @@ describe("processDiscordMessage ack reactions", () => {
|
|||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
await processDiscordMessage(ctx as any);
|
||||
|
||||
expect(sendMocks.removeReactionDiscord).toHaveBeenCalledWith("c1", "m1", "👀", expect.objectContaining({ rest: {}, cfg: expect.objectContaining({ messages: expect.objectContaining({ ackReaction: "👀", removeAckAfterReply: true }) }) }));
|
||||
expect(sendMocks.removeReactionDiscord).toHaveBeenCalledWith(
|
||||
"c1",
|
||||
"m1",
|
||||
"👀",
|
||||
expect.objectContaining({
|
||||
rest: {},
|
||||
cfg: expect.objectContaining({
|
||||
messages: expect.objectContaining({
|
||||
ackReaction: "👀",
|
||||
removeAckAfterReply: true,
|
||||
}),
|
||||
}),
|
||||
accountId: "default",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("removes the plain ack reaction when status reactions are disabled and removeAckAfterReply is enabled", async () => {
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ type DiscordSubagentSpawningEvent = {
|
|||
threadId?: string | number;
|
||||
};
|
||||
childSessionKey: string;
|
||||
agentId?: string;
|
||||
agentId: string;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
type DiscordSubagentEndedEvent = {
|
||||
targetSessionKey: string;
|
||||
accountId?: string;
|
||||
targetKind?: string;
|
||||
targetKind?: ThreadBindingTargetKind;
|
||||
reason?: string;
|
||||
sendFarewell?: boolean;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ const resolveTelegramApproveCommandBehavior: NonNullable<
|
|||
isTelegramExecApprovalAuthorizedSender({ cfg, accountId, senderId }) &&
|
||||
!isTelegramExecApprovalApprover({ cfg, accountId, senderId })
|
||||
) {
|
||||
return { kind: "ignore" };
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
kind: "reply",
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ const telegramCommandTestPlugin: ChannelPlugin = {
|
|||
isTelegramExecApprovalAuthorizedSender({ cfg, accountId, senderId }) &&
|
||||
!getTelegramExecApprovalApprovers({ cfg, accountId }).includes(senderId?.trim() ?? "")
|
||||
) {
|
||||
return { kind: "ignore" } as const;
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
kind: "reply",
|
||||
|
|
|
|||
|
|
@ -1217,7 +1217,7 @@ describe("secrets runtime snapshot", () => {
|
|||
const ignoredInactiveWarnings = snapshot.warnings.filter(
|
||||
(warning) => warning.code === "SECRETS_REF_IGNORED_INACTIVE_SURFACE",
|
||||
);
|
||||
expect(ignoredInactiveWarnings).toHaveLength(10);
|
||||
expect(ignoredInactiveWarnings).toHaveLength(6);
|
||||
expect(snapshot.warnings.map((warning) => warning.path)).toEqual(
|
||||
expect.arrayContaining([
|
||||
"agents.defaults.memorySearch.remote.apiKey",
|
||||
|
|
@ -1226,10 +1226,6 @@ describe("secrets runtime snapshot", () => {
|
|||
"channels.telegram.accounts.disabled.botToken",
|
||||
"plugins.entries.brave.config.webSearch.apiKey",
|
||||
"plugins.entries.google.config.webSearch.apiKey",
|
||||
"plugins.entries.xai.config.webSearch.apiKey",
|
||||
"plugins.entries.moonshot.config.webSearch.apiKey",
|
||||
"plugins.entries.perplexity.config.webSearch.apiKey",
|
||||
"plugins.entries.firecrawl.config.webSearch.apiKey",
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue