Skip to content

fix(gateway): keep multiplexed /approvals authorization and persistent mode writes on the routed profile - #72476

Closed
Drexuxux wants to merge 1 commit into
NousResearch:mainfrom
Drexuxux:codex/fix-multiplex-approvals-profile-scope
Closed

Drexuxux wants to merge 1 commit into
NousResearch:mainfrom
Drexuxux:codex/fix-multiplex-approvals-profile-scope

Conversation

@Drexuxux

@Drexuxux Drexuxux commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

What?

In multiplex gateways, /approvals used the default profile’s admin policy and configuration even when the message was routed to another profile. The command could report success while changing the wrong profile’s persistent approval mode.

Fix

Scope both slash-command authorization and /approvals reads/writes to the routed profile. Single-profile behavior remains unchanged.

Follow-up to #63517. No duplicate PR or issue found.

Tests

  • Main: default changed from manual to off; routed profile incorrectly remained smart.
  • Fixed: default remains manual; routed profile changes to off.
  • 5 focused tests passed.
  • 96 related gateway/multiplex tests passed.
  • Ruff, compileall, and git diff --check passed.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery area/config Config system, migrations, profiles area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 27, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the focused multiplex-profile fix. The premise is confirmed on current main: the central slash gate reads policy from self.config at gateway/run.py:17561, and /approvals repeats that default-config policy read and performs its persistent write unscoped at gateway/slash_commands.py:3617-3620. Those command paths execute before the normal routed-profile wrappers at gateway/run.py:15416-15424 and gateway/run.py:22991-23004.

The proposed approach reuses _profile_runtime_scope, which already scopes profile-aware configuration and credentials (gateway/run.py:1777-1809), and the added tests cover both the routed-profile persistence and routed admin policy cases.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/profiles Multi-profile isolation, HERMES_HOME scoping labels Jul 30, 2026
@teknium1

teknium1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Thanks @Drexuxux — reviewed against current origin/main (dbb6acd) in the multiplexed-gateway backlog sweep. Closing; the two halves of this PR meet different fates on main.

Persistent-write half — redundant. /approvals persists through set_config_value("approvals.mode", ...)get_config_path()get_hermes_home(), and since 9ab748a (#95088, merged 2026-08-26) the entire primary-adapter _handle_message — slash dispatch included — runs inside _profile_runtime_scope(profile_home) for the routed profile (gateway/run.py:17335-17379). The write therefore lands in profiles/<name>/config.yaml, which is exactly what your test asserted (default stays manual, routed flips to off). Credit for spotting the unscoped write path early — you filed this a month before the general fix.

Policy half — wrong premise (design, not quality). 2afed50 (same PR #95088) made it explicit that slash-command / intake authorization belongs to the transport owner, not the routed runtime: _is_user_authorized_for_source re-enters the transport profile's scope for the auth read and then restores the routed scope (gateway/run.py:17429-17460, docstring explains why — the routed profile normally doesn't hold the shared bot's token or allowlist). Reading /approvals admin policy from the routed profile's config would invert that and let a routed profile's allow_admin_from grant admin on a bot it doesn't own. So that part isn't a bug to fix; it's the intended boundary.

If /approvals still writes to the wrong profile on main, a fresh report needs the platform, route config, and both config.yaml files before/after.

@teknium1 teknium1 closed this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles area/profiles Multi-profile isolation, HERMES_HOME scoping comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants