docs(pairing): address reviewer comments — comments, error msg, __all__ test

- Clarify SystemExit message for missing/null allowFrom (manager.py)
- Document why Feishu passes content="" for unauthorized DMs
- Document exact-match semantics in BaseChannel.is_allowed()
- Document negligible collision probability in generate_code()
- Add test_all_exports_are_importable for nanobot.pairing.__all__
This commit is contained in:
chengyongru 2026-05-15 10:31:29 +08:00 committed by Xubin Ren
parent ac9a2d0c25
commit 199a1bb8fa
5 changed files with 15 additions and 1 deletions

View File

@ -202,6 +202,7 @@ class BaseChannel(ABC):
allow_list = getattr(self.config, "allow_from", []) or []
if "*" in allow_list:
return True
# allowFrom entries are opaque tokens — must match exactly.
if str(sender_id) in allow_list:
return True
if is_approved(self.name, str(sender_id)):

View File

@ -1716,6 +1716,8 @@ class FeishuChannel(BaseChannel):
# Group chats are silently ignored; DMs get a pairing code.
if not self.is_allowed(sender_id):
if chat_type == "p2p":
# content="" because the pairing reply is generated by
# BaseChannel._handle_message, not from the original message.
await self._handle_message(
sender_id=sender_id,
chat_id=sender_id,

View File

@ -145,7 +145,7 @@ class ChannelManager:
allow = getattr(cfg, "allow_from", None)
if allow is None:
raise SystemExit(
f'Error: "{name}" is missing allowFrom. '
f'Error: "{name}" is missing or null allowFrom. '
f'Set ["*"] to allow everyone, or add specific user IDs.'
)

View File

@ -82,6 +82,8 @@ def generate_code(
with _LOCK:
data = _load()
_gc_pending(data)
# Collision probability is negligible (~1e-12 with 20 pending codes),
# so we skip an existence check for simplicity.
raw = "".join(secrets.choice(_ALPHABET) for _ in range(_CODE_LENGTH))
code = f"{raw[:4]}-{raw[4:]}"

View File

@ -2,9 +2,18 @@ import time
import pytest
from nanobot.pairing import __all__ as pairing_all
from nanobot.pairing import store
def test_all_exports_are_importable():
"""Every name in __all__ must actually be importable from nanobot.pairing."""
import nanobot.pairing as pkg
for name in pairing_all:
assert hasattr(pkg, name), f"{name} is in __all__ but not exported"
@pytest.fixture(autouse=True)
def _tmp_store(tmp_path, monkeypatch):
path = tmp_path / "pairing.json"