← Back to PRs

#11611: feat: separate group-level allowlist from sender-level command authorization

by thisnick open 2026-02-08 02:15 View on GitHub →
docs channel: telegram channel: whatsapp-web gateway size: M
## Problem Currently `groupPolicy: "allowlist"` + `groupAllowFrom` gates **all** group interaction (both chat and commands) by sender phone number. There is no way to: 1. Allowlist specific groups by JID while letting anyone in those groups chat 2. Restrict slash commands (`/new`, `/reset`, etc.) to the owner only 3. Prevent the bot from being pulled into spam groups while keeping approved groups open to all participants ## Solution When `groupPolicy: "allowlist"` is set **and** a `groups` config is present (mapping group JIDs), the access control layer now uses the `groups` config as the group-level gate instead of filtering by sender via `groupAllowFrom`. This means: - **Group-level filtering:** Only groups listed in `groups` config are accepted (spam groups blocked) - **Open chat in approved groups:** Anyone in an approved group can chat (mention or always-on) - **Command authorization unchanged:** `groupAllowFrom` continues to gate slash command access, so only the owner (or specified senders) can run `/new`, `/reset`, etc. ### Example config ```yaml channels: whatsapp: groupPolicy: allowlist groupAllowFrom: ["+1234567890"] # only owner can run slash commands groups: "my-group-123@g.us": requireMention: true "another-group@g.us": {} ``` ### Backward compatibility When no `groups` config is present, the existing sender-based `groupAllowFrom` filtering is preserved exactly as before. ## Changes - **`src/web/inbound/access-control.ts`** — Integrate `resolveChannelGroupPolicy` to check group JID allowlist when `groups` config is present - **`src/config/types.whatsapp.ts`** — Updated JSDoc for `groupPolicy` to document the new behavior - **`src/web/inbound/access-control.group-allowlist.test.ts`** — 4 new tests covering the group allowlist behavior ## Dependencies - Depends on #3326 — this PR incorporates their fix (only enable group allowlist when `groupPolicy` is explicitly `"allowlist"`, preventing implicit allowlist when `groups` config coexists with `groupPolicy: "open"`) ## Manual Testing 1. Set `groupPolicy: "allowlist"` with specific `groups` entries and `groupAllowFrom` with just your number 2. Send a message from a **non-allowlisted sender** in an approved group → ✅ should be received 3. Send `/new` from a **non-allowlisted sender** → ✅ should be silently ignored (only `groupAllowFrom` numbers can run slash commands) 4. Send a message from any **group not in `groups` config** → ❌ should be blocked 5. Remove `groups` entries → falls back to old sender-based filtering via `groupAllowFrom` (backward compat) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR changes WhatsApp `groupPolicy: "allowlist"` handling so that when a `channels.whatsapp.groups` mapping is present, inbound group access is gated by group JID membership in that mapping (via `resolveChannelGroupPolicy`), rather than by sender phone number. When no `groups` config is present, the prior sender-based behavior (using `groupAllowFrom`/`allowFrom`) remains. It also updates the WhatsApp config type docs to describe the new behavior and adds a dedicated Vitest suite covering: (1) allowing messages from an approved group JID, (2) blocking unapproved group JIDs, (3) legacy sender-based fallback when no `groups` config exists, and (4) confirming that approved groups allow any sender to chat while command authorization remains separate. <h3>Confidence Score: 4/5</h3> - This PR appears safe to merge, with one small documentation inconsistency to fix. - Core logic change is localized to `checkInboundAccessControl` and delegates group-JID gating to `resolveChannelGroupPolicy`, preserving the legacy sender-based path when no groups mapping exists. Added tests cover the new branches. Only issue found is an outdated inline comment that no longer matches behavior; runtime logic impact is unlikely beyond intended policy change. - src/web/inbound/access-control.ts (update the stale allowlist comment) <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs