mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-14 14:12:44 +00:00
Aligns runtime behaviour with SECURITY.md 2.6: externally reachable messaging adapters must fail closed unless access is explicitly configured. Closes the confirmed multiplex authorization bypass a secondary profile's open dm/group policy no longer inherits the default profile's allowlist trust. - Own-policy adapters (WhatsApp, WeCom, Weixin, QQBot, Yuanbao) default dm_policy/group_policy to pairing/allowlist instead of open; open now requires an explicit GATEWAY_ALLOW_ALL_USERS or per-platform allow-all. - Startup guard (_own_policy_open_startup_violation) refuses to boot when an enabled adapter is open without the allow-all opt-in; the guard now runs for every secondary profile in multiplex mode too. - Profile-aware own-policy authorization: _authorization_adapter / _adapter_for_source resolve the live adapter via SessionSource.profile, so _is_user_authorized and the ingress/pairing/busy/queue paths read the originating profile's adapter policy, not the default profile's. - Fail-closed intake for Email, Feishu P2P, and Discord (blank-principal denial, empty-allowlist deny, missing-interaction.user deny). Salvaged from #44073 (external-surface hardening), split into a focused gateway-authz PR per maintainer request. Follow-up fix by Hermes Agent: the Discord slash-auth channel bypass now matches DISCORD_ALLOWED_CHANNELS by the same name-inclusive keys (id + name + #name + parent) the on_message scope gate uses, so a name-form channel allowlist authorizes slash interactions consistently (was id-only, breaking #name matching). Co-authored-by: Hermes Agent <agent@nousresearch.com>
60 lines
No EOL
1.9 KiB
Python
60 lines
No EOL
1.9 KiB
Python
"""Regression tests for own-policy open startup gate in gateway/run.py."""
|
|
|
|
import pytest
|
|
|
|
from gateway.config import GatewayConfig, Platform, PlatformConfig
|
|
from gateway.run import GatewayRunner
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_unrelated_allow_all_does_not_bypass_yuanbao_open_gate(
|
|
monkeypatch, tmp_path,
|
|
):
|
|
"""TELEGRAM_ALLOW_ALL_USERS must not satisfy Yuanbao's open-policy opt-in."""
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
|
monkeypatch.delenv("GATEWAY_ALLOW_ALL_USERS", raising=False)
|
|
monkeypatch.delenv("YUANBAO_ALLOW_ALL_USERS", raising=False)
|
|
monkeypatch.setenv("TELEGRAM_ALLOW_ALL_USERS", "true")
|
|
|
|
config = GatewayConfig(
|
|
platforms={
|
|
Platform.YUANBAO: PlatformConfig(
|
|
enabled=True,
|
|
extra={"dm_policy": "open"},
|
|
),
|
|
},
|
|
sessions_dir=tmp_path / "sessions",
|
|
)
|
|
runner = GatewayRunner(config)
|
|
|
|
ok = await runner.start()
|
|
|
|
assert ok is True
|
|
assert runner.should_exit_cleanly is True
|
|
assert "yuanbao" in (runner.exit_reason or "").lower()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_gateway_allow_all_satisfies_yuanbao_open_gate(monkeypatch, tmp_path):
|
|
"""GATEWAY_ALLOW_ALL_USERS is the intended global open-policy opt-in."""
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
|
monkeypatch.setenv("GATEWAY_ALLOW_ALL_USERS", "true")
|
|
monkeypatch.delenv("YUANBAO_ALLOW_ALL_USERS", raising=False)
|
|
monkeypatch.delenv("TELEGRAM_ALLOW_ALL_USERS", raising=False)
|
|
|
|
config = GatewayConfig(
|
|
platforms={
|
|
Platform.YUANBAO: PlatformConfig(
|
|
enabled=True,
|
|
extra={"dm_policy": "open"},
|
|
),
|
|
},
|
|
sessions_dir=tmp_path / "sessions",
|
|
)
|
|
runner = GatewayRunner(config)
|
|
monkeypatch.setattr(runner, "_create_adapter", lambda platform, cfg: None)
|
|
|
|
ok = await runner.start()
|
|
|
|
assert ok is True
|
|
assert runner.should_exit_cleanly is False |