Skip to content

03 · 静态评估引擎

src/auto —— 不依赖数据库的纯判定

host 编排在 src/index.ts,真正「长脑子」的静态规则引擎在 src/auto/。三者移植自 @nanmicoder/dsh-auto-mode(MIT),并在本项目重写为独立实现。

文件职责
constants.ts27数值阈值默认值唯一事实源:5/8/10s、3/20、4000、8s/1024,及学习族(阈值 3/TTL 30d/100 条/会话放行帽 50)
risk-tokens.ts13HIGH 风险正则(NAME/REASON),供分类器与 policy 共用,防漂移
paths.ts213路径规范化(Windows 命名空间/NT 别名折叠、~ 展开、win32 小写)、受保护/关键路径判定、运行态文件名单
shell.ts1016Bash/PowerShell 词法分解(sticky 正则状态机)+ 整行熔断 + 逐段静态分类
policy.ts370每次工具调用的确定性第一遍分类 assessTool(推断型、保留类型检查)
rules.ts370Claude-Code 风格声明规则解析/求值(纯函数,host 与浏览器共用)
classifier.ts75预分类提示词、参数脱敏、严格响应解析
dsh-classifier.ts94复用 ctx.llm 做低 token 分类请求(temperature 0)
decision.ts722纯决策函数:评审解析、人机竞速、来源标注、熔断状态机、静态名单
trust.ts101web 路由信任平面(loopback/LAN 边界、Host 伪造防护、在线端点 URL 校验)
artifacts.ts98本会话成功创建路径的内存出处登记(删除豁免依据)
audit.ts45append-only 审批审计(清空留墓碑、5MiB 裁剪)
review-mode.ts52每会话评审模式持久化快照

同层的其余模块(类别层 category.ts、学习层 learning.ts、diff 预览 editdiff.ts、耗时遥测 latency.ts、上下文探针 probe.ts、结果脱敏 redact.ts、重试 retry.ts)各有专章或见 §14 全量清单。

3.1 assessTool —— 每一次调用的 17 步判定 policy.ts:L230-370

下面 17 个分支与 policy.ts:L230-370 的判定顺序一一对应。一级分支数没有变,但读/写/补丁/编辑四步内部各自长出了子闸(受保护读、敏感名熔丝、插件运行态无条件拒):

第⑰步语义

兜底方向是「拿不准就问人」:一个注册插件工具若没有任何已知形态可对号入座,一律转人工并允许语义分类器介入,绝不因为「名字无害」而静默放行

3.2 硬拒闸门 hardDenyReason policy.ts:L198-228

  • 凭据物质web_fetch/curl/wget 或外部写工具,参数里含 PEM 私钥、sk- / ghp_ / github_pat_ / xox*AKIA[0-9A-Z]{16}、aws 密钥赋值、Bearer ….ssh 路径等 → 拒。
  • shell 熔断:bash/pwsh 命令走 hardDenyShellReason(见 §3.3)。
  • 变更目标不可读:write/edit/apply_patch/str_replace_editor(≠view) 目标解析不出 → 拒(fail-closed,宁可误拒)。
  • 破坏性工具指向受保护路径 → 拒。

3.3 shell 命令分析管线 shell.ts

  • 只读名单刻意不含 cd(会改变后续段 cwd 解析基准)。
  • routineInlineProbepython -c 只放行 import/print 字面量,node -e 只放行 require/console.log(process.version) —— 内联代码只认可「绝对安全」形态。
  • 危险 token 提取:sensitiveMarker(.ssh/.env/密钥关键词)、dshHomeExfil(4 组模式抓 DSH_HOME 外传)、dynamicHomeTarget($HOME 动态目标)→ 全部绕过静态判定。
  • 写重定向脱离只读快径:命令含真实文件写重定向(>/>>/>|/&>/N>,非 discard sink)时,其段不得走只读命令快径放行——落入既有评估流;/dev/null、NUL、$null 等 discard sink 维持快径。
  • build/test 与版本探测快径目标守卫:快径仅保留给「写目标全为 discard sink 或工作区内非敏感非受保护非运行态路径」——区外/敏感/受保护/运行态目标一律脱离快径进入正常评估(categoryMode: aggressive 与 trustedDirs 放宽模式同样生效)。

3.4 路径保护清单 paths.ts

类别内容判定
家目录根 / DSH_HOME 树~~/.dsh(env DSH_HOME 或默认)hardDestructiveTargetReason → 硬拒(allowedDshSubpaths 白名单可豁免)
凭据根.ssh .gnupg .aws .azure .kube .config/gcloudisCriticalPath
shell 启动文件(12).bashrc .bash_profile .bash_login .bash_logout .profile .zshrc .zprofile .zlogin .zlogout .kshrc .cshrc .tcshrcisCriticalPath(家目录变体硬拒;工作区变体 ask)
系统关键目录POSIX: /etc /bin /sbin /usr /system /library /private/etc /boot ;Win: windows/program files/boot…isCriticalPath
工作区元数据首段.git .vscode .idea .husky .dshisProtectedProjectPath → 读/写都交人工
秘密文件 basename.gitconfig .gitmodules .bashrc .bash_profile .zshrc .zprofile .profile .mcp.json .netrc .npmrc .pypircisProtectedProjectPath
环境密钥文件.env / .env.*.env.example 例外isProtectedProjectPath
Windows 设备/NT 命名空间\\.\ \device\ \\?\ \??\(非 UNC/X: 变体)canonicalizeWindowsNamespace 折叠后再判包含
保留设备名con prn aux nul com1-9 lpt1-9硬拒

symlink 逃逸:文本层判定无法识破快捷方式/软链接指向工作区外(如 ws/ln → ~/.bashrc)。宿主侧守卫 symlinkEscapeReasonindex.ts:L1814-1866)取 symlinkGuardTargets 提取每个工具的真实路径操作数,对「文本上在工作区内/受信区」的目标做 realpath 最深祖先解析,一旦真实路径离开工作区/受信区就硬拒。受信区不止插件目录:trustedDirs 成员与 allowedDshSubpaths 一并构成复检区(index.ts:L1827);aggressive 模式下「普通出区」是设计目标故放行,但落在 critical 树 / DSH_HOME / 插件运行态文件上的逃逸仍硬拒(index.ts:L1849-1861)——运行态文件复检与位置模式无关,改审批/审计/学习状态在任何模式下都不算例行写。

3.5 声明式规则 rulesText rules.ts —— 用户写的「最优先纸条」

text
# 语法(每行一条,空行与 # 注释忽略)
Tool(pattern) | allow|deny|human [| reason|toolName|arguments]
pattern       | allow|deny|human [| field]

# 例:禁止任何含 "rm -rf" 的 bash
bash(rm\s+-\s*rf) | deny
# 例:任何工具的 any_dangling 参数命中即交人
(any_dangling)     | human
  • 工具作用域可逗号多选(含 * 通配);无括号则适配所有工具;field 缺省 arguments
  • 首条命中即胜evaluateRules 先用 extractRuleTarget 抽取命令文本(command/script/code/prompt/text/content),防锚定正则(如 ^git push)被 JSON 信封击穿。
  • ReDoS 防护:长度 ≤2000;拒绝嵌套无界量词 (a+)+、交替外套量词、嵌套重复组、{n,} 计数重复。
  • host 与浏览器设置卡共用同一份 parseRulesText(错误逐行红字显示)。
  • 干跑 rulesDryRun:只记命中不执法(host 端 index.ts:L2448-2449)。

3.6 产物登记 ArtifactRegistry artifacts.ts