fix(gateway): authorize Signal group members via SIGNAL_GROUP_ALLOWED_USERS - #44706
fix(gateway): authorize Signal group members via SIGNAL_GROUP_ALLOWED_USERS#44706StepWise1234 wants to merge 1 commit into
Conversation
…_USERS
The chat-allowlist bypass in `authz_mixin._is_user_authorized` previously
only enumerated Telegram and QQBOT, so Signal group messages always fell
through to the per-user `SIGNAL_ALLOWED_USERS` check. Operators who set
`SIGNAL_GROUP_ALLOWED_USERS` expected groups to "just work" the way they
do on Telegram, but every group member not also listed in
`SIGNAL_ALLOWED_USERS` was silently rejected with
`WARNING gateway.run: Unauthorized user: <uuid> (<name>) on signal`.
Two fixes in `gateway/authz_mixin.py`:
1. Add `Platform.SIGNAL -> "SIGNAL_GROUP_ALLOWED_USERS"` to
`chat_allowlist_env`. The env var name was chosen long ago and is
already consumed by `platforms/signal.py` as a group-ID list — this
just makes auth honor the same setting.
2. Normalize `source.chat_id` by stripping the `group:` prefix before
comparison. `platforms/signal.py` builds Signal chat_ids as
`f"group:{group_id}"` (line ~520), while the env value is stored
unprefixed (signal.py's own filter at line ~515 compares unprefixed).
Without normalization, the equality check would still fail.
Adds `tests/gateway/test_signal_group_auth.py` with 10 cases mirroring
the existing channel-allowlist test pattern (private helper mirrors the
patched branch, stdlib only, no Hermes imports).
All 376 tests across the 18 auth/allowlist/signal gateway test files
pass with this change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Verification review — LGTM ✅ Reviewed the diff and test suite. This is a clean, well-scoped fix. What was checked:
|
|
Reviewed the diff — this is a clean security fix. Two things verified:
Test coverage is thorough (156 lines covering prefixed/unprefixed IDs, wildcards, empty lists, multiple groups, DM bypass, forum/channel types). |
|
having the same problem, have SIGNAL_GROUP_ALLOWED_USERS=*, but no other people except owner can talk to hermes. anyone talk in the group will see this in the log 2026-06-23 16:10:33,989 WARNING gateway.run: Unauthorized user: 4baxxxxx-a094-4606-xxxx-acf9658a5290 (Michelle🌷☃️) on signal
|
|
same fix for whatsapp is here Ok, after messing with the soruce code a bit, this patch would enable group chat in signal. The changes is based on the Telegram adapter implementation
SIGNAL_ACCOUNT=+9876543210
signal:
In the SOUL.md , add something like this would make the bot only execute privilege command from the owner CRITICAL: In a group chat, if the other party's message begins with |
|
Thanks again — same root cause I hit on Signal. I've updated #53348, which includes this exact
So #53348 should supersede this draft. Happy to credit/co-author or fold it in however the maintainers prefer — flagging here so we don't duplicate the authz-dict change. |
…, owner detection) Signal group chats lagged Telegram/WhatsApp. This brings parity: - authz_mixin: authorize Signal group members via SIGNAL_GROUP_ALLOWED_USERS (same env signal.py already honors); add a generic _is_owner() fallback. - signal.py: reply-to-bot and /slash bypass require_mention; owner detection resolves group UUID->phone and sets source.is_owner at intake. - run.py/session.py: surface owner status WITHOUT changing upstream's [name] sender prefix. A **Owner:** context line covers single-user sessions; for cache-shared group sessions (where the context prompt is sender-agnostic) an additive [SYSTEM: sender NAME is the owner] marker is prepended ONLY for the owner, so guest lines stay byte-identical to upstream. Supersedes NousResearch#44706. Refs NousResearch#7269.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating a real Signal authorization gap. Current main still omits Platform.SIGNAL from the early chat allowlist in gateway/authz_mixin.py:330-343, while the adapter already admits SIGNAL_GROUP_ALLOWED_USERS groups and constructs group:<id> chat IDs in gateway/platforms/signal.py:593-607. The production normalization is therefore aligned with the current adapter contract.
Problems
tests/gateway/test_signal_group_auth.py:35tests a local mirror of the proposed branch, notGatewayRunner._is_user_authorized. It would remain green if the production Signal mapping were removed or the real authorization ordering changed.
Suggested changes
- Exercise the real method with a
SessionSourceand environment values, following the existing bare-runner pattern intests/gateway/test_unauthorized_dm_behavior.py:58-74. Assert prefixed-ID authorization, wildcard behavior, an unlisted-group denial, and that DMs do not receive the group bypass.
Automated hermes-sweeper review.
| def _is_group_member_authorized( | ||
| chat_type: str, chat_id: str, allowed_groups_raw: str | ||
| ) -> bool: | ||
| """Mirror the Signal-relevant branch of ``_is_user_authorized``. |
There was a problem hiding this comment.
Please test GatewayRunner._is_user_authorized directly rather than a copy of the proposed branch. This helper will still pass if the production mapping or authorization ordering later regresses; the established bare-runner fixture pattern in tests/gateway/test_unauthorized_dm_behavior.py can exercise the real method.
What does this PR do?
gateway.authz_mixin._is_user_authorizedhas a group-chat-allowlist bypass that authorizes any sender in a listed chat regardless of per-user allowlists. It currently only enumerates Telegram and QQBOT:Signal isn't in the dict, so every Signal group message falls through to the per-user
SIGNAL_ALLOWED_USERScheck. Operators who setSIGNAL_GROUP_ALLOWED_USERS(whichplatforms/signal.pydoes honor for its own group filter at line ~515) reasonably expect Signal groups to work like Telegram — but every group member not also enumerated inSIGNAL_ALLOWED_USERSis silently rejected with:The fix has two parts:
Add
Platform.SIGNAL → "SIGNAL_GROUP_ALLOWED_USERS"tochat_allowlist_env. Reuses the existing env var that signal.py already consumes for its own group filter — no new config surface.Strip the
group:prefix fromsource.chat_idbefore the equality check.platforms/signal.pybuilds Signal chat_ids asf"group:{group_id}"(line ~520), while the env value is stored unprefixed. signal.py's own filter compares unprefixed; auth should too. Without this normalization a naive bypass would still fail.Related Issue
None — opened directly. Happy to file an issue first if maintainers prefer.
Type of Change
Changes Made
gateway/authz_mixin.py— one line added to the dict, onegroup:prefix-stripping block added before the comparison. 9 insertions, 1 deletion.tests/gateway/test_signal_group_auth.py— new file, 10 regression cases following the existingtests/gateway/test_discord_allowed_channels.pypattern (private helper mirrors the patched branch, stdlib + unittest only, no Hermes imports).How to Test
Unit test:
End-to-end on a running gateway:
SIGNAL_GROUP_ALLOWED_USERS=<your-group-id>(withoutgroup:prefix — matches signal.py's existing convention).SIGNAL_ALLOWED_USERS=<your-uuid>only (omit other group members on purpose).@mentionthe bot. Before the patch the gateway logsWARNING gateway.run: Unauthorized user: <uuid>and silently drops the message. After the patch the message reaches the agent.Checklist
Code
fix(gateway):)scripts/run_tests.shacross 18 auth/allowlist/signal-related files intests/gateway/; 376/376 passDocumentation & Housekeeping
SIGNAL_GROUP_ALLOWED_USERSandSIGNAL_ALLOWED_USERSare already documented; the fix makes existing docs accurate🤖 Generated with Claude Code