Files
hermes-agent/tests/gateway/test_allowlist_qualified_ids.py
kshitijk4poor 8dfae717c1 test(gateway): trim allowlist test runner stub and isolate BlueBubbles env
The authz path reads only pairing_store, so the runner stub drops the
message-pipeline attributes. conftest already blanks the EMAIL_/GATEWAY_
allowlist vars but not BLUEBUBBLES_*; an operator shell with
BLUEBUBBLES_ALLOW_ALL_USERS set failed the test, so clear those two here.
Fixes the stale comment claiming BlueBubbles has no platform allowlist env.
2026-09-23 16:20:19 +05:30

64 lines
2.4 KiB
Python

"""Allowlist matching compares qualified user_ids, not bare '@' localparts.
The generic ``user_id.split("@")[0]`` alias in ``_principal_matches_allowlist``
was added for WhatsApp JIDs (``<phone>@s.whatsapp.net``) before WhatsApp got a
dedicated alias expansion. Left unconditional, it makes a bare allowlist entry
``alice`` admit ``alice@<any domain>`` on every platform whose user_id is
'@'-shaped (email, Google Chat, iMessage handles) — domains the sender controls.
"""
import pytest
from gateway.authz_mixin import _principal_matches_allowlist
from gateway.config import Platform
from gateway.session import SessionSource
def _source(platform: Platform, user_id: str) -> SessionSource:
return SessionSource(
platform=platform,
user_id=user_id,
chat_id=user_id,
user_name="tester",
chat_type="dm",
)
def _make_runner():
from gateway.run import GatewayRunner
runner = object.__new__(GatewayRunner)
runner.pairing_store = None
return runner
# The BlueBubbles adapter does no sender gate of its own, so with its platform
# allowlist unset GATEWAY_ALLOWED_USERS is the only enforcement on that path.
@pytest.mark.parametrize(
("platform", "env_var"),
[(Platform.EMAIL, "EMAIL_ALLOWED_USERS"), (Platform.BLUEBUBBLES, "GATEWAY_ALLOWED_USERS")],
)
def test_bare_localpart_entry_admits_no_foreign_domain(monkeypatch, platform, env_var):
# conftest's hermetic env blanks the EMAIL_/GATEWAY_ vars but not BlueBubbles' own.
for key in ("BLUEBUBBLES_ALLOWED_USERS", "BLUEBUBBLES_ALLOW_ALL_USERS"):
monkeypatch.delenv(key, raising=False)
monkeypatch.setenv(env_var, "alice,bob@corp.example")
runner = _make_runner()
assert runner._is_user_authorized(_source(platform, "alice@evil.example")) is False
assert runner._is_user_authorized(_source(platform, "bob@evil.example")) is False
# Positive control: a qualified entry still admits its exact sender.
assert runner._is_user_authorized(_source(platform, "bob@corp.example")) is True
@pytest.mark.parametrize(
("platform", "user_id"),
[
(Platform.WHATSAPP, "15550000001@s.whatsapp.net"),
(Platform.WHATSAPP, "15550000001:47@s.whatsapp.net"),
(Platform.WHATSAPP_CLOUD, "15550000001@s.whatsapp.net"),
],
)
def test_whatsapp_bare_phone_entry_still_matches_jid(platform, user_id):
assert _principal_matches_allowlist(_source(platform, user_id), user_id, {"15550000001"}) is True