Hermes 执行提权命令总是弹窗要密码(系统已免密)——根因与修复
日期:2026-11-01;平台:max2-nixos;会话:Desktop。用户诉求:Hermes 与系统保持一致,由系统决定是否需要密码,而不是系统免密了 Hermes 还一律弹窗。
R01 症状
Hermes Desktop 中执行任何含 sudo 的 CLI 命令,都会弹出 Desktop 密码卡(网关 sudo server→client 请求),要求输入密码;即使 NixOS 系统层已配置免密也每次必弹。
R02 用户系统侧确已免密(实测)
/run/wrappers/bin/sudo -n true 在登录 shell 下 exit=0;sudo -l 显示 (ALL : ALL) SETENV: NOPASSWD: ALL。排除 sudoers 配置问题。
R03 弹窗来源定位
非审批流(approvals.mode 已是 off)。弹窗是 Desktop 渲染的 sudo 取密码卡,对应网关 gateway/session_sudo_prompt.py 经 tools/terminal_tool_sudo.py::_transform_sudo_command 发出的 sudo 请求。触发条件:无 SUDO_PASSWORD、无会话缓存密码、且有 UI 回调时,先跑免密探针,探针失败才弹窗。
R04 免密探针机制
探针为各 backend 内执行 sudo -n true(tools/environments/base.py::_sudo_nopasswd_works,3 秒超时,失败闭合即失败视为需密码)。local/docker/ssh backend 均启用该探针。每次含 sudo 的命令都会重新探测,不缓存结果。
R05 根因:网关 PATH 里没有 NixOS 的 sudo
网关 systemd 单元 ~/.config/systemd/user/hermes-gateway.service 的 PATH 为 node 系目录 + /home/cat/.local/bin + /usr/local/sbin…/sbin:/bin,NixOS 下根本没有 /usr/bin/sudo(sudo 在 /run/wrappers/bin/sudo)。用网关同款最小 PATH 实测复现:sudo → command not found,exit=127 → 探针恒失败 → 每次必弹窗。连带问题:coreutils 的 true/id 在 /run/current-system/sw/bin,同样不在 PATH,即使 sudo 可解析探针仍失败。
R06 修复(两处,均可逆)
① /home/cat/.local/bin/sudo → /run/wrappers/bin/sudo 软链接(setuid 经软链接有效,已验证可执行;该目录本就在网关 PATH 内)。② 新建 systemd drop-in ~/.config/systemd/user/hermes-gateway.service.d/nixos-path.conf,在 [Service] 中重设完整 PATH,把 /home/cat/.local/bin:/run/wrappers/bin:/run/current-system/sw/bin 置于最前。采用 drop-in 而非改主单元文件:主单元由 Hermes 生成、升级可能重写,drop-in 目录保留。
R07 重启约束
PATH 变更需重启网关生效,但 agent 自身终端跑在网关进程树内,网关侧直接拦截 restart/stop(自杀保护),daemon-reload 可在网关内执行。最终由用户在 Konsole(网关之外)执行 systemctl --user restart hermes-gateway,Desktop 断开重连一次。
R08 验证结果(2026-11-01 重启后)
新网关进程实测 environ PATH 已含两处 NixOS 目录;同款最小环境 sudo -n true → exit=0;经 Hermes terminal 工具跑 sudo -n id -u → 0 且 sudo true 直接成功,全程无密码卡、无等待。行为即“由系统决定”:免密则过,系统侧收紧时命令干净报错。
R09 回滚方法
删除 /home/cat/.local/bin/sudo 软链接与上述 drop-in 文件,systemctl --user restart hermes-gateway 即可。
R10 上游改进建议(未做)
Hermes 上游 tools/environments/local.py::_SANE_PATH 仅含 FHS 路径,无 NixOS 路径;且探针用 sudo -n true 而非实际命令,按命令粒度的 NOPASSWD 规则会被误判。两处均为上游源码,改了升级会被覆盖,故本次只做本机侧修复。