mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 15:47:28 +00:00
fix(telegram/groups): treat empty accounts.<id>.groups: {} as unspecified in single-account setups
`mergeTelegramAccountConfig` and the generic `resolveChannelGroups` both used
`accountGroups ?? channelConfig.groups` to fall back to root group allowlists,
which only catches the `undefined` case. An explicit empty `{}` survives
nullish coalescing and overrides the root allowlist with an empty allowlist,
which then pairs with the default `groupPolicy: "allowlist"` to silently
deny every group update — the symptom reported in #79427.
Treat an explicit empty `{}` the same as undefined for fallback purposes in
single-account setups (one or zero configured accounts). Multi-account setups
keep current semantics so per-account explicit-empty groups still scope
disable a single account without affecting its siblings. The explicit way to
block all groups for any account remains `groupPolicy: "disabled"`, which
this PR does not touch.
Fixes #79427.
This commit is contained in:
committed by
Peter Steinberger
parent
d540512d00
commit
ab719c2f82
@@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai
|
||||
- fix(gateway): honor minimal discovery mode for wide-area DNS-SD [AI]. (#80903) Thanks @pgondhi987.
|
||||
- slack: enforce reaction notification policy [AI]. (#80907) Thanks @pgondhi987.
|
||||
- Enforce gateway command scopes by caller context [AI]. (#80891) Thanks @pgondhi987.
|
||||
- Telegram/groups: in single-account setups, treat an explicit empty `accounts.<id>.groups: {}` map the same as undefined so the root `channels.telegram.groups` allowlist still applies, instead of silently dropping every group update under the default `groupPolicy: "allowlist"`. Multi-account semantics are unchanged so per-account explicit-empty groups still scope-disable a single account without affecting siblings; the explicit way to block all groups for any account remains `groupPolicy: "disabled"`. Fixes #79427. Thanks @nikolaykazakovvs-ux.
|
||||
- Enforce Slack plugin approval button authorization [AI]. (#80899) Thanks @pgondhi987.
|
||||
- Recognize PowerShell -ec inline commands [AI]. (#80893) Thanks @pgondhi987.
|
||||
- fix(qqbot): authorize approval button callbacks [AI]. (#80892) Thanks @pgondhi987.
|
||||
|
||||
@@ -68,9 +68,19 @@ export function mergeTelegramAccountConfig(
|
||||
const account = resolveTelegramAccountConfig(cfg, accountId) ?? {};
|
||||
|
||||
// Multi-account bots must not inherit channel-level groups unless explicitly set.
|
||||
// Single-account bots fall back to root `channels.telegram.groups` when the
|
||||
// account does not declare its own groups — including the empty-literal case
|
||||
// `accounts.<id>.groups: {}`, which is almost always a config-migration
|
||||
// artifact rather than an intentional "block all" declaration (use
|
||||
// `groupPolicy: "disabled"` for that).
|
||||
const configuredAccountIds = Object.keys(cfg.channels?.telegram?.accounts ?? {});
|
||||
const isMultiAccount = configuredAccountIds.length > 1;
|
||||
const groups = account.groups ?? (isMultiAccount ? undefined : channelGroups);
|
||||
const hasAccountGroups = account.groups && Object.keys(account.groups).length > 0;
|
||||
const groups = isMultiAccount
|
||||
? account.groups
|
||||
: hasAccountGroups
|
||||
? account.groups
|
||||
: channelGroups;
|
||||
const allowFrom = resolveMergedAllowFrom({
|
||||
baseAllowFrom: base.allowFrom,
|
||||
accountAllowFrom: account.allowFrom,
|
||||
|
||||
@@ -536,6 +536,24 @@ describe("resolveTelegramAccount groups inheritance (#30673)", () => {
|
||||
expect(resolved.config.groups).toEqual({ "-100123": { requireMention: false } });
|
||||
});
|
||||
|
||||
it("inherits channel-level groups when single-account explicitly sets `groups: {}` (regression: #79427)", () => {
|
||||
const resolved = resolveTelegramAccount({
|
||||
cfg: {
|
||||
channels: {
|
||||
telegram: {
|
||||
groups: { "-100123": { requireMention: false } },
|
||||
accounts: {
|
||||
default: { botToken: "123:default", groups: {} },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
accountId: "default",
|
||||
});
|
||||
|
||||
expect(resolved.config.groups).toEqual({ "-100123": { requireMention: false } });
|
||||
});
|
||||
|
||||
it("does NOT inherit channel-level groups to secondary account in multi-account setup", () => {
|
||||
const resolved = resolveTelegramAccount({
|
||||
cfg: createMultiAccountGroupsConfig(),
|
||||
|
||||
@@ -169,6 +169,68 @@ describe("resolveChannelGroupPolicy", () => {
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("falls back to root channel groups when account.groups is an empty object (regression: #79427)", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
groupPolicy: "allowlist",
|
||||
groups: {
|
||||
"-100123": { requireMention: false },
|
||||
},
|
||||
accounts: {
|
||||
default: { botToken: "123:default", groups: {} },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const policy = resolveChannelGroupPolicy({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
groupId: "-100123",
|
||||
accountId: "default",
|
||||
});
|
||||
|
||||
expect(policy.allowlistEnabled).toBe(true);
|
||||
expect(policy.allowed).toBe(true);
|
||||
});
|
||||
|
||||
it("uses populated account.groups instead of root when both are configured", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
telegram: {
|
||||
groupPolicy: "allowlist",
|
||||
groups: {
|
||||
"-100root": { requireMention: false },
|
||||
},
|
||||
accounts: {
|
||||
default: {
|
||||
botToken: "123:default",
|
||||
groups: { "-100account": { requireMention: false } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
expect(
|
||||
resolveChannelGroupPolicy({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
groupId: "-100account",
|
||||
accountId: "default",
|
||||
}).allowed,
|
||||
).toBe(true);
|
||||
expect(
|
||||
resolveChannelGroupPolicy({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
groupId: "-100root",
|
||||
accountId: "default",
|
||||
}).allowed,
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveToolsBySender", () => {
|
||||
|
||||
@@ -340,6 +340,21 @@ function resolveChannelGroups(
|
||||
return undefined;
|
||||
}
|
||||
const accountGroups = resolveAccountEntry(channelConfig.accounts, normalizedAccountId)?.groups;
|
||||
// In a single-account setup, treat an explicit empty account groups map
|
||||
// (`accounts.<id>.groups: {}`) the same as undefined for fallback: the empty
|
||||
// literal is almost always a config-migration artifact, not an intentional
|
||||
// "block all groups" declaration — the explicit way to block is
|
||||
// `groupPolicy: "disabled"` (or omitting the group from a populated
|
||||
// allowlist). Without this, an empty `{}` paired with the default
|
||||
// `groupPolicy: "allowlist"` silently denies every group update even though
|
||||
// root `channels.<channel>.groups` is populated. Multi-account contexts keep
|
||||
// the existing semantics so per-account explicit-empty groups still scope
|
||||
// disable a single account without affecting siblings.
|
||||
const isMultiAccount = Object.keys(channelConfig.accounts ?? {}).length > 1;
|
||||
if (!isMultiAccount) {
|
||||
const hasAccountGroups = accountGroups && Object.keys(accountGroups).length > 0;
|
||||
return hasAccountGroups ? accountGroups : channelConfig.groups;
|
||||
}
|
||||
return accountGroups ?? channelConfig.groups;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user