Conversation
… gateway Fix NousResearch#68559 **根因分析** 多路复用网关启动时,将默认 profile 的 terminal.* 配置桥接到进程全局 TERMINAL_* 环境变量。_profile_runtime_scope() 在路由到二级 profile 时 只切换了 hermes_home 和 secret scope,但没有切换 terminal 配置。 tools.terminal_tool._get_env_config() 从 os.environ 读取,导致被路由的 profile 继承了网关启动 profile 的 terminal backend 设置。 当默认 profile 使用 local backend、被路由的 profile 配置为 docker 时, 这构成了安全边界失效:本应被 Docker 沙箱隔离的 profile 实际获得了主机 终端访问权限。 **修复方式** 1. 在 tools/terminal_tool.py 中引入 ContextVar 类型的终端配置作用域 (_terminal_config_scope),并提供 set_terminal_config_scope() 和 reset_terminal_config_scope() 辅助函数。 2. 重构 _get_env_config():当作用域激活时,从作用域 dict 读取终端配置; 否则回退到旧版环境变量路径,保持向后兼容。 3. 在 gateway/run.py 的 _profile_runtime_scope() 中,进入路由 profile 作用域时也安装该 profile 的 terminal 配置(从 profile 自身的 config.yaml 读取),退出时清理。 4. 新增 _resolve_profile_terminal_config() 辅助函数,从目标 profile 的 config.yaml 中读取 terminal 段,不修改 os.environ。 5. 添加回归测试验证作用域隔离、嵌套作用域、以及无 terminal 段的 profile 不会崩溃。
This was referenced Aug 3, 2026
This was referenced Aug 30, 2026
muhifni
added a commit
to muhifni/hermes-agent
that referenced
this pull request
Sep 2, 2026
A multiplexed Hermes process (gateway.multiplex_profiles, unified dashboard/TUI, or cron) can serve several profiles at once. Terminal settings used to resolve through process-global TERMINAL_* env vars plus the one-shot _ensure_terminal_env_bridged() guard. The first profile to touch a terminal tool after startup therefore pinned its backend and other policy (mounts, SSH target, network, cwd, resources) onto every later profile until restart. This is a correctness and sandbox-boundary bug: a local profile can run inside another profile's docker sandbox, and a docker/ssh profile can be dropped onto the launch host. Repro lineages: canonical NousResearch#68559, gateway backend latch NousResearch#94200, dashboard/container symptoms NousResearch#98581/NousResearch#96992. Fix with an authoritative profile terminal policy seam, analogous to agent/secret_scope.py: - tools/terminal_scope.py adds a ContextVar that holds the active profile's complete effective terminal policy. Projection order is defined defaults + supplemental tool defaults <- profile .env TERMINAL_* values <- explicit terminal: config.yaml keys. Once a scope is bound, missing values never fall through to ambient os.environ. - install_profile_terminal_scope() fail-closes: unreadable/malformed policy installs a refusal scope; terminal_tool / execute_code refuse execution instead of inheriting launch-process policy. - tools/terminal_tool.py routes TERMINAL_* reads through the scope-aware _tenv() helper and suppresses the process-env bridge while scoped. - gateway/run.py, tui_gateway/server.py and cron/scheduler.py install the same profile terminal scope at their in-process profile boundaries. - Other scoped readers from the first patch (prompt/cwd/media/footer) remain routed through the same seam. Tests now cover the review-requested matrix: polluted launch profile A with sensitive mounts/SSH/CWD/network/resource policy; profile B with backend-only, empty terminal config, or .env-only selections cannot observe A's values. They also cover malformed/unreadable policy refusal, terminal_tool refusal, gateway cleanup including error paths, dashboard/TUI session scope, and cron install/reset lifecycles. Prior art / lineage: x7peeps NousResearch#68611 (original ContextVar direction), 100yenadmin NousResearch#79117/NousResearch#78030, liuhao1024 NousResearch#94206/NousResearch#98589, and complementary Bergmann89 NousResearch#97014 (env_loader re-bridge containment). Fixes NousResearch#68559 Refs NousResearch#94200, NousResearch#98581, NousResearch#96992
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
修复 #68559: 多路复用网关忽略路由 profile 的 terminal backend 配置,Docker profile 继承了本地 backend
根因分析
多路复用网关启动时,将默认 profile 的
terminal.*配置桥接到进程全局TERMINAL_*环境变量。_profile_runtime_scope()在路由到二级 profile 时只切换了hermes_home和secret_scope,但没有切换 terminal 配置。tools.terminal_tool._get_env_config()从os.environ读取,导致被路由的 profile 继承了网关启动 profile 的 terminal backend 设置。当默认 profile 使用
localbackend、被路由的 profile 配置为docker时,这构成了安全边界失效:本应被 Docker 沙箱隔离的 profile 实际获得了主机终端访问权限。修复方式
tools/terminal_tool.py: 引入 ContextVar 类型的终端配置作用域(
_terminal_config_scope),并提供set_terminal_config_scope()/reset_terminal_config_scope()辅助函数。重构_get_env_config():作用域激活时从作用域 dict 读取,否则回退到旧版环境变量路径。gateway/run.py: 在
_profile_runtime_scope()中,进入路由 profile 作用域时同时安装该 profile 的 terminal 配置(从 profile 自身的config.yaml读取),退出时清理。新增_resolve_profile_terminal_config()辅助函数。不变量保证:
os.environ(进程全局)copy_context()传播到 agent worker 线程测试
tests/gateway/test_68559_terminal_config_scope.py,5 个测试全部通过test_multiplex_credential_isolation.py)10 个测试全部通过验证
Closes #68559