feat(gateway): WhatsApp group authz + owner detection + reactions (fixes #7269) - #53623
Open
sdugoten wants to merge 5 commits into
Open
feat(gateway): WhatsApp group authz + owner detection + reactions (fixes #7269)#53623sdugoten wants to merge 5 commits into
sdugoten wants to merge 5 commits into
Conversation
Collaborator
Fixes the issue where a WhatsApp group member is rejected under require_mention unless they're in WHATSAPP_ALLOWED_USERS, and brings WhatsApp to Telegram parity. - authz_mixin: WHATSAPP / WHATSAPP_CLOUD group-allowlist entry so WHATSAPP_GROUP_ALLOWED_USERS authorizes the group; generic _is_owner() fallback. - whatsapp_common: _set_owner_flag() resolves the group sender (LID) to the owner via WHATSAPP_ALLOWED_USERS; called at intake by BOTH the Cloud adapter and the Baileys plugin adapter (plugins/platforms/whatsapp/adapter.py). - run.py/session.py: owner surfaced WITHOUT changing the [name] prefix — a **Owner:** context line + an additive [SYSTEM: sender NAME is the owner] marker. Gated to WHATSAPP/WHATSAPP_CLOUD so other platforms stay byte-identical (other platforms can opt in by adding themselves to the set). - plugin adapter + bridge.js: reaction progress indicators — 👀 while processing, ✅/❌ when done, cleared on cancel (parity with Telegram); WHATSAPP_REACTIONS=false to disable. New bridge POST /send-reaction.
sdugoten
force-pushed
the
feat/whatsapp-group-parity-owner-detection
branch
from
June 27, 2026 13:05
775ad47 to
94cbdee
Compare
sdugoten
marked this pull request as ready for review
June 27, 2026 13:32
This was referenced Jun 27, 2026
teknium1
reviewed
Jul 15, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for tackling WhatsApp group parity; the underlying intake path still needs work on current main.
Problems
scripts/whatsapp-bridge/bridge.js:637drops a non-self sender not inWHATSAPP_ALLOWED_USERSbefore the Python gateway sees it, including a group member. This PR does not change that gate, so its gateway allowlist cannot fix the stated Baileys configuration.- WhatsApp Cloud currently drops group-shaped inbound payloads at
gateway/platforms/whatsapp_cloud.py:1891-1899; the proposed Cloud authz/owner wiring cannot provide the claimed group behavior. WHATSAPP_REACTIONSis a new user-facing non-secret environment setting.AGENTS.mdrequires behavioral settings to useconfig.yaml.- No regression test covers the bridge → adapter → gateway authorization path; existing group-policy coverage is adapter-level (
tests/gateway/test_whatsapp_group_gating.py:262-272).
Suggested changes
- Rework the Baileys intake gate around the existing
whatsapp.group_policy/group_allow_frommodel, then add an end-to-end regression for an unlisted member mentioning the bot in an allowlisted group. - Scope the patch to Baileys until Cloud group intake is implemented, and place reaction configuration in
config.yaml.
Automated hermes-sweeper review.
| Platform.TELEGRAM: "TELEGRAM_GROUP_ALLOWED_CHATS", | ||
| Platform.QQBOT: "QQ_GROUP_ALLOWED_USERS", | ||
| Platform.WHATSAPP: "WHATSAPP_GROUP_ALLOWED_USERS", | ||
| Platform.WHATSAPP_CLOUD: "WHATSAPP_GROUP_ALLOWED_USERS", |
Contributor
There was a problem hiding this comment.
WHATSAPP_CLOUD cannot use this group allowlist yet: current gateway/platforms/whatsapp_cloud.py:1891-1899 drops every group-shaped payload before gateway authz. Please omit the Cloud entry or implement Cloud group intake first.
…ope, bridge group gate, reactions config, e2e test Four items from the hermes-sweeper review: 1. bridge.js group gate (scripts/whatsapp-bridge/bridge.js) The WHATSAPP_ALLOWED_USERS gate dropped non-self, non-allowlisted senders — including group members — before the Python gateway saw them, so a concrete allowlist (required for owner detection) meant only the owner could trigger the bot in a group. Gate is now DM-only; group messages pass through to the gateway, which authorizes via the documented whatsapp.group_policy / group_allow_from model and applies require_mention. 2. Scope to Baileys (gateway/platforms/whatsapp_cloud.py) WhatsApp Cloud drops group-shaped inbound earlier in the handler, so wiring owner detection there was dead code. Removed; documented to re-add once Cloud group intake exists. Baileys owner detection is unchanged. 3. Reactions setting -> config.yaml (plugins/platforms/whatsapp/adapter.py) WHATSAPP_REACTIONS is a behavioral setting; AGENTS.md requires config.yaml. Now read from whatsapp.reactions (legacy env kept as a fallback). 4. Regression test (tests/gateway/test_whatsapp_group_gating.py) Adds an end-to-end authorization test: an unlisted group member @mentioning the bot in an allowlisted group is processed by the adapter AND authorized by the gateway, while the same sender in a DM is denied. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # gateway/authz_mixin.py # gateway/session.py # scripts/whatsapp-bridge/bridge.js
19 tasks
Signal DMs already resolve source.is_owner via the generic _is_owner() fallback (SIGNAL_ALLOWED_USERS), but the two owner-marker opt-in gates (the **Owner:** session-prompt line and the additive [SYSTEM: sender NAME is the owner] message marker) only listed WHATSAPP/WHATSAPP_CLOUD. Add Platform.SIGNAL to both gates so Signal gets the same owner disclosure as WhatsApp once is_owner is set, and add regression tests covering all three gated platforms plus the non-gated/shared-session cases.
…-parity-owner-detection # Conflicts: # gateway/run.py # tests/gateway/test_shared_group_sender_prefix.py
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Fixes #7269 — in a WhatsApp group with
require_mention: true, the bot only replies to senders already inWHATSAPP_ALLOWED_USERS; a normal group member who @mentions it is rejected. This brings WhatsApp to Telegram parity: any allowed-group member can talk to the bot, the bot knows which sender is the owner, and messages get 👀→✅ progress reactions — without changing the[name]sender prefix or any other platform's behavior.The changes
1. Group-member authorization —
gateway/authz_mixin.pyAdds
WHATSAPP/WHATSAPP_CLOUD→WHATSAPP_GROUP_ALLOWED_USERSto the group-allowlist dict, soWHATSAPP_GROUP_ALLOWED_USERS=*authorizes the whole group exactly likeTELEGRAM_GROUP_ALLOWED_CHATS. Direct fix for the issue.2. Owner detection (both transports) —
whatsapp_common.py,whatsapp_cloud.py,plugins/platforms/whatsapp/adapter.py_set_owner_flag()resolves the group sender's LID to the owner viaWHATSAPP_ALLOWED_USERS+ the on-disk alias map and setssource.is_ownerat intake. Called by both the Cloud adapter and the Baileys plugin adapter. A generic_is_owner()fallback covers the DM path; wildcard*is never an owner.3. Surfacing the owner — gated, additive, no
[name]change —gateway/run.py,gateway/session.py**Owner:** yes/nocontext line;[name]and prepend an owner-only[SYSTEM: sender NAME is the owner]marker (guests byte-identical to upstream).Both outputs are gated to
WHATSAPP/WHATSAPP_CLOUD, so Telegram/Slack/Discord/etc. are completely unaffected. The gate is asource.platform in {...}set with a comment inviting other platforms to opt in once their adapter setssource.is_owner.4. Reaction progress indicators —
plugins/platforms/whatsapp/adapter.py,scripts/whatsapp-bridge/bridge.jsOverrides the base
on_processing_start/on_processing_completehooks (which the gateway already calls for every platform): 👀 while processing, ✅/❌ when done, and clears the 👀 on cancel so it never lingers (parity with the Telegram adapter). New bridge endpointPOST /send-reaction(Baileysreact; empty emoji removes). Disable withWHATSAPP_REACTIONS=false.Scope notes
_is_owner, therun.pymarker,session.pyis_owner) is shared with the Signal PR feat(gateway): bring Signal groups to Telegram parity (authz, mention, owner detection) #53348; whichever merges first, the other's shared hunks become no-ops, and the gate set merges to{SIGNAL, WHATSAPP, WHATSAPP_CLOUD}.How to test
.env:WHATSAPP_GROUP_ALLOWED_USERS=*,WHATSAPP_ALLOWED_USERS=<owner phone/LID>(concrete, not*).config.yaml:whatsapp: { require_mention: true }.[SYSTEM: sender … is the owner]; everyone else plain[name]. (2,3)Platforms tested
macOS (Apple Silicon), Baileys bridge (bot mode). Owner-surfacing + reactions are additive/gated; non-WhatsApp adapters unaffected.
Related