81c0691e17
Under gateway.multiplex_profiles, Discord and Telegram authorization gates (allowed/ignored channels, allowed users/roles, allow-all flags) were read from process-global os.environ, populated first-writer-wins by the YAML->env bridge in each adapter's _apply_yaml_config. The first profile to initialize pinned its allow/deny lists — and its ALLOW_ALL flags — for every other profile in the process (issue #72348, incl. the Telegram mirror reported in the thread). Fix (per-adapter-instance gate reads, whole class): - gateway/authz_mixin.py: new _platform_gate_env — scope-authoritative gate read: under an installed profile secret scope with multiplex active, a missing key returns the default instead of falling through to os.environ (which may hold another profile's value). Single-profile behavior is byte-identical to os.getenv. - Discord adapter: - connect() snapshots all gate env vars (_GATE_ENV_KEYS) inside the owning profile's runtime scope into a per-adapter dict; new accessors (_get_allowed_channels/_get_ignored_channels/_get_allowed_users/ _get_allowed_roles/_get_no_thread_channels/_discord_allow_all_users/ _gateway_allow_all_users/_get_allow_bots) resolve snapshot -> config.extra -> scope-aware env, replacing every raw os.getenv gate read: on_message channel gates, _is_allowed_user allow-all flags, slash authorization, fail-closed diagnostics, missed-message backfill, bot-message gating, and _component_check_auth (component buttons). - _apply_yaml_config always seeds gate values into PlatformConfig.extra (incl. new allowed_roles / allow_all_users keys) and SKIPS the process-global env writes when loading a profile-scoped config under multiplex; the legacy first-writer env bridge is preserved verbatim for single-profile deployments. - _resolve_allowed_usernames no longer unconditionally rewrites os.environ[DISCORD_ALLOWED_USERS] — under multiplex the resolved IDs stay adapter-local (snapshot refresh); single-profile keeps the env rewrite. - Telegram adapter (mirror of the same class): intake prefilter and callback-auth fallbacks, _telegram_auth_env_configured, and the allowed/ignored chats-topics-threads getters now read via the scoped gate reader; _apply_yaml_config skips authorization env writes for profile-scoped loads and seeds free_response_chats/ignored_threads extras. Regression tests (tests/plugins/platforms/test_discord_gate_isolation.py): two adapter instances with different allow-lists enforce their OWN lists order-independently across message, slash, and component gates; negative allow-all case proves profile A's open-access flag cannot authorize profile B; username-resolution env-clobber; YAML-bridge seeding/skip matrix; and the Telegram scoped-reader matrix. Sabotage-verified: reverting either the Discord snapshot accessors or the Telegram scoped reader fails 12/2 tests respectively. Credit: builds on the per-adapter accessor direction of PR #72427 (@JonthanaHanh) and the scope-aware-reader approach validated live on v0.19.0 by @yournetworkplug-ctrl for the Telegram mirror; scope corrections from jackjin1997's and cal88's analysis in the issue thread (allow-all flags, unguarded username-resolution env write, per-site channel reads). Fixes #72348