mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-07 22:09:57 +00:00
refactor(channels): centralize runtime group policy handling
This commit is contained in:
@@ -1,32 +1,85 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveRuntimeGroupPolicy } from "./runtime-group-policy.js";
|
||||
import {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
resolveRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "./runtime-group-policy.js";
|
||||
|
||||
describe("resolveRuntimeGroupPolicy", () => {
|
||||
it("fails closed when provider config is missing and no defaults are set", () => {
|
||||
const resolved = resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: false,
|
||||
});
|
||||
expect(resolved.groupPolicy).toBe("allowlist");
|
||||
expect(resolved.providerMissingFallbackApplied).toBe(true);
|
||||
it.each([
|
||||
{
|
||||
title: "fails closed when provider config is missing and no defaults are set",
|
||||
params: { providerConfigPresent: false },
|
||||
expectedPolicy: "allowlist",
|
||||
expectedFallbackApplied: true,
|
||||
},
|
||||
{
|
||||
title: "keeps configured fallback when provider config is present",
|
||||
params: { providerConfigPresent: true, configuredFallbackPolicy: "open" as const },
|
||||
expectedPolicy: "open",
|
||||
expectedFallbackApplied: false,
|
||||
},
|
||||
{
|
||||
title: "ignores global defaults when provider config is missing",
|
||||
params: {
|
||||
providerConfigPresent: false,
|
||||
defaultGroupPolicy: "disabled" as const,
|
||||
configuredFallbackPolicy: "open" as const,
|
||||
missingProviderFallbackPolicy: "allowlist" as const,
|
||||
},
|
||||
expectedPolicy: "allowlist",
|
||||
expectedFallbackApplied: true,
|
||||
},
|
||||
])("$title", ({ params, expectedPolicy, expectedFallbackApplied }) => {
|
||||
const resolved = resolveRuntimeGroupPolicy(params);
|
||||
expect(resolved.groupPolicy).toBe(expectedPolicy);
|
||||
expect(resolved.providerMissingFallbackApplied).toBe(expectedFallbackApplied);
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps configured fallback when provider config is present", () => {
|
||||
const resolved = resolveRuntimeGroupPolicy({
|
||||
describe("resolveOpenProviderRuntimeGroupPolicy", () => {
|
||||
it("uses open fallback when provider config exists", () => {
|
||||
const resolved = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: true,
|
||||
configuredFallbackPolicy: "open",
|
||||
});
|
||||
expect(resolved.groupPolicy).toBe("open");
|
||||
expect(resolved.providerMissingFallbackApplied).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores global defaults when provider config is missing", () => {
|
||||
const resolved = resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: false,
|
||||
defaultGroupPolicy: "disabled",
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
describe("resolveAllowlistProviderRuntimeGroupPolicy", () => {
|
||||
it("uses allowlist fallback when provider config exists", () => {
|
||||
const resolved = resolveAllowlistProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: true,
|
||||
});
|
||||
expect(resolved.groupPolicy).toBe("allowlist");
|
||||
expect(resolved.providerMissingFallbackApplied).toBe(true);
|
||||
expect(resolved.providerMissingFallbackApplied).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("warnMissingProviderGroupPolicyFallbackOnce", () => {
|
||||
it("logs only once per provider/account key", () => {
|
||||
const lines: string[] = [];
|
||||
const first = warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied: true,
|
||||
providerKey: "runtime-policy-test",
|
||||
accountId: "account-a",
|
||||
blockedLabel: "room messages",
|
||||
log: (message) => lines.push(message),
|
||||
});
|
||||
const second = warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied: true,
|
||||
providerKey: "runtime-policy-test",
|
||||
accountId: "account-a",
|
||||
blockedLabel: "room messages",
|
||||
log: (message) => lines.push(message),
|
||||
});
|
||||
|
||||
expect(first).toBe(true);
|
||||
expect(second).toBe(false);
|
||||
expect(lines).toHaveLength(1);
|
||||
expect(lines[0]).toContain("channels.runtime-policy-test is missing");
|
||||
expect(lines[0]).toContain("room messages blocked");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,13 +5,17 @@ export type RuntimeGroupPolicyResolution = {
|
||||
providerMissingFallbackApplied: boolean;
|
||||
};
|
||||
|
||||
export function resolveRuntimeGroupPolicy(params: {
|
||||
export type RuntimeGroupPolicyParams = {
|
||||
providerConfigPresent: boolean;
|
||||
groupPolicy?: GroupPolicy;
|
||||
defaultGroupPolicy?: GroupPolicy;
|
||||
configuredFallbackPolicy?: GroupPolicy;
|
||||
missingProviderFallbackPolicy?: GroupPolicy;
|
||||
}): RuntimeGroupPolicyResolution {
|
||||
};
|
||||
|
||||
export function resolveRuntimeGroupPolicy(
|
||||
params: RuntimeGroupPolicyParams,
|
||||
): RuntimeGroupPolicyResolution {
|
||||
const configuredFallbackPolicy = params.configuredFallbackPolicy ?? "open";
|
||||
const missingProviderFallbackPolicy = params.missingProviderFallbackPolicy ?? "allowlist";
|
||||
const groupPolicy = params.providerConfigPresent
|
||||
@@ -21,3 +25,67 @@ export function resolveRuntimeGroupPolicy(params: {
|
||||
!params.providerConfigPresent && params.groupPolicy === undefined;
|
||||
return { groupPolicy, providerMissingFallbackApplied };
|
||||
}
|
||||
|
||||
export type ResolveProviderRuntimeGroupPolicyParams = {
|
||||
providerConfigPresent: boolean;
|
||||
groupPolicy?: GroupPolicy;
|
||||
defaultGroupPolicy?: GroupPolicy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Standard provider runtime policy:
|
||||
* - configured provider fallback: open
|
||||
* - missing provider fallback: allowlist (fail-closed)
|
||||
*/
|
||||
export function resolveOpenProviderRuntimeGroupPolicy(
|
||||
params: ResolveProviderRuntimeGroupPolicyParams,
|
||||
): RuntimeGroupPolicyResolution {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Strict provider runtime policy:
|
||||
* - configured provider fallback: allowlist
|
||||
* - missing provider fallback: allowlist (fail-closed)
|
||||
*/
|
||||
export function resolveAllowlistProviderRuntimeGroupPolicy(
|
||||
params: ResolveProviderRuntimeGroupPolicyParams,
|
||||
): RuntimeGroupPolicyResolution {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "allowlist",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
const warnedMissingProviderGroupPolicy = new Set<string>();
|
||||
|
||||
export function warnMissingProviderGroupPolicyFallbackOnce(params: {
|
||||
providerMissingFallbackApplied: boolean;
|
||||
providerKey: string;
|
||||
accountId?: string;
|
||||
blockedLabel?: string;
|
||||
log: (message: string) => void;
|
||||
}): boolean {
|
||||
if (!params.providerMissingFallbackApplied) {
|
||||
return false;
|
||||
}
|
||||
const key = `${params.providerKey}:${params.accountId ?? "*"}`;
|
||||
if (warnedMissingProviderGroupPolicy.has(key)) {
|
||||
return false;
|
||||
}
|
||||
warnedMissingProviderGroupPolicy.add(key);
|
||||
const blockedLabel = params.blockedLabel?.trim() || "group messages";
|
||||
params.log(
|
||||
`${params.providerKey}: channels.${params.providerKey} is missing; defaulting groupPolicy to "allowlist" (${blockedLabel} blocked until explicitly configured).`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
createInboundDebouncer,
|
||||
resolveInboundDebounceMs,
|
||||
} from "../../auto-reply/inbound-debounce.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import { resolveOpenProviderRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import { danger } from "../../globals.js";
|
||||
import type { DiscordMessageEvent, DiscordMessageHandler } from "./listeners.js";
|
||||
import { preflightDiscordMessage } from "./message-handler.preflight.js";
|
||||
@@ -24,12 +24,10 @@ type DiscordMessageHandlerParams = Omit<
|
||||
export function createDiscordMessageHandler(
|
||||
params: DiscordMessageHandlerParams,
|
||||
): DiscordMessageHandler {
|
||||
const { groupPolicy } = resolveRuntimeGroupPolicy({
|
||||
const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.cfg.channels?.discord !== undefined,
|
||||
groupPolicy: params.discordConfig?.groupPolicy,
|
||||
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
const ackReactionScope = params.cfg.messages?.ackReactionScope ?? "group-mentions";
|
||||
const debounceMs = resolveInboundDebounceMs({ cfg: params.cfg, channel: "discord" });
|
||||
|
||||
@@ -39,7 +39,7 @@ import type { ReplyPayload } from "../../auto-reply/types.js";
|
||||
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
||||
import { createReplyPrefixOptions } from "../../channels/reply-prefix.js";
|
||||
import type { OpenClawConfig, loadConfig } from "../../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import { resolveOpenProviderRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
@@ -1330,12 +1330,10 @@ async function dispatchDiscordCommandInteraction(params: {
|
||||
const channelAllowlistConfigured =
|
||||
Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
|
||||
const channelAllowed = channelConfig?.allowed !== false;
|
||||
const { groupPolicy } = resolveRuntimeGroupPolicy({
|
||||
const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.discord !== undefined,
|
||||
groupPolicy: discordConfig?.groupPolicy,
|
||||
defaultGroupPolicy: cfg.channels?.defaults?.groupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
const allowByPolicy = isDiscordGroupAllowedByPolicy({
|
||||
groupPolicy,
|
||||
|
||||
@@ -21,8 +21,10 @@ import {
|
||||
} from "../../config/commands.js";
|
||||
import type { OpenClawConfig, ReplyToMode } from "../../config/config.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import type { GroupPolicy } from "../../config/types.base.js";
|
||||
import {
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../../config/runtime-group-policy.js";
|
||||
import { danger, logVerbose, shouldLogVerbose, warn } from "../../globals.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { createDiscordRetryRunner } from "../../infra/retry-policy.js";
|
||||
@@ -172,23 +174,6 @@ function dedupeSkillCommandsForDiscord(
|
||||
return deduped;
|
||||
}
|
||||
|
||||
function resolveDiscordRuntimeGroupPolicy(params: {
|
||||
providerConfigPresent: boolean;
|
||||
groupPolicy?: GroupPolicy;
|
||||
defaultGroupPolicy?: GroupPolicy;
|
||||
}): {
|
||||
groupPolicy: GroupPolicy;
|
||||
providerMissingFallbackApplied: boolean;
|
||||
} {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
async function deployDiscordCommands(params: {
|
||||
client: Client;
|
||||
runtime: RuntimeEnv;
|
||||
@@ -273,20 +258,20 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
let guildEntries = rawDiscordCfg.guilds;
|
||||
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
||||
const providerConfigPresent = cfg.channels?.discord !== undefined;
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveDiscordRuntimeGroupPolicy({
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent,
|
||||
groupPolicy: rawDiscordCfg.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
const discordCfg =
|
||||
rawDiscordCfg.groupPolicy === groupPolicy ? rawDiscordCfg : { ...rawDiscordCfg, groupPolicy };
|
||||
if (providerMissingFallbackApplied) {
|
||||
runtime.log?.(
|
||||
warn(
|
||||
'discord: channels.discord is missing; defaulting groupPolicy to "allowlist" (guild messages blocked until explicitly configured).',
|
||||
),
|
||||
);
|
||||
}
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "discord",
|
||||
accountId: account.accountId,
|
||||
blockedLabel: "guild messages",
|
||||
log: (message) => runtime.log?.(warn(message)),
|
||||
});
|
||||
let allowFrom = discordCfg.allowFrom ?? dmConfig?.allowFrom;
|
||||
const mediaMaxBytes = (opts.mediaMaxMb ?? discordCfg.mediaMaxMb ?? 8) * 1024 * 1024;
|
||||
const textLimit = resolveTextChunkLimit(cfg, "discord", account.accountId, {
|
||||
@@ -643,7 +628,7 @@ async function clearDiscordNativeCommands(params: {
|
||||
export const __testing = {
|
||||
createDiscordGatewayPlugin,
|
||||
dedupeSkillCommandsForDiscord,
|
||||
resolveDiscordRuntimeGroupPolicy,
|
||||
resolveDiscordRuntimeGroupPolicy: resolveOpenProviderRuntimeGroupPolicy,
|
||||
resolveDiscordRestFetch,
|
||||
resolveThreadBindingsEnabled,
|
||||
};
|
||||
|
||||
@@ -16,9 +16,11 @@ import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.j
|
||||
import { createReplyPrefixOptions } from "../../channels/reply-prefix.js";
|
||||
import { recordInboundSession } from "../../channels/session.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import {
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../../config/runtime-group-policy.js";
|
||||
import { readSessionUpdatedAt, resolveStorePath } from "../../config/sessions.js";
|
||||
import type { GroupPolicy } from "../../config/types.base.js";
|
||||
import { danger, logVerbose, shouldLogVerbose, warn } from "../../globals.js";
|
||||
import { normalizeScpRemoteHost } from "../../infra/scp-host.js";
|
||||
import { waitForTransportReady } from "../../infra/transport-ready.js";
|
||||
@@ -122,23 +124,6 @@ class SentMessageCache {
|
||||
}
|
||||
}
|
||||
|
||||
function resolveIMessageRuntimeGroupPolicy(params: {
|
||||
providerConfigPresent: boolean;
|
||||
groupPolicy?: GroupPolicy;
|
||||
defaultGroupPolicy?: GroupPolicy;
|
||||
}): {
|
||||
groupPolicy: GroupPolicy;
|
||||
providerMissingFallbackApplied: boolean;
|
||||
} {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): Promise<void> {
|
||||
const runtime = resolveRuntime(opts);
|
||||
const cfg = opts.config ?? loadConfig();
|
||||
@@ -163,18 +148,17 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
(imessageCfg.allowFrom && imessageCfg.allowFrom.length > 0 ? imessageCfg.allowFrom : []),
|
||||
);
|
||||
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveIMessageRuntimeGroupPolicy({
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.imessage !== undefined,
|
||||
groupPolicy: imessageCfg.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
if (providerMissingFallbackApplied) {
|
||||
runtime.log?.(
|
||||
warn(
|
||||
'imessage: channels.imessage is missing; defaulting groupPolicy to "allowlist" (group messages blocked until explicitly configured).',
|
||||
),
|
||||
);
|
||||
}
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "imessage",
|
||||
accountId: accountInfo.accountId,
|
||||
log: (message) => runtime.log?.(warn(message)),
|
||||
});
|
||||
const dmPolicy = imessageCfg.dmPolicy ?? "pairing";
|
||||
const includeAttachments = opts.includeAttachments ?? imessageCfg.includeAttachments ?? false;
|
||||
const mediaMaxBytes = (opts.mediaMaxMb ?? imessageCfg.mediaMaxMb ?? 16) * 1024 * 1024;
|
||||
@@ -540,5 +524,5 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
resolveIMessageRuntimeGroupPolicy,
|
||||
resolveIMessageRuntimeGroupPolicy: resolveOpenProviderRuntimeGroupPolicy,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,10 @@ import type {
|
||||
PostbackEvent,
|
||||
} from "@line/bot-sdk";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../config/runtime-group-policy.js";
|
||||
import {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
import { danger, logVerbose } from "../globals.js";
|
||||
import { resolvePairingIdLabel } from "../pairing/pairing-labels.js";
|
||||
import { buildPairingReply } from "../pairing/pairing-messages.js";
|
||||
@@ -41,8 +44,6 @@ export interface LineHandlerContext {
|
||||
processMessage: (ctx: LineInboundContext) => Promise<void>;
|
||||
}
|
||||
|
||||
let lineGroupPolicyFallbackWarned = false;
|
||||
|
||||
function resolveLineGroupConfig(params: {
|
||||
config: ResolvedLineAccount["config"];
|
||||
groupId?: string;
|
||||
@@ -136,19 +137,18 @@ async function shouldProcessLineEvent(
|
||||
dmPolicy,
|
||||
});
|
||||
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.line !== undefined,
|
||||
groupPolicy: account.config.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "allowlist",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
const { groupPolicy, providerMissingFallbackApplied } =
|
||||
resolveAllowlistProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.line !== undefined,
|
||||
groupPolicy: account.config.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "line",
|
||||
accountId: account.accountId,
|
||||
log: (message) => logVerbose(message),
|
||||
});
|
||||
if (providerMissingFallbackApplied && !lineGroupPolicyFallbackWarned) {
|
||||
lineGroupPolicyFallbackWarned = true;
|
||||
logVerbose(
|
||||
'line: channels.line is missing; defaulting groupPolicy to "allowlist" (group messages blocked until explicitly configured).',
|
||||
);
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
if (groupConfig?.enabled === false) {
|
||||
|
||||
@@ -133,8 +133,13 @@ export type {
|
||||
MSTeamsTeamConfig,
|
||||
} from "../config/types.js";
|
||||
export {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
resolveRuntimeGroupPolicy,
|
||||
type RuntimeGroupPolicyResolution,
|
||||
type RuntimeGroupPolicyParams,
|
||||
type ResolveProviderRuntimeGroupPolicyParams,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export {
|
||||
DiscordConfigSchema,
|
||||
|
||||
@@ -3,7 +3,10 @@ import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "../auto-reply/re
|
||||
import type { ReplyPayload } from "../auto-reply/types.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../config/runtime-group-policy.js";
|
||||
import {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
import type { SignalReactionNotificationMode } from "../config/types.js";
|
||||
import { waitForTransportReady } from "../infra/transport-ready.js";
|
||||
import { saveMediaBuffer } from "../media/store.js";
|
||||
@@ -346,18 +349,18 @@ export async function monitorSignalProvider(opts: MonitorSignalOpts = {}): Promi
|
||||
: []),
|
||||
);
|
||||
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.signal !== undefined,
|
||||
groupPolicy: accountInfo.config.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "allowlist",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
const { groupPolicy, providerMissingFallbackApplied } =
|
||||
resolveAllowlistProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: cfg.channels?.signal !== undefined,
|
||||
groupPolicy: accountInfo.config.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "signal",
|
||||
accountId: accountInfo.accountId,
|
||||
log: (message) => runtime.log?.(message),
|
||||
});
|
||||
if (providerMissingFallbackApplied) {
|
||||
runtime.log?.(
|
||||
'signal: channels.signal is missing; defaulting groupPolicy to "allowlist" (group messages blocked until explicitly configured).',
|
||||
);
|
||||
}
|
||||
const reactionMode = accountInfo.config.reactionNotifications ?? "own";
|
||||
const reactionAllowlist = normalizeAllowList(accountInfo.config.reactionAllowlist);
|
||||
const mediaMaxBytes = (opts.mediaMaxMb ?? accountInfo.config.mediaMaxMb ?? 8) * 1024 * 1024;
|
||||
|
||||
@@ -10,9 +10,11 @@ import {
|
||||
summarizeMapping,
|
||||
} from "../../channels/allowlists/resolve-utils.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import {
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../../config/runtime-group-policy.js";
|
||||
import type { SessionScope } from "../../config/sessions.js";
|
||||
import type { GroupPolicy } from "../../config/types.base.js";
|
||||
import { warn } from "../../globals.js";
|
||||
import { installRequestBodyLimitGuard } from "../../infra/http-body.js";
|
||||
import { normalizeMainKey } from "../../routing/session-key.js";
|
||||
@@ -43,23 +45,6 @@ const { App, HTTPReceiver } = slackBolt;
|
||||
const SLACK_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
|
||||
const SLACK_WEBHOOK_BODY_TIMEOUT_MS = 30_000;
|
||||
|
||||
function resolveSlackRuntimeGroupPolicy(params: {
|
||||
providerConfigPresent: boolean;
|
||||
groupPolicy?: GroupPolicy;
|
||||
defaultGroupPolicy?: GroupPolicy;
|
||||
}): {
|
||||
groupPolicy: GroupPolicy;
|
||||
providerMissingFallbackApplied: boolean;
|
||||
} {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
function parseApiAppIdFromAppToken(raw?: string) {
|
||||
const token = raw?.trim();
|
||||
if (!token) {
|
||||
@@ -119,18 +104,17 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
|
||||
let channelsConfig = slackCfg.channels;
|
||||
const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
|
||||
const providerConfigPresent = cfg.channels?.slack !== undefined;
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveSlackRuntimeGroupPolicy({
|
||||
const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent,
|
||||
groupPolicy: slackCfg.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
if (providerMissingFallbackApplied) {
|
||||
runtime.log?.(
|
||||
warn(
|
||||
'slack: channels.slack is missing; defaulting groupPolicy to "allowlist" (group messages blocked until explicitly configured).',
|
||||
),
|
||||
);
|
||||
}
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "slack",
|
||||
accountId: account.accountId,
|
||||
log: (message) => runtime.log?.(warn(message)),
|
||||
});
|
||||
|
||||
const resolveToken = slackCfg.userToken?.trim() || botToken;
|
||||
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
|
||||
@@ -384,5 +368,5 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
resolveSlackRuntimeGroupPolicy,
|
||||
resolveSlackRuntimeGroupPolicy: resolveOpenProviderRuntimeGroupPolicy,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { ChannelGroupPolicy } from "../config/group-policy.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../config/runtime-group-policy.js";
|
||||
import { resolveOpenProviderRuntimeGroupPolicy } from "../config/runtime-group-policy.js";
|
||||
import type {
|
||||
TelegramAccountConfig,
|
||||
TelegramGroupConfig,
|
||||
@@ -78,12 +78,10 @@ export const resolveTelegramRuntimeGroupPolicy = (params: {
|
||||
groupPolicy?: TelegramAccountConfig["groupPolicy"];
|
||||
defaultGroupPolicy?: TelegramAccountConfig["groupPolicy"];
|
||||
}) =>
|
||||
resolveRuntimeGroupPolicy({
|
||||
resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
|
||||
export const evaluateTelegramGroupPolicyAccess = (params: {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { resolveRuntimeGroupPolicy } from "../../config/runtime-group-policy.js";
|
||||
import {
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
warnMissingProviderGroupPolicyFallbackOnce,
|
||||
} from "../../config/runtime-group-policy.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { buildPairingReply } from "../../pairing/pairing-messages.js";
|
||||
import {
|
||||
@@ -26,12 +29,10 @@ function resolveWhatsAppRuntimeGroupPolicy(params: {
|
||||
groupPolicy: "open" | "allowlist" | "disabled";
|
||||
providerMissingFallbackApplied: boolean;
|
||||
} {
|
||||
return resolveRuntimeGroupPolicy({
|
||||
return resolveOpenProviderRuntimeGroupPolicy({
|
||||
providerConfigPresent: params.providerConfigPresent,
|
||||
groupPolicy: params.groupPolicy,
|
||||
defaultGroupPolicy: params.defaultGroupPolicy,
|
||||
configuredFallbackPolicy: "open",
|
||||
missingProviderFallbackPolicy: "allowlist",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,11 +106,12 @@ export async function checkInboundAccessControl(params: {
|
||||
groupPolicy: account.groupPolicy,
|
||||
defaultGroupPolicy,
|
||||
});
|
||||
if (providerMissingFallbackApplied) {
|
||||
logVerbose(
|
||||
'whatsapp: channels.whatsapp is missing; defaulting groupPolicy to "allowlist" (group messages blocked until explicitly configured).',
|
||||
);
|
||||
}
|
||||
warnMissingProviderGroupPolicyFallbackOnce({
|
||||
providerMissingFallbackApplied,
|
||||
providerKey: "whatsapp",
|
||||
accountId: account.accountId,
|
||||
log: (message) => logVerbose(message),
|
||||
});
|
||||
if (params.group && groupPolicy === "disabled") {
|
||||
logVerbose("Blocked group message (groupPolicy: disabled)");
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user