1
0
Files
DiAL/openspec/specs/expect-body-checkers/spec.md
lanyuanxiaoyao bcfac52112 refactor: HTTP checker 质量加固
- failure actual 截断格式改为 …(共 N 字符),标量不序列化直接返回
- 新增 redos.ts 实现 ReDoS 静态检测(嵌套量词/重叠交替),启动期拒绝危险正则
- JSON body rules 共享同一次 JSON.parse 结果,避免重复解析
- checkCssRule 重构为线性流程,消除 exist:true 与无 operator 的冗余分支
- extract checkEarlyTimeout 辅助函数,明确提前 duration 检查意图
- 补充 303/307/308 重定向、相对路径 Location、混合 body rules 集成测试
2026-05-13 21:35:05 +08:00

266 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Purpose
定义 HTTP 拨测中响应体校验方法集contains/regex/json/css/xpath、操作符系统和响应头校验的行为规范。
## Requirements
### Requirement: 响应体多种校验方法
系统 SHALL 支持对 HTTP 响应体进行五种可组合的校验方法contains子串、regex正则、jsonJSONPath、cssCSS 选择器、xpathXPath。这些方法 MUST 配置在 `expect.body` 有序数组中。
#### Scenario: contains 子串匹配
- **WHEN** HTTP target 配置 `expect.body: [{contains: "healthy"}]`,且响应体包含 `"healthy"`
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: contains 不匹配
- **WHEN** HTTP target 配置 `expect.body: [{contains: "healthy"}]`,且响应体不包含该文本
- **THEN** 系统 SHALL 判定 matched 为 false并记录该规则的 failure.path
#### Scenario: regex 正则匹配
- **WHEN** HTTP target 配置 `expect.body: [{regex: '"status"\\s*:\\s*"ok"'}]`,且响应体匹配该正则
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: regex 不匹配
- **WHEN** HTTP target 配置 regex body 规则,且响应体不匹配该正则
- **THEN** 系统 SHALL 判定 matched 为 false并记录该规则的 failure.path
#### Scenario: json JSONPath 等值匹配
- **WHEN** HTTP target 配置 `expect.body: [{json: {path: "$.status", equals: "ok"}}]`,且响应 JSON 中 `$.status` 值为 `"ok"`
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: json JSONPath 值不匹配
- **WHEN** HTTP target 配置 json body 规则,且提取值不符合期望
- **THEN** 系统 SHALL 判定 matched 为 false并记录包含 JSONPath 的 failure.path
#### Scenario: json 解析失败
- **WHEN** HTTP target 配置了 json body 规则但响应体不是合法 JSON
- **THEN** 系统 SHALL 判定 matched 为 false
#### Scenario: css 选择器匹配
- **WHEN** HTTP target 配置 `expect.body: [{css: {selector: "div#health", equals: "OK"}}]`,且 HTML 中存在 `div#health` 元素文本为 `"OK"`
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: css 选择器匹配属性值
- **WHEN** HTTP target 配置 css 规则带 `attr: "content"` 用于提取属性,且属性值匹配期望
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: css 选择器无匹配元素
- **WHEN** HTTP target 配置了 css 选择器但 HTML 中无匹配元素
- **THEN** 系统 SHALL 判定 matched 为 false
#### Scenario: xpath 表达式匹配
- **WHEN** HTTP target 配置 `expect.body: [{xpath: {path: "/root/status/text()", equals: "ok"}}]`,且 XML 中 `/root/status` 节点文本为 `"ok"`
- **THEN** 系统 SHALL 判定该 body 规则通过
#### Scenario: xpath 表达式无匹配节点
- **WHEN** HTTP target 配置了 xpath 表达式但 XML 中无匹配节点
- **THEN** 系统 SHALL 判定 matched 为 false
### Requirement: 多种 body 校验方法 AND 组合
系统 SHALL 支持在 `expect.body` 数组中同时配置多种 body 校验方法,所有方法均通过时 matched 方为 true。
#### Scenario: 多种方法全部通过
- **WHEN** HTTP target 的 `expect.body` 数组依次配置 contains、json、regex且全部通过
- **THEN** 系统 SHALL 判定 matched 为 true
#### Scenario: 多种方法任一失败
- **WHEN** HTTP target 的 `expect.body` 数组第一条 contains 不通过,后续还有 json 规则
- **THEN** 系统 SHALL 判定 matched 为 false且不再检查后续 json 规则
### Requirement: 操作符系统
系统 SHALL 支持对提取值和文本值使用以下操作符进行比较equals默认等值、contains子串包含、match正则匹配、empty空值判断、exists存在性判断、gte/lte/gt/lt数值比较
#### Scenario: 标量值隐式 equals
- **WHEN** 配置的期望值为标量(字符串/数字/布尔/null`equals: "ok"`
- **THEN** 系统 SHALL 使用 equals 操作符,对实际值做严格相等比较
#### Scenario: 显式 contains 操作符
- **WHEN** 配置 `{contains: "success"}`,且实际值包含 `"success"`
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: 显式 match 操作符
- **WHEN** 配置 `{match: '\\d+\\.\\d+\\.\\d+'}`,且实际值匹配该正则
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: empty 操作符判断为空
- **WHEN** 配置 `{empty: true}`,且实际值为空数组 `[]`
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: empty 操作符判断非空
- **WHEN** 配置 `{empty: false}`,且实际值为 `[1, 2]`
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: exists 操作符判断存在
- **WHEN** 配置 `{exists: false}`,且实际值不存在
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: gte 数值比较
- **WHEN** 配置 `{gte: 10}`,且实际值为 `15`(数字)
- **THEN** 系统 SHALL 判定该规则通过
#### Scenario: gt/lt 数值比较
- **WHEN** 配置 `{gt: 0, lt: 1000}`,且实际值为 `500`
- **THEN** 系统 SHALL 对同一字段进行多操作符复合比较,全部通过则该规则通过
### Requirement: 响应头校验
系统 SHALL 支持通过 `expect.headers` 配置对 HTTP 响应头进行键值规则校验header 名称匹配 MUST 不区分大小写。
#### Scenario: 响应头匹配
- **WHEN** HTTP target 配置 `expect.headers: {"Content-Type": {contains: "application/json"}}`,且响应包含该 header 且值匹配
- **THEN** 系统 SHALL 判定 headers 阶段通过
#### Scenario: 响应头不匹配
- **WHEN** HTTP target 配置 `expect.headers: {"Content-Type": {equals: "application/json"}}`,且响应 header 值为 `"text/html"`
- **THEN** 系统 SHALL 判定 matched 为 false
#### Scenario: 响应头缺失
- **WHEN** HTTP target 配置了某个 header 但响应中不存在该 header
- **THEN** 系统 SHALL 判定 matched 为 false
### Requirement: 结构化 expect 失败信息
系统 SHALL 在任一 expect 规则失败时生成结构化 failure用于标识失败阶段、规则路径、期望值、实际值和可读错误信息。actual 值 SHALL 在构造时截断至不超过 200 字符超出部分以省略标记和总字符数替代。expected 值不截断。
#### Scenario: body 规则失败信息
- **WHEN** HTTP target 的 `expect.body[1].json` 规则失败
- **THEN** failure SHALL 包含 kind=`mismatch`、phase=`body`、path 指向 `expect.body[1]`,并包含 message
#### Scenario: actual 值截断
- **WHEN** 失败规则的实际值为字符串且长度超过 200 字符
- **THEN** failure.actual SHALL 为前 200 字符加 `…(共 N 字符)` 后缀,其中 N 为原始总字符数
#### Scenario: actual 值未超限
- **WHEN** 失败规则的实际值为字符串且长度不超过 200 字符
- **THEN** failure.actual SHALL 保留完整原始值,不做截断
#### Scenario: actual 值为对象或数组
- **WHEN** 失败规则的实际值为对象或数组,且 JSON 序列化后长度超过 200 字符
- **THEN** failure.actual SHALL 为序列化后前 200 字符加 `…(共 N 字符)` 后缀
#### Scenario: actual 值为标量
- **WHEN** 失败规则的实际值为 number、boolean、null 或 undefined
- **THEN** failure.actual SHALL 保留原始值,不做截断
### Requirement: 状态码范围匹配
系统 SHALL 支持在 `expect.status` 数组中使用范围模式字符串(`"1xx"``"2xx"``"3xx"``"4xx"``"5xx"`),与精确数字混合使用。范围模式 SHALL 匹配对应百位段内的所有状态码。其他范围模式 SHALL 在启动期配置校验失败。
#### Scenario: 1xx 范围匹配
- **WHEN** HTTP target 配置 `expect.status: ["1xx"]`,且响应状态码为 101
- **THEN** 系统 SHALL 判定状态码匹配
#### Scenario: 2xx 范围匹配
- **WHEN** HTTP target 配置 `expect.status: ["2xx"]`,且响应状态码为 200
- **THEN** 系统 SHALL 判定状态码匹配
#### Scenario: 2xx 范围匹配 204
- **WHEN** HTTP target 配置 `expect.status: ["2xx"]`,且响应状态码为 204
- **THEN** 系统 SHALL 判定状态码匹配
#### Scenario: 2xx 范围不匹配 301
- **WHEN** HTTP target 配置 `expect.status: ["2xx"]`,且响应状态码为 301
- **THEN** 系统 SHALL 判定状态码不匹配
#### Scenario: 混合精确值与范围模式
- **WHEN** HTTP target 配置 `expect.status: ["2xx", 301]`,且响应状态码为 301
- **THEN** 系统 SHALL 判定状态码匹配(精确值 301 匹配)
#### Scenario: 混合精确值与范围模式范围命中
- **WHEN** HTTP target 配置 `expect.status: ["2xx", 301]`,且响应状态码为 204
- **THEN** 系统 SHALL 判定状态码匹配2xx 范围命中)
#### Scenario: 5xx 范围匹配
- **WHEN** HTTP target 配置 `expect.status: ["5xx"]`,且响应状态码为 503
- **THEN** 系统 SHALL 判定状态码匹配
#### Scenario: 非 HTTP 范围模式启动失败
- **WHEN** HTTP target 配置 `expect.status: ["6xx"]`
- **THEN** 系统 SHALL 在启动期配置校验失败
### Requirement: HTTP expect 规则启动期校验
系统 SHALL 在启动期校验 HTTP expect 中已支持字段的类型、格式、未知字段和可编译表达式。HTTP expect、body rule、json/css/xpath rule 和 operator 对象中的未知字段 SHALL 导致启动期配置失败。每个 body rule 对象 MUST 恰好包含 contains、regex、json、css、xpath 中的一种规则类型。纯 operator 对象 MUST 至少包含一个已知 operatorbody 提取规则可以不配置 operator并以路径、元素或节点存在作为通过语义。`equals` operator SHALL 支持任意 JSON value包括数组和对象。系统 SHALL 在启动期对 regex body 规则和 match operator 的正则表达式进行 ReDoS 安全检测,含有嵌套量词等危险模式的正则 SHALL 导致启动期配置失败。
#### Scenario: body rule 使用 regex 字段
- **WHEN** HTTP target 配置 `expect.body: [{regex: "ok|healthy"}]` 且 regex 可编译且无 ReDoS 风险
- **THEN** 系统 SHALL 接受该配置,并在运行期按 regex body 规则匹配响应体
#### Scenario: body rule 不支持 match 字段
- **WHEN** HTTP target 配置 `expect.body: [{match: "ok"}]` 且该规则没有 contains、regex、json、css、xpath 任一支持字段
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: body rule 忽略未知字段 → body rule 未知字段启动失败
- **WHEN** HTTP target 配置 `expect.body: [{contains: "ok", note: "ignored"}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,提示 `note` 是未知字段
#### Scenario: body rule 多支持字段非法
- **WHEN** HTTP target 的同一条 body rule 同时配置 contains 和 regex
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: operator match 正则非法
- **WHEN** HTTP target 的 expect.headers、json、css 或 xpath operator 配置了不可编译的 match 正则
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: operator 数值比较类型非法
- **WHEN** HTTP target 的 expect operator 配置 gt、gte、lt 或 lte且对应值不是有限数字
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: operator 布尔类型非法
- **WHEN** HTTP target 的 expect operator 配置 empty 或 exists且对应值不是布尔值
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: JSONPath 子集非法
- **WHEN** HTTP target 的 json body rule path 不符合系统支持的 JSONPath 子集
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: operator 未知字段非法
- **WHEN** HTTP target 的 expect operator 配置了 `foo: "bar"` 等未知 operator 字段
- **THEN** 系统 SHALL 在启动期配置校验失败
#### Scenario: equals 支持对象
- **WHEN** HTTP target 配置 `expect.body: [{json: {path: "$.payload", equals: {status: "ok"}}}]`
- **THEN** 系统 SHALL 接受该配置,并在运行期使用深度相等比较提取值和对象期望
#### Scenario: equals 支持数组
- **WHEN** HTTP target 配置 `expect.body: [{json: {path: "$.items", equals: ["a", "b"]}}]`
- **THEN** 系统 SHALL 接受该配置,并在运行期使用深度相等比较提取值和数组期望
#### Scenario: 纯 operator 对象不能为空
- **WHEN** HTTP target 的 `expect.headers` 中某个 header 期望配置为空对象 `{}`
- **THEN** 系统 SHALL 在启动期配置校验失败,要求显式配置至少一个 operator
#### Scenario: json rule 允许存在性语义
- **WHEN** HTTP target 配置 `expect.body: [{json: {path: "$.status"}}]`
- **THEN** 系统 SHALL 接受该配置,并在运行期以 JSONPath 值存在作为通过语义
#### Scenario: css rule 未知字段非法
- **WHEN** HTTP target 配置 `expect.body: [{css: {selector: "h1", unknown: true}}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,提示未知字段
#### Scenario: xpath rule 未知字段非法
- **WHEN** HTTP target 配置 `expect.body: [{xpath: {path: "/html/body", unknown: true}}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,提示未知字段
#### Scenario: regex body 规则含嵌套量词启动失败
- **WHEN** HTTP target 配置 `expect.body: [{regex: "(a+)+$"}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,提示正则存在 ReDoS 风险
#### Scenario: match operator 含嵌套量词启动失败
- **WHEN** HTTP target 的 expect operator 配置 `{match: "(\\d+)*x"}`
- **THEN** 系统 SHALL 在启动期配置校验失败,提示正则存在 ReDoS 风险
#### Scenario: 安全正则通过校验
- **WHEN** HTTP target 配置 `expect.body: [{regex: "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"}]`
- **THEN** 系统 SHALL 接受该配置(无嵌套量词,无 ReDoS 风险)
### Requirement: HTTP body 运行期失败结构化
系统 SHALL 将 HTTP body 运行期失败记录为结构化 CheckFailure并保留与具体规则相关的 phase 和 path。响应内容不符合配置 SHALL 记录为 mismatch响应内容无法按配置解析或解码 SHALL 记录为 error。
#### Scenario: JSON 响应不是合法 JSON
- **WHEN** HTTP target 配置 json body rule但响应体不是合法 JSON
- **THEN** 系统 SHALL 记录 `failure.kind="error"``failure.phase="body"`,且 failure.path SHALL 指向对应 json 规则
#### Scenario: CSS selector 无匹配元素
- **WHEN** HTTP target 配置 css body rule但响应 HTML 中无匹配元素
- **THEN** 系统 SHALL 记录 `failure.kind="mismatch"``failure.phase="body"`,且 failure.path SHALL 指向对应 css 规则
#### Scenario: XPath 无匹配节点
- **WHEN** HTTP target 配置 xpath body rule但响应 XML/HTML 中无匹配节点
- **THEN** 系统 SHALL 记录 `failure.kind="mismatch"``failure.phase="body"`,且 failure.path SHALL 指向对应 xpath 规则