Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(whatsapp): per-group allowFrom for sender authorization#81053

Open
jack-stormentswe wants to merge 1 commit into
openclaw:mainfrom
jack-stormentswe:fix/whatsapp-per-group-allow-from
Open

feat(whatsapp): per-group allowFrom for sender authorization#81053
jack-stormentswe wants to merge 1 commit into
openclaw:mainfrom
jack-stormentswe:fix/whatsapp-per-group-allow-from

Conversation

@jack-stormentswe
Copy link
Copy Markdown
Contributor

Fixes #69926.

Brings WhatsApp to parity with Feishu, IRC, LINE, Telegram, and Nextcloud-talk by accepting a per-group allowFrom list on channels.whatsapp.groups.<jid> (and the matching account-scoped entry). A non-empty per-group allowFrom overrides (does not merge with) the channel/account-level groupAllowFrom for that one JID, while groups without an override keep the channel/account-level list. Empty arrays fall back to the channel/account-level allowlist.

ClawSweeper triage explicitly cleared this as "narrow, source-proven feature gap with clear files, tests, and boundaries."

Change

  • WhatsAppGroupEntrySchema and WhatsAppGroupConfig gain an optional allowFrom: string[] (E.164 phone numbers).
  • New resolveWhatsAppConversationGroupAllowFrom resolver in extensions/whatsapp/src/inbound-policy.ts, wired into resolveWhatsAppIngressAccess so the effective groupAllowFrom passed to resolveStableChannelMessageIngress reflects the per-group override for group conversations.
  • The resolver respects the same multi-account inheritance guard as the rest of the WhatsApp config: account-scoped groups[<jid>].allowFrom takes precedence over a root-scope entry for the same JID, so root groups do not silently leak into accounts with their own groups map.
  • bundled-channel-config-metadata.generated.ts regenerated to surface the new field in the bundled channel schema (verified via pnpm config:channels:check).
  • docs/channels/whatsapp.md documents the per-group override semantics and shows a mixed-trust example.

Verification

  • pnpm test extensions/whatsapp/src/inbound-policy.test.ts extensions/whatsapp/src/config-schema.test.ts -- 17/17 pass (6 new resolver cases + 2 new schema cases + existing schema tests).
  • pnpm config:channels:check clean.
  • pnpm exec oxfmt --check --threads=1 clean on every touched file.

Real behavior proof

Behavior addressed: operators should be able to express different sender allowlists per WhatsApp group (e.g. "Group A: any team member can drive the bot; Group B: only staff; Group C: only me") without dropping back to a single channel-wide allowlist. The runtime resolver should also honor the multi-account inheritance guard so root-scope per-group lists do not leak into accounts with their own groups map.

Real environment tested: local Linux 6.17 (Node 22.22.2). Live Node process driving the real production resolveWhatsAppInboundPolicy and resolveWhatsAppConversationGroupAllowFrom helpers from this PR (no mocks). The proof feeds the helper realistic OpenClaw configs (single-account, multi-account, override+inherit+empty cases) and prints the effective groupAllowFrom the inbound gate would apply.

Exact steps or command run after this patch:

node --import tsx /tmp/proof-69926.mts

Where /tmp/proof-69926.mts directly imports the production resolver helpers from extensions/whatsapp/src/inbound-policy.ts and validates per-group override, fallback on empty, account-scoped override, and inheritance behavior across seven scenarios.

Evidence after fix: terminal output captured directly from the live Node process exercising the production helpers.

--- channel-level only (single-account) ---
  group with per-group allowFrom override
    -> ["+15550003333","+15550004444"]
  group with a different per-group allowFrom
    -> ["+15550005555"]
  group WITHOUT override -> inherits channel-level
    -> ["+15550001111"]
  empty per-group allowFrom -> inherits channel-level
    -> ["+15550001111"]

--- multi-account: account-scoped groups override account-level groupAllowFrom ---
  work account, group has per-group override
    -> ["+15550007777"]
  work account, no override on this jid -> inherits work groupAllowFrom
    -> ["+15550008888"]
  personal account, no groups map at all -> inherits personal groupAllowFrom
    -> ["+15550006666"]

