dsh-command-guard
DSH 的命令级守卫:默认一切放行,命中你配置的规则时 ask(弹审批等你点)或 deny(直接拒绝)。
规则两个维度:command(整条命令行的正则)与 workdir(工作目录正则)。两者都填是「且」,只填一个则另一维不限制;第一条命中的规则生效,其余一律放行。
安装
装插件和「让 ask 能弹出来」是两步——DSH 里这是两个独立的旋钮,本插件只管前者。
第一步:装插件
dsh plugin --profile web add github:john-walks-slow/dsh-command-guard
pnpm ≥10 的用户按提示把包名加进 profile 的 pnpm-workspace.yaml → allowBuilds,再重跑一次(插件从源码构建,prepare 是自包含的)。建议 pin 到 commit:github:john-walks-slow/dsh-command-guard#<sha>。
第二步:加一档「全权 + 审批」的权限预设
出厂预设里没有这个组合(danger-full-access 绑死 approval: never;workspace-write 会限制文件写入),所以在 profile 的 cordis.patch.yml 里加一档:
- id: permission
name: "@deepseek-ai/dsh-permission-presets"
config:
presets:
guarded:
sandbox: danger-full-access
approval: ask
name: Guarded
defaultPreset: guarded
- 这一行是整块替换
permission 的 config:若你原本还配着别的预设(read-only / workspace-write / …),要一并写全,否则会被清掉。
- 不加预设也能用,只要会话的 approval 策略本来就是
ask(DSH 未显式设置时的默认值)。但如果会话落在 never 档(如 danger-full-access 预设),ask 规则会退化成硬拒:命令直接失败,并说明命中哪条规则,不会弹窗。
规则
- id: command-guard # 行 id 保持 command-guard:设置页按这个 id 找命名空间
name: dsh-command-guard
config:
rules:
# 丢工作区改动 / 改写历史的 git 命令 → 弹审批
- name: git-destructive
command: "(^|[;&|]\\s*)git\\s+((reset|clean|rebase|filter-branch|restore)\\b|checkout\\s+(-f\\b|--\\s+\\.|\\.\\s*($|[;&|]))|push\\s+(-f\\b|--force)|worktree\\s+remove|stash\\s+(drop|pop))"
action: ask
# 灾难性形态 → 直接拒绝(不依赖审批策略)
- name: disk-destructive
command: "(^|[;&|]\\s*)(sudo\\s+)?(rm\\s+(-[a-zA-Z]+\\s+)*(/(\\s|$|\\*)|~(\\s|$))|mkfs\\.|dd\\s+[^|;&]*of=/dev/|shutdown|reboot)"
action: deny
# 某个目录里的一切命令都要问
- name: system-dirs
workdir: "^/(etc|opt)(/|$)"
action: ask
正则匹配的是整条命令行的文本:命令里只要出现这个形态就算命中——脚本里的示例、注释、乃至 grep 的目标都算。所以别把危险命令的原文直接写进命令行。
设置页
插件带 web 端面板:设置页里会多出一节 Command Guard,可以增删改规则、逐字段编辑。改动写回 profile 补丁,profile 热加载后 apply 带着新规则重跑,不用重启 DSH。规则直接用文本编辑器改 profile 同样有效。
权限与兼容
- 只拦
bash 工具调用,读它的 command / workdir 两个字段;其它工具完全不经过守卫。
- 不联网、不读写你的文件、不执行任何命令:
ask / deny 只是把决定交回 DSH 的审批与工具流水线。
- 走 DSH 保留的
tools/pre-execute 扩展点;运行时依赖只有宿主供给的 cordis / schemastery。
ask 需要应答者(Web 客户端自带审批 UI)。应答者缺失或策略为 never 时按 fail-closed 拒绝——绝不放行。
MIT License.