dsh-guard-mode

August 15, 2026 · View on GitHub

DSH 插件:在 danger-full-access 之上加一道安全防呆——shell 命令执行前扫描文本, 命中"形状自明且明确危险"的黑名单时,转单次人工批准;未命中则与 FullAccess 完全一致。 为 FullAccess 提供"多一道保险、少一分失控"的日常使用体验。

定位(必须诚实):这不是安全边界。静态文本扫描可被编码混淆、字符串拼接、 运行时构造绕过;它防的是手滑失误形状自明的显形恶意,不防有意的对抗。 要"LLM 无法越界",请使用 workspace-write 或更强的文件沙箱。

安装注意事项

  • 仅支持完整 web 组合(或同等具备以下宿主服务的组合):subprocess / sandbox / sandboxPolicy / sessions / tools / systemPrompt / approval。注入依赖任一缺失都会在激活时失败——不要装进 headless 等精简组合。
  • 不要重复挂载:dsh plugin add 已把本包写进 dsh.profile.bundles,patch 自带 disable pwsh-sandbox + insert guard-shell切勿再往 profile 的 cordis.patch.yml 里手工复制一份同样的 insert——同一 patch 应用两次会导致 guard-shellguard_allow 重复注册,启动失败(与 dsh-deepseek-meter 的警告同理)。
  • 本 bundle 整值覆盖 permission:预设表固定为 read-only / workspace-write / danger-full-access / full-access-safe 四项。如果你的部署自定义过预设表或曾在设置里持久化自定义预设名,bundle 会替换掉它们;请在 profile 的用户层 cordis.patch.yml 里重新覆盖 permission 行以恢复。
  • 版本策略:devDependencies 用 npm 的 0.1.0-rc.6 构建(npm 未发布 0.1.0-rc.5);产物为纯转译、@deepseek-ai/* 全部外部化,在宿主 rc.5 上运行。API 兼容性在 rc.5 源码与 rc.6 两套环境下均经端到端测试验证。

安装

从 GitHub(发布后)

dsh plugin --profile web add github:<you>/dsh-guard-mode

git 安装运行包的 prepare 构建脚本,pnpm ≥10 首次安装需要在 profile 的 pnpm-workspace.yaml 允许构建:

allowBuilds:
  dsh-guard-mode: true

该许可意味着允许包的代码在安装时于你机器上执行,仅对信任的包开启,并建议锁定 commit(github:<you>/dsh-guard-mode#<sha>)。

从 tarball(当前形态)

cd dsh-guard-mode && pnpm install && pnpm build && pnpm pack
dsh plugin --profile web add ./dsh-guard-mode-0.1.0.tgz

不要用源码目录 link: 安装:插件的 devDependencies(编译期 @deepseek-ai/*)会遮蔽 dsh 宿主提供的版本,造成双实例。发布物(tgz / github)是唯一受支持的安装形态——files 只含构建产物,运行时依赖全部由宿主(dsh 安装目录)解析。

使用

  1. 重启 GUI。
  2. 在权限下拉里选择 FullAccess (safe)(与 danger-full-access 一样拥有全部能力, 但 approval 策略为 ask,且 shell 命令执行前过黑名单)。
  3. 命中黑名单时,命令不会执行,返回:
    [guard: blocked by <rule-id>: <reason>]
    [guard: fingerprint <fp>]
    [guard: approval available — call guard_allow with this fingerprint ...]
    
    调用 guard_allow(附指纹 + 一句理由)会弹出一次人工确认;批准后该次命令可重试执行, 同命令再次执行仍需重新审批(TTL 默认 60s)。
  4. 不选 FullAccess (safe)(即 workspace-write / danger-full-access 原样)时, 守卫不启用,行为与未安装完全一致。

配置:$DSH_HOME/guard-rules.json

文件缺失或损坏时使用内置默认规则(损坏时会有日志告警)。格式:

{
  "enabledPresets": ["full-access-safe"],
  "allowTtlMs": 60000,
  "rules": [
    { "id": "destructive-remove", "pattern": "\\b(Remove-Item|del|rd|rmdir)\\b(?=[^;]*(\\\\Windows|SystemRoot|[Cc]:\\\\))(?=[^;]*(-Recurse|-Force|/s\\b))", "reason": "递归强制删除系统路径", "enabled": true }
  ]
}
  • enabledPresets:启用守卫的 preset 名列表(空数组 = 永不启用)。
  • rules:pattern 是正则(大小写不敏感,对整个命令文本匹配;用 [\s\S]* 表示跨行),enabled: false 可临时停用。
  • 修改后需重启 dsh 生效。
  • 内置默认规则见 src/decide.tsDEFAULT_RULES(README 示例只是其中一条,JSON 转义易错,建议以源码为准)。

边界与限制

  • 只覆盖 shell 命令执行(pwsh);文件工具(tool-fs 等结构化读写)不在守卫范围内。
  • 未武装语义:preset 未知或不是 full-access-safe 时,不启用扫描,命令与普通 FullAccess 完全一致——守卫是"用户显式选择才武装"的防呆层,不是默认开启的边界。
  • 命中后的 fail-closed:approval 为 never(或没有 approval 通道、无 open turn)时,命中即硬拒绝,绝不静默放行。
  • 单次放行缓存按会话隔离,TTL 默认 60s(同会话同命令再次执行仍需重新审批)。
  • 规则是启发式,已知误报示例:\biex\b 会拦任何独立词 iex(如 Get-ChildItem iex);\.env\b 会匹配 .env.example;destructive-removeC:\ 下任意递归强制删除都命中(含用户目录)。误报的代价是弹一次人工确认——这是防呆层的可接受取舍。
  • 编码混淆、字符串拼接、运行时构造可绕过静态扫描 → 只防失误与显形恶意。
  • UI 已知限制(暂未实现):权限下拉里 FullAccess (safe) 没有图标——图标映射(permissionGlyphs)在 DSH 核心组件 ui-conversation/src/client/skeleton/PermissionSelect.tsx,只内置了 read-only / workspace-write / danger-full-access 三个图形。如需图标,须改该核心组件(样式偏好:盾牌 + 锁)并重建 web 前端;作为插件无法从外部注入。