Repository navigation
fix(start-goal): reject desktop host in SSH sessions - #6312
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · xhigh
动机
在 SSH 工作区使用 Codex App 启动 Goal 的操作者。 原流程允许把远端 SSH 工作区选为桌面 App 宿主,生成无法在该宿主执行的 heartbeat 激活步骤,后续工作因此停在错误入口。 已观察到的 Codex SSH 运行时误选桌面 App 时,当前 head 提前拒绝;改用原 SSH profile 后生成 visible Goal 任务包,本地 App 和 CLI 路由保持。 本 PR 不增加远端宿主权限,不负责实际创建自动化,也不把命令预览当成 Goal 已启动。
改动思路
宿主检测应保留运行时环境证据与显式路由参数的区别;在既有 Python CLI 环境 IO 预检中提前拒绝即可,不需要额外身份权威、自动改宿主或 TypeScript 重写。 本 PR 交付已观察到的 Codex SSH 运行时误选桌面宿主的提前拒绝、原 SSH visible Goal 纠正包及本地 App/CLI 行为保留;预览不等于实际激活。
独立依据:docs/reference/protocols/loopx-goal-command-v0.md,冻结修订 323c3053128e41e16df27e6b6498f83c37e81f5e 的 Goal-Start Flow。SSH App 应走 visible Goal,桌面 App 才走 heartbeat。同修订 docs/reference/protocols/codex-app-host-command-registry-v0.md 明确只读预览与当前宿主选择边界。另核对既有 _host_thread.py::ambient_host_thread_id:宿主提供的环境上下文是本地运行时观察,显式 --thread-id 是路由输入,不能单靠它认定当前进程属于 Codex;这也不是身份认证。
具体改动
精确 head 2d964f488a026697c9bfe96985b5f0eabbda359f;全 PR 2 文件 +135/-1(生产 +57/-1,测试 +78),全差异和上下游调用均已读取。
start_goal.py::_host_surface_environment_mismatch_payload(124)在codex-app+ 环境线程标识 + SSH_CONNECTION/SSH_CLIENT 时返回host_surface_environment_mismatch、非零退出、所需 SSH profile 及纠正建议。只列环境变量名,不回显值;安全字段说明不写 registry、不激活宿主。handle_start_goal_command(335)在 packet 构建前执行预检;_render_start_goal_markdown(105)增加 error_code 展示。已有 typed host profile/activation owner 和显式/环境线程解析没有改变。test_start_goal_compact_projection.py隔离测试宿主 SSH 环境,增加 wrong-host 拒绝与 corrected-host bootstrap 对照。纠正后的包使用--thin --runtime-profile codex_app_ssh_goal,不请求桌面 automation。- 非阻断建议:
suggested_command目前包含字面...。recommended_action已明确要求原命令仅更换 host flag,可正常纠正;后续可由原 CLI 参数 owner 提供保留 project/Goal/Agent/thread/goal-text 的完整 rerun 命令,减少手工重填。该建议不构成额外审批或权限门槛。
对主干的风险
独立冻结 base/head 对同一 8 例实际 CLI 比较:ambient SSH + App(有/无显式 thread 参数)与 SSH_CLIENT-only 在 base 都生成桌面 activation,head 均 exit2 mismatch;保留环境宿主证据时显式参数不能绕过。纠正为 SSH profile 后两者均 set_visible_goal,本地 App 与 CLI 路由不变;普通 SSH shell 缺少环境 Codex 证据时,即使提供显式 thread route 也保留原行为。
审查中曾把“删去环境宿主证据、仅保留显式 ID”的输出当成绕过;核对既有本地运行时来源契约后撤回这一判断。没有把 caller route 提升为宿主证明或把缺证据视为权限。每例都比较可丢弃项目文件字节无变化,不创建实际 heartbeat、不改活动 Goal。纠正路径从拒绝继续到真实 native SSH command pack;不以错误回执声称后续工作已执行。
当前 96 项 start-goal projection/output-budget 验证、native premerge 5 direct +5 selected、Ruff 和 control-plane typecheck 通过。额外 strict mypy 单文件命令会沿 imports 报全树4722错误;冻结 base 与当前 head 的完整错误身份/细节逐项一致,只归一化行号,且本 PR 未修改其因果源。该既有诊断单列,核心 changed invariant 有独立通过证据;不以错误总数相等自证。未查询或等待 CI。
新 gate schema 是局部 CLI 诊断,host literal 重用既有 vocabulary;环境 IO 留在既有 Python CLI,TS 配额/生命周期 owner 不变。没有 default-off 功能声明、新 managed skill、substring denylist 或更广 actor/权限模型。早期拒绝是机器执行义务;纠正建议不执行激活。实际远端 Codex App、真实宿主工具和后续工作未运行,CLI/profile 预览资格不冒称 installed-host 资格。
我的整体评价
APPROVE,无阻断发现。宿主检测应保留运行时环境证据与显式路由参数的区别;在既有 Python CLI 环境 IO 预检中提前拒绝即可,不需要额外身份权威、自动改宿主或 TypeScript 重写。 本 PR 交付已观察到的 Codex SSH 运行时误选桌面宿主的提前拒绝、原 SSH visible Goal 纠正包及本地 App/CLI 行为保留;预览不等于实际激活。 原问题在受支持的运行时观察范围内得到实际 base/head 修复,纠正、本地与未覆盖调用方保持。相邻精简检查了现有 thread helper 与 host profile:显式路由和 ambient runtime fence 语义不同,不能为了“复用”合并为第二种宿主证明;无需新抽象。完整 rerun 的 P2 建议可跟随原 CLI owner 改进。批准只绑定该 head,不授予合并、账户切换或宿主激活。
English verdict: APPROVE - 2d964f4; observed Codex SSH runtime rejects desktop App routing and the corrected native SSH Goal route works. Independent eight-case base/head CLI coverage, 96 focused tests and native premerge pass; explicit-only caller routing is not ambient host evidence. Baseline-identical mypy diagnostics remain separate.
Summary
Root cause
start-goal trusted an explicit host surface even when CODEX_THREAD_ID and SSH transport signals made that selection contradictory. The downstream host profiles were correct, but the CLI admitted the wrong profile and generated a desktop automation activation packet for a remote SSH session.
Scope
This stays in the existing Python start-goal CLI boundary because it validates local process environment before control-plane packet construction. No frontend change is needed: the affected entry point is the CLI host-selection path, and the typed JSON/Markdown failure is the user feedback surface. No adjacent refactor was needed.
Validation