外观
03 · 静态评估引擎
src/auto —— 不依赖数据库的纯判定
host 编排在 src/index.ts,真正「长脑子」的静态规则引擎在 src/auto/。三者移植自 @nanmicoder/dsh-auto-mode(MIT),并在本项目重写为独立实现。
| 文件 | 行 | 职责 |
|---|---|---|
constants.ts | 27 | 数值阈值默认值唯一事实源:5/8/10s、3/20、4000、8s/1024,及学习族(阈值 3/TTL 30d/100 条/会话放行帽 50) |
risk-tokens.ts | 13 | HIGH 风险正则(NAME/REASON),供分类器与 policy 共用,防漂移 |
paths.ts | 213 | 路径规范化(Windows 命名空间/NT 别名折叠、~ 展开、win32 小写)、受保护/关键路径判定、运行态文件名单 |
shell.ts | 1016 | Bash/PowerShell 词法分解(sticky 正则状态机)+ 整行熔断 + 逐段静态分类 |
policy.ts | 370 | 每次工具调用的确定性第一遍分类 assessTool(推断型、保留类型检查) |
rules.ts | 370 | Claude-Code 风格声明规则解析/求值(纯函数,host 与浏览器共用) |
classifier.ts | 75 | 预分类提示词、参数脱敏、严格响应解析 |
dsh-classifier.ts | 94 | 复用 ctx.llm 做低 token 分类请求(temperature 0) |
decision.ts | 722 | 纯决策函数:评审解析、人机竞速、来源标注、熔断状态机、静态名单 |
trust.ts | 101 | web 路由信任平面(loopback/LAN 边界、Host 伪造防护、在线端点 URL 校验) |
artifacts.ts | 98 | 本会话成功创建路径的内存出处登记(删除豁免依据) |
audit.ts | 45 | append-only 审批审计(清空留墓碑、5MiB 裁剪) |
review-mode.ts | 52 | 每会话评审模式持久化快照 |
同层的其余模块(类别层
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 解析基准)。 routineInlineProbe:python -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/gcloud | isCriticalPath |
| shell 启动文件(12) | .bashrc .bash_profile .bash_login .bash_logout .profile .zshrc .zprofile .zlogin .zlogout .kshrc .cshrc .tcshrc | isCriticalPath(家目录变体硬拒;工作区变体 ask) |
| 系统关键目录 | POSIX: /etc /bin /sbin /usr /system /library /private/etc /boot ;Win: windows/program files/boot… | isCriticalPath |
| 工作区元数据首段 | .git .vscode .idea .husky .dsh | isProtectedProjectPath → 读/写都交人工 |
| 秘密文件 basename | .gitconfig .gitmodules .bashrc .bash_profile .zshrc .zprofile .profile .mcp.json .netrc .npmrc .pypirc | isProtectedProjectPath |
| 环境密钥文件 | .env / .env.*(.env.example 例外) | isProtectedProjectPath |
| Windows 设备/NT 命名空间 | \\.\ \device\ \\?\ \??\(非 UNC/X: 变体) | canonicalizeWindowsNamespace 折叠后再判包含 |
| 保留设备名 | con prn aux nul com1-9 lpt1-9 | 硬拒 |
symlink 逃逸:文本层判定无法识破快捷方式/软链接指向工作区外(如 ws/ln → ~/.bashrc)。宿主侧守卫 symlinkEscapeReason(index.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)。