mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(discord): honor pairing grants for message auth
This commit is contained in:
parent
551f00109d
commit
c3808cfc14
2 changed files with 53 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue