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-shell与guard_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 安装目录)解析。
使用
- 重启 GUI。
- 在权限下拉里选择 FullAccess (safe)(与 danger-full-access 一样拥有全部能力, 但 approval 策略为 ask,且 shell 命令执行前过黑名单)。
- 命中黑名单时,命令不会执行,返回:
调用[guard: blocked by <rule-id>: <reason>] [guard: fingerprint <fp>] [guard: approval available — call guard_allow with this fingerprint ...]guard_allow(附指纹 + 一句理由)会弹出一次人工确认;批准后该次命令可重试执行, 同命令再次执行仍需重新审批(TTL 默认 60s)。 - 不选
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.ts的DEFAULT_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-remove对C:\下任意递归强制删除都命中(含用户目录)。误报的代价是弹一次人工确认——这是防呆层的可接受取舍。 - 编码混淆、字符串拼接、运行时构造可绕过静态扫描 → 只防失误与显形恶意。
- UI 已知限制(暂未实现):权限下拉里
FullAccess (safe)没有图标——图标映射(permissionGlyphs)在 DSH 核心组件ui-conversation/src/client/skeleton/PermissionSelect.tsx,只内置了 read-only / workspace-write / danger-full-access 三个图形。如需图标,须改该核心组件(样式偏好:盾牌 + 锁)并重建 web 前端;作为插件无法从外部注入。