1
0
Files
DiAL/openspec/specs/probe-config/spec.md
lanyuanxiaoyao bce0f8e7a8 feat: 增强 HTTP checker 鲁棒性 — 严格配置校验、完整耗时、流式body、重定向与编码完善
启动期校验: 新增 validate.ts 对 HTTP config/expect/body rule/operator 全方位严格校验
执行语义: body 改为 Web Stream 流式超限中止,durationMs 覆盖完整执行
错误归属: status/header 失败不读 body,phase 分层 request/body,early duration skip body
重定向: 跟随前释放 body,POST/303 改 GET 清理 header,跨 origin 剥离敏感 header
编码: 支持 quoted charset,未知编码返回结构化解码错误
文档: README match→regex+durationMs,DEVELOPMENT 执行流程与错误归属
测试: +63 测试覆盖全部新增场景,325 pass 0 fail
规格: 同步 probe-config/probe-engine/expect-body-checkers 3 个 delta spec
2026-05-13 08:00:05 +08:00

235 lines
13 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 拨测工具的 YAML 配置文件格式、解析校验规则和 CLI 启动流程。
## Requirements
### Requirement: YAML 配置文件格式
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、runtime 配置、checker 默认值和 typed target 列表(含可选 group 字段。target MUST 使用 `type` 字段声明 checker 类型HTTP 领域字段 MUST 放在 `http` 分组command 领域字段 MUST 放在 `command` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`(非负整数)字段。
#### Scenario: 完整配置文件解析
- **WHEN** 系统启动并读取包含 server、runtime、defaults、targets含 group 字段)的 YAML 配置文件
- **THEN** 系统 SHALL 正确解析所有字段并用于初始化服务、调度引擎和对应 checker runner
#### Scenario: 最简 HTTP 配置文件解析
- **WHEN** 系统读取只包含一个 `type: http` target 和 `http.url` 的 YAML 配置文件(省略 server、runtime、defaults 和 expect
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段host=127.0.0.1, port=3000, dir=./data, interval=30s, timeout=10s, runtime.maxConcurrentChecks=20, http.method=GET, http.maxBodyBytes=100MB, http.ignoreSSL=false, http.maxRedirects=0, group="default"
#### Scenario: 最简 command 配置文件解析
- **WHEN** 系统读取只包含一个 `type: command` target 和 `command.exec` 的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, command.cwd 为配置文件所在目录, command.maxOutputBytes=100MB
#### Scenario: per-target 配置覆盖全局默认值
- **WHEN** 某个 target 指定 interval、timeout 或对应领域分组中的默认字段
- **THEN** 该 target SHALL 使用其自身的值,不受 defaults 中对应字段影响
#### Scenario: HTTP target 配置 ignoreSSL
- **WHEN** YAML 配置中 HTTP target 设置 `http.ignoreSSL: true`
- **THEN** 系统 SHALL 解析该字段并在执行时跳过 SSL 证书校验
#### Scenario: HTTP target 配置 maxRedirects
- **WHEN** YAML 配置中 HTTP target 设置 `http.maxRedirects: 5`
- **THEN** 系统 SHALL 解析该字段并在执行时允许最多跟随 5 次重定向
### Requirement: CLI 参数
系统 SHALL 通过单一命令行参数接受 YAML 配置文件路径。
#### Scenario: 指定配置文件启动
- **WHEN** 用户执行 `./dial-server ./probes.yaml`
- **THEN** 系统 SHALL 读取并解析指定路径的 YAML 文件作为配置
#### Scenario: 未提供配置文件路径
- **WHEN** 用户启动程序时未提供任何命令行参数
- **THEN** 系统 SHALL 以错误退出并提示需要指定配置文件路径
#### Scenario: 配置文件不存在
- **WHEN** 用户指定的配置文件路径不存在
- **THEN** 系统 SHALL 以错误退出并提示文件不存在
### Requirement: 配置校验
系统 SHALL 在启动时对 YAML 配置进行完整校验校验失败时以非零状态退出并输出清晰的错误信息。HTTP checker SHALL 对已支持字段执行严格启动期校验;未知字段 SHALL 被忽略,不触发启动失败且不影响运行行为。
#### Scenario: target 缺少必填字段
- **WHEN** YAML 中某个 target 缺少 name 或 type 字段
- **THEN** 系统 SHALL 以错误退出,提示哪个 target 缺少哪个字段
#### Scenario: HTTP target 缺少 url
- **WHEN** YAML 中某个 target 配置 `type: http` 但缺少 `http.url`
- **THEN** 系统 SHALL 以错误退出,提示该 target 缺少 http.url 字段
#### Scenario: command target 缺少 exec
- **WHEN** YAML 中某个 target 配置 `type: command` 但缺少 `command.exec`
- **THEN** 系统 SHALL 以错误退出,提示该 target 缺少 command.exec 字段
#### Scenario: target type 非法
- **WHEN** YAML 中某个 target 的 type 不是 `http``command`
- **THEN** 系统 SHALL 以错误退出,提示不支持的 target type
#### Scenario: target name 重复
- **WHEN** YAML 中存在两个 name 相同的 target
- **THEN** 系统 SHALL 以错误退出,提示重复的 name
#### Scenario: group 字段类型校验
- **WHEN** YAML 中某个 target 的 `group` 字段不是字符串
- **THEN** 系统 SHALL 以错误退出并提示 group 字段类型错误
#### Scenario: interval 格式非法
- **WHEN** interval 或 timeout 值不是有效的时长格式(如 `30s``5m``500ms`
- **THEN** 系统 SHALL 以错误退出并提示格式错误
#### Scenario: maxConcurrentChecks 非法
- **WHEN** runtime.maxConcurrentChecks 不是正整数
- **THEN** 系统 SHALL 以错误退出并提示 runtime.maxConcurrentChecks 格式错误
#### Scenario: size 格式非法
- **WHEN** maxBodyBytes 或 maxOutputBytes 值不是有效的 size 格式
- **THEN** 系统 SHALL 以错误退出并提示支持 B、KB、MB、GB 格式
#### Scenario: HTTP method 非法
- **WHEN** YAML 中某个 HTTP target 的 `http.method` 不是 GET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS 之一
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 method 不合法
#### Scenario: URL 格式非法
- **WHEN** YAML 中某个 HTTP target 的 `http.url` 不以 `http://``https://` 开头
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 URL 格式不合法
#### Scenario: maxRedirects 非法
- **WHEN** YAML 中某个 HTTP target 的 `http.maxRedirects` 为负数
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 maxRedirects 必须为非负整数
#### Scenario: maxRedirects 非整数非法
- **WHEN** YAML 中某个 HTTP target 的 `http.maxRedirects` 不是非负整数(如 `1.5``"5"`
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 maxRedirects 必须为非负整数
#### Scenario: ignoreSSL 类型非法
- **WHEN** YAML 中某个 HTTP target 的 `http.ignoreSSL` 不是布尔值
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 ignoreSSL 必须为布尔值
#### Scenario: HTTP headers 类型非法
- **WHEN** YAML 中某个 HTTP target 的 `http.headers` 不是对象,或任一 header 名和值不能作为字符串使用
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 http.headers 格式错误
#### Scenario: HTTP body 类型非法
- **WHEN** YAML 中某个 HTTP target 的 `http.body` 已配置但不是字符串
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 http.body 必须为字符串
#### Scenario: maxBodyBytes 数字非法
- **WHEN** YAML 中某个 HTTP target 的 `http.maxBodyBytes` 或 defaults.http.maxBodyBytes 是负数、非整数或非安全整数
- **THEN** 系统 SHALL 以错误退出,提示 maxBodyBytes 必须为非负安全整数字节数或合法 size 字符串
#### Scenario: status 模式非法
- **WHEN** YAML 中某个 HTTP target 的 `expect.status` 包含不符合 `1xx``5xx` 格式的字符串(如 `"abc"``"2x"``"6xx"`
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 status 模式不合法
#### Scenario: status 数字非法
- **WHEN** YAML 中某个 HTTP target 的 `expect.status` 包含非整数或不在 100-599 范围内的数字
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 status 数字不合法
#### Scenario: maxDurationMs 非法
- **WHEN** YAML 中某个 target 的 `expect.maxDurationMs` 不是非负有限数字
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 expect.maxDurationMs 格式错误
#### Scenario: HTTP expect headers 非法
- **WHEN** YAML 中某个 HTTP target 的 `expect.headers` 不是对象,或某个 header 期望既不是字符串也不是合法 operator
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 expect.headers 格式错误
#### Scenario: HTTP expect body 必须为数组
- **WHEN** YAML 中某个 HTTP target 的 `expect.body` 已配置但不是数组
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 expect.body 必须为数组
#### Scenario: HTTP body rule 缺少支持字段
- **WHEN** YAML 中某个 HTTP target 的 `expect.body` 数组项未包含 contains、regex、json、css、xpath 任一支持字段
- **THEN** 系统 SHALL 以错误退出,提示该 body rule 缺少支持的规则类型
#### Scenario: HTTP body rule 同时配置多个支持字段
- **WHEN** YAML 中某个 HTTP target 的同一条 body rule 同时包含 contains、regex、json、css、xpath 中的多个支持字段
- **THEN** 系统 SHALL 以错误退出,提示每条 body rule 只能配置一种规则类型
#### Scenario: HTTP body regex 非法
- **WHEN** YAML 中某个 HTTP target 的 body regex 规则不是字符串或不是可编译正则表达式
- **THEN** 系统 SHALL 以错误退出,提示该 body regex 不合法
#### Scenario: HTTP body json path 非法
- **WHEN** YAML 中某个 HTTP target 的 body json 规则缺少 path或 path 不符合系统支持的 JSONPath 子集
- **THEN** 系统 SHALL 以错误退出,提示该 body json path 不合法
#### Scenario: HTTP body css selector 非法
- **WHEN** YAML 中某个 HTTP target 的 body css 规则缺少 selector或 selector 不是非空字符串
- **THEN** 系统 SHALL 以错误退出,提示该 body css selector 不合法
#### Scenario: HTTP body xpath path 非法
- **WHEN** YAML 中某个 HTTP target 的 body xpath 规则缺少 path或 path 不是非空字符串,或可被现有 XPath 库静态判定为语法错误
- **THEN** 系统 SHALL 以错误退出,提示该 body xpath path 不合法
#### Scenario: expect operator 类型非法
- **WHEN** YAML 中某个 HTTP expect operator 的 match 不是可编译正则字符串empty/exists 不是布尔值,或 gt/gte/lt/lte 不是有限数字
- **THEN** 系统 SHALL 以错误退出,提示对应 operator 配置不合法
#### Scenario: unknown 字段忽略
- **WHEN** YAML 中某个 HTTP target、expect 或 rule 对象包含未知字段,且所有已支持字段均合法
- **THEN** 系统 SHALL 忽略未知字段并正常启动
### Requirement: size 配置解析
系统 SHALL 支持使用单位字符串配置读取上限,单位包括 `B``KB``MB``GB`
#### Scenario: 解析 MB
- **WHEN** YAML 中配置 `maxBodyBytes: "100MB"`
- **THEN** 系统 SHALL 将其解析为 104857600 bytes
#### Scenario: 解析 KB
- **WHEN** YAML 中配置 `maxOutputBytes: "512KB"`
- **THEN** 系统 SHALL 将其解析为 524288 bytes
### Requirement: runtime 并发配置
系统 SHALL 支持 `runtime.maxConcurrentChecks` 配置全局最大并发检查数。
#### Scenario: 使用默认并发限制
- **WHEN** YAML 中未配置 runtime.maxConcurrentChecks
- **THEN** 系统 SHALL 使用默认值 20
#### Scenario: 配置并发限制
- **WHEN** YAML 中配置 `runtime.maxConcurrentChecks: 5`
- **THEN** 系统 SHALL 将全局最大并发检查数设置为 5
### Requirement: YAML 配置使用 Bun 内置解析
系统 SHALL 使用 Bun 内置的 `Bun.YAML.parse()` 解析配置文件,不引入外部 YAML 解析库。
#### Scenario: 解析 YAML 内容
- **WHEN** 系统读取 YAML 文件内容
- **THEN** 系统 SHALL 调用 `Bun.YAML.parse()` 将内容解析为配置对象
### Requirement: expect 配置增强
系统 SHALL 支持 typed target 的领域专用 expect 配置,包括 HTTP 的 `status`(支持精确数字和范围模式)、`headers``body` 和 command 的 `exitCode``stdout``stderr`。内容类 expect MUST 使用数组表达配置顺序。
#### Scenario: 解析 HTTP expect 配置
- **WHEN** YAML 配置文件中 HTTP target 的 expect 包含 status、headers、body 规则数组及内部方法
- **THEN** 系统 SHALL 正确解析并存储为 HTTP target 的 expect 字段
#### Scenario: 解析 command expect 配置
- **WHEN** YAML 配置文件中 command target 的 expect 包含 exitCode、stdout 和 stderr 规则数组
- **THEN** 系统 SHALL 正确解析并存储为 command target 的 expect 字段
#### Scenario: 解析 body 有序规则数组
- **WHEN** YAML 中 HTTP target 配置 `expect.body` 为 contains、json、regex 三个数组项
- **THEN** 系统 SHALL 保留数组顺序,供执行阶段按配置顺序快速失败
#### Scenario: 不配置 HTTP status
- **WHEN** HTTP target 未配置 `expect.status`
- **THEN** 系统 SHALL 在执行 expect 时使用默认 `status: [200]` 语义
#### Scenario: 配置 HTTP status 范围模式
- **WHEN** HTTP target 配置 `expect.status: ["2xx"]`
- **THEN** 系统 SHALL 在执行 expect 时匹配所有 200-299 状态码
#### Scenario: 配置 HTTP status 混合模式
- **WHEN** HTTP target 配置 `expect.status: ["2xx", 301]`
- **THEN** 系统 SHALL 在执行 expect 时匹配所有 200-299 状态码或精确匹配 301
#### Scenario: 不配置 command exitCode
- **WHEN** command target 未配置 `expect.exitCode`
- **THEN** 系统 SHALL 在执行 expect 时使用默认 `exitCode: [0]` 语义
#### Scenario: 不配置 expect
- **WHEN** target 未配置任何 expect 规则
- **THEN** 系统 SHALL 正常处理expect 字段为 undefined