Observed result after fix:

  • Group with a per-group allowFrom returns exactly that list, suppressing the channel-level groupAllowFrom for that JID.
  • A different per-group entry returns its own list independently -- the override is per-JID, not channel-wide.
  • A group without a per-group entry returns the channel-level groupAllowFrom, so existing configs keep working unchanged.
  • An empty allowFrom: [] falls back to the channel-level list, so accidental empties do not silently fail closed for the group.
  • In a multi-account config, the work account's per-group override applies for that JID, and groups without overrides correctly inherit the work account's groupAllowFrom rather than leaking from the personal account or the channel root.
  • The personal account, which has no groups map of its own, falls back to its own account-level groupAllowFrom.

What was not tested: a live WhatsApp message ingress against a real WhatsApp Web account. The runtime proof above exercises the production resolver and resolveWhatsAppInboundPolicy chain, and the unit suite covers the schema acceptance plus the resolver semantics under every documented case, but neither runs a real inbound WhatsApp event against a paired account.

…w#69926)

Bring WhatsApp to parity with Feishu, IRC, LINE, Telegram, and
Nextcloud-talk by accepting a per-group `allowFrom` list on
`channels.whatsapp.groups.<jid>` (and the matching account-scoped
entry). A non-empty per-group `allowFrom` overrides (does not merge
with) the channel/account-level `groupAllowFrom` for that one JID,
while groups without an override keep the channel/account-level list.
Empty arrays fall back to the channel/account-level allowlist.

The resolver respects the same multi-account inheritance guard as the
rest of the WhatsApp config: account-scoped `groups[<jid>].allowFrom`
takes precedence over a root-scope entry for the same JID, so root
groups do not silently leak into accounts with their own groups map.

Changes:

- `WhatsAppGroupEntrySchema` and `WhatsAppGroupConfig` gain an
  optional `allowFrom: string[]` (E.164 phone numbers).
- New `resolveWhatsAppConversationGroupAllowFrom` resolver in
  `inbound-policy.ts`, wired into `resolveWhatsAppIngressAccess` so
  the effective `groupAllowFrom` passed to
  `resolveStableChannelMessageIngress` reflects the per-group
  override for group conversations.
- `bundled-channel-config-metadata.generated.ts` regenerated to
  surface the new field in the bundled channel schema.
- `docs/channels/whatsapp.md` documents the per-group override and
  shows a mixed-trust example.

Tests:

- New `extensions/whatsapp/src/inbound-policy.test.ts` covers the
  resolver semantics: override applied, empty list falls back,
  unrelated groups inherit the account-level list, account-scoped
  groups override root-scope entries, missing groups map returns the
  account-level allowlist.
- `extensions/whatsapp/src/config-schema.test.ts` gains two cases for
  the new field at root and account scope.

Fixes openclaw#69926.
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: whatsapp-web Channel integration: whatsapp-web size: M proof: supplied External PR includes structured after-fix real behavior proof. labels May 12, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 12, 2026

Codex review: needs maintainer review before merge.

Summary
The PR adds WhatsApp per-group allowFrom config support, runtime resolution, generated channel metadata, docs, changelog, and focused schema/resolver tests.

Reproducibility: yes. for the feature gap: current main's strict WhatsApp group schema omits allowFrom, and the inbound policy passes only the account/channel-level groupAllowFrom. I did not run a failing config parse because the review checkout is read-only, but the source path is direct.

Real behavior proof
Sufficient (terminal): The PR body includes after-fix terminal output from a live Node process importing the production resolver helpers from the PR and showing override, fallback, and multi-account behavior.

Next step before merge
No repair lane is needed; this open PR is the implementation path and I found no narrow automation-fixable defect.

Security
Cleared: The diff touches WhatsApp config/runtime/docs/tests/generated metadata only and does not add dependencies, workflows, scripts, secret handling, or new external code execution.

Review details

Best possible solution:

Land a WhatsApp-owned additive config/runtime/docs update that preserves existing channel-level fallback while allowing explicit per-group sender authorization.

Do we have a high-confidence way to reproduce the issue?

