Skip to content

[Grok/dsh 75] 组织身份连接远程工作区 #207

Description

@Blackman99

Parent

#132

Ticket: 75

Status: ready-for-agent

User Stories: 36, 60, 61(见父规格)

What to build

已配置组织身份的用户连接远程 dsh 工作区时,登录、组织限制和凭据撤销实际作用于远端访问。

Acceptance criteria

  • 组织认证与远程连接明确映射,客户端不能仅凭已登录 UI 状态获得远端权限。
  • 令牌过期、组织不匹配、撤销、重连和管理员锁定在实际请求中生效。
  • 凭据用途/传递边界可审计,不能被不同配置目的地复用;错误不泄露令牌。
  • 使用可部署身份/远端服务完成端到端验证;普通显式远程认证不等待该组织集成票。

Blocked by

Delivery contract

用户于2026-09-20批准当前测试与任务拆分。按父规格的已安装产物/真实终端和公开协议测试验收;实际实现须带适用的文档、Changeset及必要检查。ready-for-agent表示任务已定义,不表示前置任务已完成,也不授权自动开始本轮实施、购买付费资源或发布软件版本。

Activity

  1. Blackman99 commented on Sep 25, 2026

    @Blackman99
    OwnerAuthor

    已实现并快进推送到 rewrite/grok-dsh-20260920:bced29083d2a7f1212b83bb01e8fb7e88ed43e3b(快进范围 5b300a8..bced290)。

    Rebase 说明:分支起点是 9bd0449(#191)。开发期间 #206(5b300a8,deep-research workflow)先合入,rebase 一次,没有冲突,两边的新增都保留了。#173 这期间没有推送。下列检查都在最终基线上重跑。

    做法:可部署的身份服务替身,不伪造官方设施
    参考实现把已登录的组织 bearer 发给官方 Computer Hub。这里没有官方 Hub、SSO 或付费账号,所以映射为:组织自己部署的 OpenID Connect 服务(用真实的 Ory Hydra v26.2.0 验证,Apache-2.0,sqlite 版本,按发布页 checksums 校验)加上 #190 的 SSH 远端。组织的共享远端主机把组织密钥限制为强制命令(restrict,command="…/org-agent.sh"),这个密钥能到达的只有 codsh --rust agent --leader stdio。

    实现内容

    • 远端策略(新文件 rust/src/remote_identity.rs):requirements.toml(或 managed_config.toml)中的 [remote_access] identity = "required",加上 issuer、audience、introspection_url(RFC 7662;https 或回环 http;官方 x.ai/grok.com 端点拒绝;可选 introspection_client_id + 只有属主可读的 introspection_secret_file,Basic 认证)、teams、deny_subjects、recheck_secs(默认 30)、locked + lock_message、applies_to = "all"。优先级是 requirements > managed > user,用户的 config.toml 写 identity = "off" 无效。策略不完整或读不出来时,所有连接都拒绝(fail closed)。remote_access/remote_identity 已加入策略键白名单。
    • 远端网关(在 agent --leader stdio 代理里):认证之前只放行 initialize 和 authenticate(方法 codsh-org-identity,令牌放在 _meta."codsh/identity",由网关自己处理,不会转发给 leader)。其余请求都回 -32000 并带 data.reason。initialize 结果会注入 authMethods(issuer、audience、teams),并在认证前去掉 liveSessions。令牌要被 introspection 报告为 active,issuer 必须存在且一致,audience 一致,团队在允许列表中,而且不能是 refresh token。认证之后每个请求都重新向身份服务确认,连接期间还有定时复查。过期、在身份服务处撤销(包括 codsh --rust logout)、deny_subjects、locked、连接中途换主体、连续 3 次认证失败,都会发出 _codsh/remote_access_revoked、在 leader 上取消这个连接启动的轮次,然后断开。身份服务不可达或返回非 JSON 时拒绝;不跟随重定向。
    • 客户端(acp.rs、main.rs):只有 UI 登录状态不授予任何远程访问。codsh --rust login 的会话只发给 [[remote_identity]] target = "ssh://host[:port][/path]" 中列出、audience 与远端要求一致的目标(按完整路径段匹配)。issuer 也必须一致;如果 JWT 的 aud 指向别的受众,就不发送。每个请求前都重新读取 auth.json:会话刷新后重新认证,会话被清除或无法刷新时,请求在发出前就停下。空闲时令牌快过期会自动续期。收到撤销通知后显示原因,标记为断开,/reconnect 会重新认证。remote check(含 --json 的 identity 字段)和 /remote 会显示是否要求身份、结果、主体和团队,或拒绝原因。
    • 审计:两端都写只有属主可读的 JSONL(客户端 remote-identity.log,主机 remote-access.log,1 MiB 轮转),记录用途(audience/issuer)、目标及其配置来源、主体、团队、结果,以及令牌 SHA-256 的前 12 位十六进制指纹,从不记录令牌本身;错误信息也不含令牌。
    • 要求身份的主机会拒绝远程克隆(--codsh-remote-lifeline,退出码 2),因为普通 ssh 命令无法携带身份。没有策略的远端行为与 [Grok/dsh 58] 远程工作区连接与执行 #190 完全相同。
    • CODSH_SHELL_SLEEP 加入 dsh 子进程环境白名单(mock 模型的测试参数,之前实际没有传过去)。
    • 文档:README 中英文(映射、配置、限制)、CONTEXT.md、CONTRIBUTING.md(Hydra 下载、校验、CODSH_TEST_HYDRA)、packages/cli/README.md、remote --help、changeset。

    验收对照

    1. 组织认证明确映射到远程连接,只有 UI 登录不会授权:有测试覆盖“已登录但目标未配置,什么都不发送”和“不认证的客户端被拒”。
    2. 过期、组织/团队不匹配、撤销、重连和管理员锁定都作用在真实请求上:有 Hydra 签发的短期令牌、Hydra 撤销、logout 撤销、deny_subjects/locked,以及轮次进行中被撤销后远端命令被取消。
    3. 用途和发送边界可审计;令牌不能被另一个配置的目标复用(beta 令牌客户端不发给 alpha,强行发送时远端按 audience 拒绝;issuer 不匹配时客户端和远端都拒绝);错误里不含令牌。
    4. 端到端用可部署的身份服务(Hydra + 组织登录/授权应用)和远端服务(真实 OpenSSH + 真实 dsh)验证;普通的 [Grok/dsh 58] 远程工作区连接与执行 #190 显式远程认证不依赖本票。

    检查(干净环境、最终基线 bced290)

    • cargo fmt --check 通过;pnpm typecheck 通过。
    • clippy -D warnings:只有两处已存在的 filesystem_sandbox(tail_marker、needless_return)报错;加 -A dead_code -A clippy::needless_return 后无告警。
    • cargo test --workspace --no-fail-fast:bin 632 通过、4 失败(含新增 7 个 remote_identity 单元测试,其中一个用本机 introspection 端点验证 Basic 认证、secret 文件权限、refresh token 和缺少 issuer 的拒绝);其余 crate 498 + 42 + 61 + 2 + 379 + 61 全部通过,2 个 ignored。4 个失败都是已存在问题,涉及的文件本票都没改:filesystem_sandbox 2 个,以及 privacy::drafts_stay_local… 和 voice::substitute_route…(这两个测试捕获的 HTTP 请求体不完整,这次单独重跑也失败)。
    • pnpm test(带 CODSH_TEST_OPENSSH、CODSH_TEST_HYDRA):99 个文件,2533 通过、2 跳过、1 失败。失败的是 reference-evidence(负载下 5 秒超时),用 --testTimeout=60000 单独重跑 11/11 通过。新增的 scripts/rust-remote-identity.spec.mjs 6/6 通过(真实 Hydra + 真实 sshd + 真实 dsh);rust-remote.spec.mjs 和 rust-clone.spec.mjs 也通过。
    • PTY(Linux,pnpm run build:rust 之后):rust-remote-pty-test.py 通过。rust-auth-pty-test.py 只在 macOS 上运行,这里按设计退出,没有跑。本票没有新增 PTY 脚本。
    • 全部在本机回环上运行,没有使用付费服务或官方设施。

    未验证 / 限制

    • 没有官方 Computer Hub、SSO 或付费组织账号;只验证了 Hydra 这一个真实的 OIDC 实现。
    • 只在 Linux 上验证,macOS 和 Windows 未验证。
    • Hydra 的设备码端点路径与 codsh 的 /oauth2/device/code 不一致,所以测试用的是回环 PKCE 登录,没有覆盖设备码登录。
    • 检查位于 codsh 的 leader 代理中:能开 shell 的密钥可以绕过,必须用强制命令部署(README 已写明)。agent serve 套接字不受网关约束。
    • 撤销只取消本连接启动的轮次;之前某个已关闭连接留下、仍在运行的轮次,不会因为之后的撤销而停止(主机上 codsh --rust leader kill 可以停止)。
    • 团队来自令牌里的 claim;目录中的团队变更要等下一次签发的令牌才生效。
    • 需要 client 认证的 introspection 端点只用本机测试端点验证过,没有对真实 IdP 验证。
    • 没有修改 inventory。
    • 没有改 main、npm 发布和默认版本;没有编辑 PR test(reference): pin Grok provenance and compatibility inventory #213(它的 head 就是集成分支,会随推送自动更新)。

    #207 阻塞的只有 #211,它仍被其他 11 个未关闭的票阻塞(其中 #206 已合入但还没关闭),所以本票关闭后没有新解锁的后续票。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions