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

14 KiB
Raw Blame History

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 配置的期望值为标量(字符串/数字/布尔/nullequals: "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 规则