Yes for the feature gap: current main's strict WhatsApp group schema omits allowFrom, and the inbound policy passes only the account/channel-level groupAllowFrom. I did not run a failing config parse because the review checkout is read-only, but the source path is direct.

Is this the best way to solve the issue?

Yes. The PR keeps the change inside the WhatsApp plugin/config surface, reuses the existing stable ingress resolver, and avoids changing unrelated group admission or global denylist behavior.

What I checked:

  • current_main_schema_gap: Current main's strict WhatsApp group-entry schema includes requireMention, tools, toolsBySender, and systemPrompt, but not allowFrom, so the requested group-scoped sender allowlist is not accepted on main. (src/config/zod-schema.providers-whatsapp.ts:21, 7c2c91a0fa8b)
  • current_main_runtime_gap: Current main derives one resolved groupAllowFrom from the account/channel and passes that list directly to resolveStableChannelMessageIngress; it does not inspect the matched WhatsApp group entry for sender authorization. (extensions/whatsapp/src/inbound-policy.ts:90, 7c2c91a0fa8b)
  • pr_runtime_change: The PR head adds resolveWhatsAppConversationGroupAllowFrom and passes effectiveGroupAllowFrom into the stable ingress resolver for group conversations. (extensions/whatsapp/src/inbound-policy.ts:136, 3f60f7b316a5)
  • pr_schema_docs_tests: The PR head adds allowFrom?: string[] to the WhatsApp group type/schema, documents the override/fallback semantics, and adds resolver tests for override, fallback, and account-scoped inheritance cases. (extensions/whatsapp/src/inbound-policy.test.ts:12, 3f60f7b316a5)
  • related_issue_context: The linked feature issue is still open and has a ClawSweeper comment calling this a narrow, source-proven feature gap with clear files, tests, and boundaries; it also records the intended owner routing and acceptance criteria.
  • history_current_main: Current WhatsApp inbound policy, account config, schema, type, and docs files in this checkout trace to commit f1ce79b in local blame/log history, making it the local current-main provenance anchor for the reviewed code path. (extensions/whatsapp/src/inbound-policy.ts:77, f1ce79ba6c40)

Likely related people:

  • @omarshahine: The linked feature issue is assigned to @omarshahine, and the issue discussion specifically routed the WhatsApp multi-account and inbound-auth follow-up to him. (role: domain reviewer / assigned follow-up owner; confidence: medium; commits: 08bc16853ef4; files: extensions/whatsapp/src/inbound-policy.ts, extensions/whatsapp/src/account-config.ts, extensions/whatsapp/src/inbound/access-control.ts)
  • Bluetegu: The related issue's prior ClawSweeper review identifies Bluetegu as the author of merged WhatsApp group/direct system-prompt work that this sender-authorization feature extends. (role: introduced adjacent behavior; confidence: medium; commits: 63e2b50e01de, 08bc16853ef4; files: src/config/types.whatsapp.ts, src/config/zod-schema.providers-whatsapp.ts, extensions/whatsapp/src/system-prompt.ts)
  • Peter Steinberger: Local blame shows the current-main WhatsApp inbound policy, account config, schema, type, and docs files in this checkout were introduced or rewritten in commit f1ce79b. (role: recent area contributor; confidence: medium; commits: f1ce79ba6c40; files: extensions/whatsapp/src/inbound-policy.ts, extensions/whatsapp/src/account-config.ts, src/config/zod-schema.providers-whatsapp.ts)

Remaining risk / open question:

  • I did not run the PR tests in this read-only review checkout; the PR body reports the focused WhatsApp tests, generated-config check, and formatting check as passing.
  • The supplied proof exercises production resolver helpers, not a live paired WhatsApp Web inbound message; that is acceptable for this config-resolution feature but leaves full live ingress as residual maintainer validation.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 7c2c91a0fa8b.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: whatsapp-web Channel integration: whatsapp-web docs Improvements or additions to documentation proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: WhatsApp: per-group allowFrom for sender authorization (parity with Feishu/IRC/LINE/Telegram/Nextcloud-talk)

1 participant