fix(discord): honor pairing grants for message auth

This commit is contained in:
BROCCOLO1D 2026-07-03 12:14:00 +10:00 committed by Teknium
parent 551f00109d
commit c3808cfc14
2 changed files with 53 additions and 0 deletions

View file

@ -3227,6 +3227,18 @@ class DiscordAdapter(BasePlatformAdapter):
return True
return bool(channel_ids & allowed)
def _is_pairing_approved_user(self, user_id: str) -> bool:
"""True when the Discord user has an explicit Hermes pairing grant."""
user_id = str(user_id or "").strip()
if not user_id:
return False
try:
from gateway.pairing import PairingStore
return bool(PairingStore().is_approved("discord", user_id))
except Exception:
return False
def _is_allowed_user(
self,
user_id: str,
@ -3267,6 +3279,14 @@ class DiscordAdapter(BasePlatformAdapter):
allowed_roles = getattr(self, "_allowed_role_ids", set())
has_users = bool(allowed_users)
has_roles = bool(allowed_roles)
# Pairing is a first-class auth grant in the gateway auth union and in
# Discord component buttons. Honor it here too so normal guild/DM text
# messages do not get dropped at the adapter before the pairing-aware
# gateway layer can see them.
if self._is_pairing_approved_user(user_id):
return True
if not has_users and not has_roles:
if os.getenv("DISCORD_ALLOW_ALL_USERS", "").strip().lower() in {"true", "1", "yes"}:
return True

View file

@ -178,6 +178,18 @@ def _make_interaction(
)
def _stub_pairing_store(monkeypatch, approved_ids):
approved = {str(uid) for uid in approved_ids}
class _FakePairingStore:
def is_approved(self, platform, user_id):
return platform == "discord" and str(user_id) in approved
import gateway.pairing as pairing
monkeypatch.setattr(pairing, "PairingStore", _FakePairingStore)
# ---------------------------------------------------------------------------
# Backwards-compat: empty allowlist → everything passes (matches on_message)
# ---------------------------------------------------------------------------
@ -235,6 +247,27 @@ async def test_disallowed_user_rejected_with_ephemeral(adapter, caplog):
assert any("DISCORD_ALLOWED_USERS" in r.message for r in caplog.records)
def test_pairing_approved_user_passes_message_gate_without_allowlist(adapter, monkeypatch):
"""Pairing grants must be honored before on_message drops guild mentions."""
_stub_pairing_store(monkeypatch, {"100200300"})
assert adapter._is_allowed_user(
"100200300",
author=SimpleNamespace(id=100200300),
guild=SimpleNamespace(id=42, get_member=lambda _uid: None),
is_dm=False,
channel_ids={"12345"},
) is True
@pytest.mark.asyncio
async def test_pairing_approved_user_passes_slash_gate_without_allowlist(adapter, monkeypatch):
"""Slash and normal text auth share the pairing-aware user gate."""
_stub_pairing_store(monkeypatch, {"100200300"})
interaction = _make_interaction("100200300")
assert await adapter._check_slash_authorization(interaction, "/help") is True
interaction.response.send_message.assert_not_awaited()
# ---------------------------------------------------------------------------
# Role allowlist (DISCORD_ALLOWED_ROLES) parity
# ---------------------------------------------------------------------------