Files
dsh_shenxian/dsh-server-docs/04-调整方案/33-实例权限默认档位改为完全权限.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

5.6 KiB
Raw Blame History

33 · 实例权限默认档位改为「完全权限」(复用官方 DSH_PERMISSION_MODE)

  • 日期:2026-09-11
  • 触发:档案 32 的 P0(dsh workspace-write 沙箱在本机不可用 → 拒绝执行任何 shell)+用户决策「方案 A」+追问「假如用户就是想授权 agent 执行、不想反复点确认,最佳方案是什么」+「可以复用官方的权限设置逻辑」
  • 状态:✅ 已实施(commit 见 git),配置链路已核验;末段 UI 点击验收待人工

TL;DR|结论:实例权限默认档位改为**「完全权限」**(复用官方 DSH_PERMISSION_MODE),避免 agent 每步都弹确认。 关键:方案 A:复用官方权限设置链路,不改官方包;配置链路已核验。 状态:✅ 已实施(末段 UI 点击验收待人工)

一、方案选型

方案 做法 结论
裸改内置预设 直接用 danger-full-access 预设 ❌ 该预设把 approval 绑成 never({sandbox:'danger-full-access', approval:'never'}),会静默摘掉全部确认
自造自定义预设 profile cordis.patch.yml 给 permission-presets 行加 config.presets 新增一档 可行(已核实 patch 支持 config 覆盖),但要给每个用户铺 profile、且 config 是整体替换
✅ 采用:官方 env 开关 DSH_PERMISSION_MODE=danger-full-access 一条环境变量:官方 dsh-base/cordis.patch.yml:217/233 直接读它决定 sandbox mode 与 approval policy;新用户自动生效(env 随 spawn 注入,无需铺 profile);且完全复用官方逻辑(预设表 / 设置 UI 都不动)

官方逻辑原文(@deepseek-ai/dsh-base/cordis.patch.yml):

mode:   !!js process.env.DSH_PERMISSION_MODE ?? 'workspace-write'
policy: !!js "(process.env.DSH_PERMISSION_MODE ?? 'workspace-write') === 'danger-full-access' ? 'never' : 'ask'"

→ 设为 danger-full-access 时:沙箱模式 = 完全权限,审批策略 = never(一次都不弹确认,正是「授权一次、别反复点」要的效果)。

二、为什么这样是安全的(隔离边界上移)

层 谁提供 状态
内层 dsh 自带沙箱(read-only/workspace-write,靠 Landlock/bubblewrap) 本机不可用(内核 5.10 无 Landlock、bwrap 后端在平台容器内探测失败)→ 受限模式 fail-closed 拒绝执行
外层 平台 systemd-run --scope + bwrap + setpriv 正常,真正的边界:mount 路径隔离(只暴露用户根)+ uid 隔离 + cgroup(512M/150%/128)

源码依据:SANDBOX_UNAVAILABLE 的定义即「a requested confined mode when no backend is usable」——danger-full-access 不是受限模式,不需要后端;其报错文案本身也把 danger-full-access 列为官方逃生口径。→ 改档位不会引入新的暴露面,只是不再叠加一个坏的冗余层。

三、实现(2 处,均在本仓库自研编排器内,不碰官方程序)

文件 改动
src/supervisor/spawn.ts ALLOWED_ENV 增加 DSH_PERMISSION_MODE(否则被 scrubEnv 丢弃 —— 这是本项目的已知卡点)
src/supervisor/orchestrator.ts baseEnv() 注入 DSH_PERMISSION_MODE: process.env.DSH_PERMISSION_MODE ?? 'danger-full-access'(运维可用同名 env 覆盖,改档位不必改码)

npm run build 通过;systemctl restart dshs 后实例 respawn。

四、验证

项 结果
实例进程 env ✅ pid=240941/240943/240944 全部 DSH_PERMISSION_MODE=danger-full-access
是否存在用户级覆盖 ✅ 无:admin 与 guest 的 settings.yaml 都没有 permission: 键;全盘 yaml/yml/json 除会话记录外无命中 → 配置派生的默认即生效
新用户是否自动生效 ✅ 是(env 在 spawn 时注入,与 profile 无关)
官方逻辑映射 ✅ 源码核实(见上 yaml 片段)
受限模式才需后端 ✅ 源码核实(SANDBOX_UNAVAILABLE = confined mode 专用)
末段 UI 实测 ⚠️ 未完成:headless Chrome 能进实例、UI 显示访问模式,但「新建会话 / 发送消息」的脚本化点击未成功创建会话(dsh 会话在发首条消息时才落盘)。留给人工点击一次确认

五、重要副作用(必须知道)

权限档位是「会话级播种」的,不跟随后续默认变化。 会话创建时会写入 3 条种子事件(实测旧会话 session-00341dea):

permission/preset {preset:"workspace-write"}
sandbox/mode      {mode:"workspace-write"}
approval/policy   {policy:"ask"}

→ 已存在的旧会话仍显示「工作区内修改」(实例 UI 就是这个表现),只有新建的会话才拿到「完全权限」。 因此:给用户的话术应是「新开一个会话」,而不是「刷新页面」。

六、风险与后续

  1. 审批确认被关闭:danger-full-access 在官方语义下等价于 approval: never。平台容器仍是硬边界,但失去了「危险操作人工确认」这层交互护栏。
  2. 未覆盖的残留风险(与本次改动无关,但关掉审批后更值得关注):
    • 实例共享宿主网络(可连 3080/8888/32022 等宿主监听端口)
    • 出网无白名单(档案 14 只封了云元数据 + 观测外联)
  3. 建议后续:① 补出网白名单(nftables);② 若要保留「危险操作确认」又想免去反复点击,可评估在 profile patch 里新增自定义预设(sandbox: danger-full-access + approval: ask)——但那属于方案 A2,本次未采用。