fix(discord): isolate multiplex access policy per profile - #76166
fix(discord): isolate multiplex access policy per profile#76166OneNoted wants to merge 1 commit into
Conversation
Related: #75970 and #72427 address the same Discord multiplex policy family using narrower scoped-read/per-adapter-extra approaches. This PR carries adapter policy and transport provenance through restored sessions and interaction paths, so it is a competing mechanism rather than a duplicate. Maintainer decision needed. |
|
too large to review safely This PR changes 1487 production lines before tests and docs. Please split it or add a focused justification if it should stay together. Signed: GPT-5.6-terra-low in Codex |
|
Thanks for tracing the policy across ingress, restored-session, interaction, and voice paths. The underlying defect is confirmed on current The PR's diff addresses those concrete current-main paths with an adapter-local policy and carries the policy through the second gateway gate and persisted source metadata. I did not identify a specific blocking correctness defect from the read-only diff review. This is an automated hermes-sweeper review. |
SummaryThree PRs address #72348: #72427 starts replacing process-global Discord gate reads with per-adapter accessors, #75970 broadens that approach across Discord and Telegram, and #76166 introduces a fuller Discord policy object carried through ingress, gateway authorization, interactions, voice, and restored sessions. The diffs overlap on adapter-local gate isolation but differ materially in how they handle the downstream gateway gate and transport provenance. Related pull requests
Duplicates#72427 and #75970 substantially overlap on moving Discord authorization gates from process-global environment reads to per-adapter state; #75970 superseded #72427. #76166 overlaps with both on gate isolation but is not a pure duplicate because it additionally carries transport provenance and authorization context through the gateway, persistence, interactions, and voice paths. Suggested consolidationauthor action: rebase #76166 onto main, or split out the part that can merge. Preserve the adapter-owned downstream gateway authorization and persisted transport/channel provenance that address the reviewed gap left after #75970, while dropping code already implemented by merged #75970; this is consistent with the automated keep_open review's medium salvageability, while explicitly addressing the contributor's blocking review-size concern. Keep #72427 closed as superseded by #75970; #75970 is already merged and should remain the reference for the narrower adapter-local and Telegram work. Complex graphflowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I72348(["issue #72348 (closed)"])
P76166["PR #76166 (open)"]
P76166 -->|best fix| I72348
class I72348 closed
class P76166 open
class P76166 best
class P76166 target
click I72348 "https://github.com/NousResearch/hermes-agent/issues/72348"
click P76166 "https://github.com/NousResearch/hermes-agent/pull/76166"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 3 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 229 kB of PR diffs, 20 kB of issue/PR text, 34 kB of discussion (17 comments), 7 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
Related: #75970 merged the core per-profile Discord admission gate. This conflicting PR retains broader restored-session and voice-policy propagation, so it needs a scoped rebase and maintainer decision rather than being treated as a duplicate. |
What does this PR do?
Under multiplexing, Discord authorization settings are bridged through process-global state. Depending on the setting and initialization path, one profile's values can therefore be observed by another profile's adapter, causing unauthorized acceptance or silent rejection.
This change captures a
DiscordAccessPolicyfor each adapter while that adapter's profile scope is active, then carries the receiving profile and its policy through admission, routing, persistence/restoration, voice, interactive views, and the gateway's second authorization gate. Multiplex config handoff usesPlatformConfig.extrainstead of mutating process-global admission state. Explicit empty and false values remain authoritative, and each setting retains its existing environment/YAML precedence within the owning profile.Transport provenance is persisted separately from the runtime routed profile so restored sessions continue to authorize through the bot/profile that received them. Explicit allowed/ignored channel boundaries remain hard constraints, including parent/thread and normalized channel context. Pairing remains profile-owned and fails closed when an explicitly stamped profile has no corresponding store.
Single-profile behavior remains compatible, including live environment/config reads and existing direct helper/view construction.
Why this scope is necessary
The receiving profile's authorization decision crosses several asynchronous boundaries after ingress. Each changed path preserves that same owner rather than introducing a separate behavior:
Leaving any one of these paths process-global would reopen the same cross-profile authorization boundary after the initial message was admitted.
Related Issue
Fixes #72348
This follows the already-public, security-labeled issue above; it does not disclose a new private vulnerability report.
Type of Change
Changes Made
plugins/platforms/discord/adapter.py).gateway/session.py,gateway/platforms/base.py).defaultsources to their actual owning adapter and pairing store (gateway/authz_mixin.py,gateway/run.py).tests/gateway/test_discord_multiplex_access_policy.py).How to Test
scripts/run_tests.sh tests/gateway/test_discord_multiplex_access_policy.py -qfiles=$(python3 - <<'PY'from pathlib import Pathpatterns = ['test_discord*.py', 'test_*multiplex*.py', 'test_*pairing*.py', 'test_authorization.py', 'test_authz*.py', 'test_voice_command.py', 'test_session*.py']root = Path('tests/gateway')print(' '.join(str(p) for p in sorted({p for pattern in patterns for p in root.glob(pattern)})))PY); scripts/run_tests.sh $files -qscripts/run_tests.sh tests/gateway -qObserved locally on Arch Linux / Python 3.11 after a clean merge with upstream
mainat470cf66b0:mainat470cf66b0(4 passed, 2 failed in that module).git diff --checkpass for all changed files.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — N/A; no user-facing keys or setup steps were addedcli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/AScreenshots / Logs
N/A — authorization behavior is covered by regression tests.