diff --git a/extensions/bluebubbles/src/channel.ts b/extensions/bluebubbles/src/channel.ts index 8e3ae2ea6a5..e0260c5c716 100644 --- a/extensions/bluebubbles/src/channel.ts +++ b/extensions/bluebubbles/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import type { ChannelAccountSnapshot, ChannelPlugin, @@ -144,7 +145,13 @@ export const bluebubblesPlugin: ChannelPlugin = { return []; } return [ - `- BlueBubbles groups: groupPolicy="open" allows any member to trigger the bot. Set channels.bluebubbles.groupPolicy="allowlist" + channels.bluebubbles.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "BlueBubbles groups", + openScope: "any member", + groupPolicyPath: "channels.bluebubbles.groupPolicy", + groupAllowFromPath: "channels.bluebubbles.groupAllowFrom", + mentionGated: false, + }), ]; }, }, diff --git a/extensions/discord/src/channel.ts b/extensions/discord/src/channel.ts index 5744bb3d946..33fe3bebcaf 100644 --- a/extensions/discord/src/channel.ts +++ b/extensions/discord/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyConfigureRouteAllowlistWarning, + buildOpenGroupPolicyWarning, +} from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildComputedAccountStatusSnapshot, @@ -151,11 +155,22 @@ export const discordPlugin: ChannelPlugin = { if (groupPolicy === "open") { if (channelAllowlistConfigured) { warnings.push( - `- Discord guilds: groupPolicy="open" allows any channel not explicitly denied to trigger (mention-gated). Set channels.discord.groupPolicy="allowlist" and configure channels.discord.guilds..channels.`, + buildOpenGroupPolicyConfigureRouteAllowlistWarning({ + surface: "Discord guilds", + openScope: "any channel not explicitly denied", + groupPolicyPath: "channels.discord.groupPolicy", + routeAllowlistPath: "channels.discord.guilds..channels", + }), ); } else { warnings.push( - `- Discord guilds: groupPolicy="open" with no guild/channel allowlist; any channel can trigger (mention-gated). Set channels.discord.groupPolicy="allowlist" and configure channels.discord.guilds..channels.`, + buildOpenGroupPolicyWarning({ + surface: "Discord guilds", + openBehavior: + "with no guild/channel allowlist; any channel can trigger (mention-gated)", + remediation: + 'Set channels.discord.groupPolicy="allowlist" and configure channels.discord.guilds..channels', + }), ); } } diff --git a/extensions/feishu/src/channel.ts b/extensions/feishu/src/channel.ts index a8fa04d5700..3f2cf6d286d 100644 --- a/extensions/feishu/src/channel.ts +++ b/extensions/feishu/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import type { ChannelMeta, ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk/feishu"; import { buildProbeChannelStatusSummary, @@ -268,7 +269,12 @@ export const feishuPlugin: ChannelPlugin = { }); if (groupPolicy !== "open") return []; return [ - `- Feishu[${account.accountId}] groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.feishu.groupPolicy="allowlist" + channels.feishu.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: `Feishu[${account.accountId}] groups`, + openScope: "any member", + groupPolicyPath: "channels.feishu.groupPolicy", + groupAllowFromPath: "channels.feishu.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/googlechat/src/channel.ts b/extensions/googlechat/src/channel.ts index 8026334d21a..f7635b9bf11 100644 --- a/extensions/googlechat/src/channel.ts +++ b/extensions/googlechat/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyConfigureRouteAllowlistWarning } from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, @@ -212,7 +213,12 @@ export const googlechatPlugin: ChannelPlugin = { }); if (groupPolicy === "open") { warnings.push( - `- Google Chat spaces: groupPolicy="open" allows any space to trigger (mention-gated). Set channels.googlechat.groupPolicy="allowlist" and configure channels.googlechat.groups.`, + buildOpenGroupPolicyConfigureRouteAllowlistWarning({ + surface: "Google Chat spaces", + openScope: "any space", + groupPolicyPath: "channels.googlechat.groupPolicy", + routeAllowlistPath: "channels.googlechat.groups", + }), ); } if (account.config.dm?.policy === "open") { diff --git a/extensions/imessage/src/channel.ts b/extensions/imessage/src/channel.ts index 8c77f2a94bf..c4d21f2f913 100644 --- a/extensions/imessage/src/channel.ts +++ b/extensions/imessage/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildChannelConfigSchema, @@ -155,7 +156,13 @@ export const imessagePlugin: ChannelPlugin = { return []; } return [ - `- iMessage groups: groupPolicy="open" allows any member to trigger the bot. Set channels.imessage.groupPolicy="allowlist" + channels.imessage.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "iMessage groups", + openScope: "any member", + groupPolicyPath: "channels.imessage.groupPolicy", + groupAllowFromPath: "channels.imessage.groupAllowFrom", + mentionGated: false, + }), ]; }, }, diff --git a/extensions/irc/src/channel.ts b/extensions/irc/src/channel.ts index a41a46f3db0..ec8997bcf9a 100644 --- a/extensions/irc/src/channel.ts +++ b/extensions/irc/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyWarning } from "openclaw/plugin-sdk"; import { buildBaseAccountStatusSnapshot, buildBaseChannelStatusSummary, @@ -146,7 +147,11 @@ export const ircPlugin: ChannelPlugin = { }); if (groupPolicy === "open") { warnings.push( - '- IRC channels: groupPolicy="open" allows all channels and senders (mention-gated). Prefer channels.irc.groupPolicy="allowlist" with channels.irc.groups.', + buildOpenGroupPolicyWarning({ + surface: "IRC channels", + openBehavior: "allows all channels and senders (mention-gated)", + remediation: 'Prefer channels.irc.groupPolicy="allowlist" with channels.irc.groups', + }), ); } if (!account.config.tls) { diff --git a/extensions/line/src/channel.ts b/extensions/line/src/channel.ts index 69491cf61f2..1107a0c1b48 100644 --- a/extensions/line/src/channel.ts +++ b/extensions/line/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import { buildChannelConfigSchema, buildComputedAccountStatusSnapshot, @@ -185,7 +186,13 @@ export const linePlugin: ChannelPlugin = { return []; } return [ - `- LINE groups: groupPolicy="open" allows any member in groups to trigger. Set channels.line.groupPolicy="allowlist" + channels.line.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "LINE groups", + openScope: "any member in groups", + groupPolicyPath: "channels.line.groupPolicy", + groupAllowFromPath: "channels.line.groupAllowFrom", + mentionGated: false, + }), ]; }, }, diff --git a/extensions/matrix/src/channel.ts b/extensions/matrix/src/channel.ts index 29dfe5fd357..80b0987e3df 100644 --- a/extensions/matrix/src/channel.ts +++ b/extensions/matrix/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyWarning } from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildChannelConfigSchema, @@ -184,7 +185,12 @@ export const matrixPlugin: ChannelPlugin = { return []; } return [ - '- Matrix rooms: groupPolicy="open" allows any room to trigger (mention-gated). Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms.', + buildOpenGroupPolicyWarning({ + surface: "Matrix rooms", + openBehavior: "allows any room to trigger (mention-gated)", + remediation: + 'Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms', + }), ]; }, }, diff --git a/extensions/mattermost/src/channel.ts b/extensions/mattermost/src/channel.ts index d1a4135a92b..c325d588dbb 100644 --- a/extensions/mattermost/src/channel.ts +++ b/extensions/mattermost/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, @@ -305,7 +306,12 @@ export const mattermostPlugin: ChannelPlugin = { return []; } return [ - `- Mattermost channels: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.mattermost.groupPolicy="allowlist" + channels.mattermost.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Mattermost channels", + openScope: "any member", + groupPolicyPath: "channels.mattermost.groupPolicy", + groupAllowFromPath: "channels.mattermost.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/msteams/src/channel.ts b/extensions/msteams/src/channel.ts index be804a25c44..2bee9c7096f 100644 --- a/extensions/msteams/src/channel.ts +++ b/extensions/msteams/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import type { ChannelMessageActionName, ChannelPlugin, @@ -144,7 +145,12 @@ export const msteamsPlugin: ChannelPlugin = { return []; } return [ - `- MS Teams groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.msteams.groupPolicy="allowlist" + channels.msteams.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "MS Teams groups", + openScope: "any member", + groupPolicyPath: "channels.msteams.groupPolicy", + groupAllowFromPath: "channels.msteams.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/nextcloud-talk/src/channel.ts b/extensions/nextcloud-talk/src/channel.ts index a547a735ad3..567e89c8d5b 100644 --- a/extensions/nextcloud-talk/src/channel.ts +++ b/extensions/nextcloud-talk/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyNoRouteAllowlistWarning, + buildOpenGroupPolicyRestrictSendersWarning, +} from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildBaseChannelStatusSummary, @@ -148,11 +152,22 @@ export const nextcloudTalkPlugin: ChannelPlugin = account.config.rooms && Object.keys(account.config.rooms).length > 0; if (roomAllowlistConfigured) { return [ - `- Nextcloud Talk rooms: groupPolicy="open" allows any member in allowed rooms to trigger (mention-gated). Set channels.nextcloud-talk.groupPolicy="allowlist" + channels.nextcloud-talk.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Nextcloud Talk rooms", + openScope: "any member in allowed rooms", + groupPolicyPath: "channels.nextcloud-talk.groupPolicy", + groupAllowFromPath: "channels.nextcloud-talk.groupAllowFrom", + }), ]; } return [ - `- Nextcloud Talk rooms: groupPolicy="open" with no channels.nextcloud-talk.rooms allowlist; any room can add + ping (mention-gated). Set channels.nextcloud-talk.groupPolicy="allowlist" + channels.nextcloud-talk.groupAllowFrom or configure channels.nextcloud-talk.rooms.`, + buildOpenGroupPolicyNoRouteAllowlistWarning({ + surface: "Nextcloud Talk rooms", + routeAllowlistPath: "channels.nextcloud-talk.rooms", + routeScope: "room", + groupPolicyPath: "channels.nextcloud-talk.groupPolicy", + groupAllowFromPath: "channels.nextcloud-talk.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/signal/src/channel.ts b/extensions/signal/src/channel.ts index 1dc3bbc15cc..b307e9b9478 100644 --- a/extensions/signal/src/channel.ts +++ b/extensions/signal/src/channel.ts @@ -1,3 +1,4 @@ +import { buildOpenGroupPolicyRestrictSendersWarning } from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildBaseAccountStatusSnapshot, @@ -179,7 +180,13 @@ export const signalPlugin: ChannelPlugin = { return []; } return [ - `- Signal groups: groupPolicy="open" allows any member to trigger the bot. Set channels.signal.groupPolicy="allowlist" + channels.signal.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Signal groups", + openScope: "any member", + groupPolicyPath: "channels.signal.groupPolicy", + groupAllowFromPath: "channels.signal.groupAllowFrom", + mentionGated: false, + }), ]; }, }, diff --git a/extensions/slack/src/channel.ts b/extensions/slack/src/channel.ts index 39951538cf3..20536444155 100644 --- a/extensions/slack/src/channel.ts +++ b/extensions/slack/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyConfigureRouteAllowlistWarning, + buildOpenGroupPolicyWarning, +} from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildComputedAccountStatusSnapshot, @@ -200,11 +204,21 @@ export const slackPlugin: ChannelPlugin = { if (groupPolicy === "open") { if (channelAllowlistConfigured) { warnings.push( - `- Slack channels: groupPolicy="open" allows any channel not explicitly denied to trigger (mention-gated). Set channels.slack.groupPolicy="allowlist" and configure channels.slack.channels.`, + buildOpenGroupPolicyConfigureRouteAllowlistWarning({ + surface: "Slack channels", + openScope: "any channel not explicitly denied", + groupPolicyPath: "channels.slack.groupPolicy", + routeAllowlistPath: "channels.slack.channels", + }), ); } else { warnings.push( - `- Slack channels: groupPolicy="open" with no channel allowlist; any channel can trigger (mention-gated). Set channels.slack.groupPolicy="allowlist" and configure channels.slack.channels.`, + buildOpenGroupPolicyWarning({ + surface: "Slack channels", + openBehavior: "with no channel allowlist; any channel can trigger (mention-gated)", + remediation: + 'Set channels.slack.groupPolicy="allowlist" and configure channels.slack.channels', + }), ); } } diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index ccb22dab55b..3fe18e3f288 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyNoRouteAllowlistWarning, + buildOpenGroupPolicyRestrictSendersWarning, +} from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildChannelConfigSchema, @@ -216,11 +220,22 @@ export const telegramPlugin: ChannelPlugin 0; if (groupAllowlistConfigured) { return [ - `- Telegram groups: groupPolicy="open" allows any member in allowed groups to trigger (mention-gated). Set channels.telegram.groupPolicy="allowlist" + channels.telegram.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Telegram groups", + openScope: "any member in allowed groups", + groupPolicyPath: "channels.telegram.groupPolicy", + groupAllowFromPath: "channels.telegram.groupAllowFrom", + }), ]; } return [ - `- Telegram groups: groupPolicy="open" with no channels.telegram.groups allowlist; any group can add + ping (mention-gated). Set channels.telegram.groupPolicy="allowlist" + channels.telegram.groupAllowFrom or configure channels.telegram.groups.`, + buildOpenGroupPolicyNoRouteAllowlistWarning({ + surface: "Telegram groups", + routeAllowlistPath: "channels.telegram.groups", + routeScope: "group", + groupPolicyPath: "channels.telegram.groupPolicy", + groupAllowFromPath: "channels.telegram.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/whatsapp/src/channel.ts b/extensions/whatsapp/src/channel.ts index 424c1046c87..60387ca0c34 100644 --- a/extensions/whatsapp/src/channel.ts +++ b/extensions/whatsapp/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyNoRouteAllowlistWarning, + buildOpenGroupPolicyRestrictSendersWarning, +} from "openclaw/plugin-sdk"; import { applyAccountNameToChannelSection, buildChannelConfigSchema, @@ -149,11 +153,22 @@ export const whatsappPlugin: ChannelPlugin = { Boolean(account.groups) && Object.keys(account.groups ?? {}).length > 0; if (groupAllowlistConfigured) { return [ - `- WhatsApp groups: groupPolicy="open" allows any member in allowed groups to trigger (mention-gated). Set channels.whatsapp.groupPolicy="allowlist" + channels.whatsapp.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "WhatsApp groups", + openScope: "any member in allowed groups", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }), ]; } return [ - `- WhatsApp groups: groupPolicy="open" with no channels.whatsapp.groups allowlist; any group can add + ping (mention-gated). Set channels.whatsapp.groupPolicy="allowlist" + channels.whatsapp.groupAllowFrom or configure channels.whatsapp.groups.`, + buildOpenGroupPolicyNoRouteAllowlistWarning({ + surface: "WhatsApp groups", + routeAllowlistPath: "channels.whatsapp.groups", + routeScope: "group", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }), ]; }, }, diff --git a/extensions/zalo/src/channel.ts b/extensions/zalo/src/channel.ts index 9de72910ab7..1d403a1df34 100644 --- a/extensions/zalo/src/channel.ts +++ b/extensions/zalo/src/channel.ts @@ -1,3 +1,7 @@ +import { + buildOpenGroupPolicyRestrictSendersWarning, + buildOpenGroupPolicyWarning, +} from "openclaw/plugin-sdk"; import type { ChannelAccountSnapshot, ChannelDock, @@ -171,11 +175,21 @@ export const zaloPlugin: ChannelPlugin = { explicitGroupAllowFrom.length > 0 ? explicitGroupAllowFrom : dmAllowFrom; if (effectiveAllowFrom.length > 0) { return [ - `- Zalo groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.zalo.groupPolicy="allowlist" + channels.zalo.groupAllowFrom to restrict senders.`, + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Zalo groups", + openScope: "any member", + groupPolicyPath: "channels.zalo.groupPolicy", + groupAllowFromPath: "channels.zalo.groupAllowFrom", + }), ]; } return [ - `- Zalo groups: groupPolicy="open" with no groupAllowFrom/allowFrom allowlist; any member can trigger (mention-gated). Set channels.zalo.groupPolicy="allowlist" + channels.zalo.groupAllowFrom.`, + buildOpenGroupPolicyWarning({ + surface: "Zalo groups", + openBehavior: + "with no groupAllowFrom/allowFrom allowlist; any member can trigger (mention-gated)", + remediation: 'Set channels.zalo.groupPolicy="allowlist" + channels.zalo.groupAllowFrom', + }), ]; }, }, diff --git a/src/channels/plugins/group-policy-warnings.test.ts b/src/channels/plugins/group-policy-warnings.test.ts new file mode 100644 index 00000000000..ee1d67a468c --- /dev/null +++ b/src/channels/plugins/group-policy-warnings.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it } from "vitest"; +import { + buildOpenGroupPolicyConfigureRouteAllowlistWarning, + buildOpenGroupPolicyNoRouteAllowlistWarning, + buildOpenGroupPolicyRestrictSendersWarning, + buildOpenGroupPolicyWarning, +} from "./group-policy-warnings.js"; + +describe("group policy warning builders", () => { + it("builds base open-policy warning", () => { + expect( + buildOpenGroupPolicyWarning({ + surface: "Example groups", + openBehavior: "allows any member to trigger (mention-gated)", + remediation: 'Set channels.example.groupPolicy="allowlist"', + }), + ).toBe( + '- Example groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.example.groupPolicy="allowlist".', + ); + }); + + it("builds restrict-senders warning", () => { + expect( + buildOpenGroupPolicyRestrictSendersWarning({ + surface: "Example groups", + openScope: "any member in allowed groups", + groupPolicyPath: "channels.example.groupPolicy", + groupAllowFromPath: "channels.example.groupAllowFrom", + }), + ).toBe( + '- Example groups: groupPolicy="open" allows any member in allowed groups to trigger (mention-gated). Set channels.example.groupPolicy="allowlist" + channels.example.groupAllowFrom to restrict senders.', + ); + }); + + it("builds no-route-allowlist warning", () => { + expect( + buildOpenGroupPolicyNoRouteAllowlistWarning({ + surface: "Example groups", + routeAllowlistPath: "channels.example.groups", + routeScope: "group", + groupPolicyPath: "channels.example.groupPolicy", + groupAllowFromPath: "channels.example.groupAllowFrom", + }), + ).toBe( + '- Example groups: groupPolicy="open" with no channels.example.groups allowlist; any group can add + ping (mention-gated). Set channels.example.groupPolicy="allowlist" + channels.example.groupAllowFrom or configure channels.example.groups.', + ); + }); + + it("builds configure-route-allowlist warning", () => { + expect( + buildOpenGroupPolicyConfigureRouteAllowlistWarning({ + surface: "Example channels", + openScope: "any channel not explicitly denied", + groupPolicyPath: "channels.example.groupPolicy", + routeAllowlistPath: "channels.example.channels", + }), + ).toBe( + '- Example channels: groupPolicy="open" allows any channel not explicitly denied to trigger (mention-gated). Set channels.example.groupPolicy="allowlist" and configure channels.example.channels.', + ); + }); +}); diff --git a/src/channels/plugins/group-policy-warnings.ts b/src/channels/plugins/group-policy-warnings.ts new file mode 100644 index 00000000000..a2bb4e87742 --- /dev/null +++ b/src/channels/plugins/group-policy-warnings.ts @@ -0,0 +1,53 @@ +export function buildOpenGroupPolicyWarning(params: { + surface: string; + openBehavior: string; + remediation: string; +}): string { + return `- ${params.surface}: groupPolicy="open" ${params.openBehavior}. ${params.remediation}.`; +} + +export function buildOpenGroupPolicyRestrictSendersWarning(params: { + surface: string; + openScope: string; + groupPolicyPath: string; + groupAllowFromPath: string; + mentionGated?: boolean; +}): string { + const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; + return buildOpenGroupPolicyWarning({ + surface: params.surface, + openBehavior: `allows ${params.openScope} to trigger${mentionSuffix}`, + remediation: `Set ${params.groupPolicyPath}="allowlist" + ${params.groupAllowFromPath} to restrict senders`, + }); +} + +export function buildOpenGroupPolicyNoRouteAllowlistWarning(params: { + surface: string; + routeAllowlistPath: string; + routeScope: string; + groupPolicyPath: string; + groupAllowFromPath: string; + mentionGated?: boolean; +}): string { + const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; + return buildOpenGroupPolicyWarning({ + surface: params.surface, + openBehavior: `with no ${params.routeAllowlistPath} allowlist; any ${params.routeScope} can add + ping${mentionSuffix}`, + remediation: `Set ${params.groupPolicyPath}="allowlist" + ${params.groupAllowFromPath} or configure ${params.routeAllowlistPath}`, + }); +} + +export function buildOpenGroupPolicyConfigureRouteAllowlistWarning(params: { + surface: string; + openScope: string; + groupPolicyPath: string; + routeAllowlistPath: string; + mentionGated?: boolean; +}): string { + const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; + return buildOpenGroupPolicyWarning({ + surface: params.surface, + openBehavior: `allows ${params.openScope} to trigger${mentionSuffix}`, + remediation: `Set ${params.groupPolicyPath}="allowlist" and configure ${params.routeAllowlistPath}`, + }); +} diff --git a/src/plugin-sdk/index.ts b/src/plugin-sdk/index.ts index bf50d3d4d8e..156d183a27c 100644 --- a/src/plugin-sdk/index.ts +++ b/src/plugin-sdk/index.ts @@ -524,6 +524,12 @@ export { applyAccountNameToChannelSection, migrateBaseNameToDefaultAccount, } from "../channels/plugins/setup-helpers.js"; +export { + buildOpenGroupPolicyConfigureRouteAllowlistWarning, + buildOpenGroupPolicyNoRouteAllowlistWarning, + buildOpenGroupPolicyRestrictSendersWarning, + buildOpenGroupPolicyWarning, +} from "../channels/plugins/group-policy-warnings.js"; export { formatPairingApproveHint } from "../channels/plugins/helpers.js"; export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";