1
0
Files
DiAL/openspec/specs/cmd-checker/spec.md
lanyuanxiaoyao e983e5d75d refactor: 重命名 command checker 为 cmd checker 并适配跨平台测试
将 type/configKey 从 "command" 统一为 "cmd",源码目录 runner/command/ → runner/cmd/,
spec 目录 command-checker/ → cmd-checker/,测试全部改用 bun -e 替代 Unix 系统命令,
归档 cmd-checker-enhancement 变更并同步 delta spec 到主 spec。
2026-05-14 09:23:10 +08:00

142 lines
7.8 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
定义 Cmd 类型拨测目标:通过 `type: cmd` 配置执行本地命令(如进程检查、脚本健康检测),捕获 exit code、stdout、stderr按 expect 规则校验并生成 matched 判定。
## Requirements
### Requirement: cmd target 配置
系统 SHALL 支持 `type: cmd` 的 target 配置,通过 `cmd.exec``cmd.args` 描述本地命令,并使用 cmd 专用字段配置工作目录、环境变量和输出限制。
#### Scenario: 解析 cmd target
- **WHEN** YAML 中 target 配置 `type: cmd``cmd.exec: "pgrep"``cmd.args: ["nginx"]`
- **THEN** 系统 SHALL 将其解析为 cmd checker并保留 exec、args、cwd、env、maxOutputBytes、interval、timeout 和 expect 配置
#### Scenario: cmd target 缺少 exec
- **WHEN** YAML 中 target 配置 `type: cmd` 但缺少 `cmd.exec`
- **THEN** 系统 SHALL 以配置错误退出,并提示该 target 缺少 cmd.exec 字段
#### Scenario: cwd 相对配置文件目录解析
- **WHEN** cmd target 配置 `cmd.cwd: "scripts"` 且配置文件位于 `/opt/checker/probes.yaml`
- **THEN** 系统 SHALL 将 cwd 解析为 `/opt/checker/scripts`
#### Scenario: cmd 不使用 shell
- **WHEN** cmd target 配置 `exec``args`
- **THEN** 系统 MUST 直接执行该程序和参数,不通过 shell 解释整段命令字符串
#### Scenario: env 默认继承并允许覆盖
- **WHEN** cmd target 配置 `cmd.env: {LANG: "C"}` 且当前进程环境包含 `PATH`
- **THEN** 系统 SHALL 继承当前进程的全部环境变量,并将 `LANG` 覆盖为 `"C"`
#### Scenario: 不支持 stdin
- **WHEN** cmd target 配置并执行命令
- **THEN** 系统 MUST NOT 向子进程 stdin 写入数据,避免命令因等待输入而阻塞
### Requirement: cmd checker 执行
系统 SHALL 按 cmd target 配置执行本地命令记录执行耗时、退出码、stdout 和 stderr并在执行失败时产生结构化错误信息。
#### Scenario: 命令正常退出
- **WHEN** cmd target 执行的进程正常退出且 exit code 为 0
- **THEN** 系统 SHALL 记录 `durationMs``statusDetail="exitCode=0"`,并进入 expect 校验
#### Scenario: 命令非零退出
- **WHEN** cmd target 执行的进程正常退出但 exit code 为 1
- **THEN** 系统 SHALL 记录 `statusDetail="exitCode=1"`,并由 expect.exitCode 决定 matched 结果
#### Scenario: 命令启动失败
- **WHEN** cmd target 的 exec 不存在或无法启动
- **THEN** 系统 SHALL 记录 `matched=false`,并在 failure 中写入 kind=`error` 和可读错误信息
#### Scenario: 命令超时
- **WHEN** cmd target 在 timeout 时间内未结束
- **THEN** 系统 MUST 终止该子进程,记录 `matched=false`,并在 failure 中写入命令超时信息
#### Scenario: 命令输出超限
- **WHEN** cmd target 的 stdout 和 stderr 合计输出超过 `maxOutputBytes`
- **THEN** 系统 MUST 停止收集输出并终止该检查,记录 `matched=false`,并在 failure 中写入输出超限信息
### Requirement: cmd expect 校验
系统 SHALL 支持 cmd 专用 expect包括 `exitCode``stdout``stderr`,并按 exitCode、duration、stdout、stderr 的阶段顺序快速失败。
#### Scenario: 默认 exitCode 成功语义
- **WHEN** cmd target 未显式配置 `expect.exitCode`
- **THEN** 系统 SHALL 使用默认 `expect.exitCode: [0]` 进行校验
#### Scenario: 显式 exitCode 校验
- **WHEN** cmd target 配置 `expect.exitCode: [0, 2]` 且实际 exit code 为 2
- **THEN** 系统 SHALL 判定 exitCode 阶段通过,并继续后续 expect 阶段
#### Scenario: exitCode 不匹配快速失败
- **WHEN** cmd target 配置 `expect.exitCode: [0]` 且实际 exit code 为 1
- **THEN** 系统 SHALL 立即返回 `matched=false`,并在 failure 中写入 phase=`exitCode`、path=`expect.exitCode`、expected 和 actual
#### Scenario: stdout 按配置顺序校验
- **WHEN** cmd target 配置 `expect.stdout` 为两个规则,第一条通过且第二条失败
- **THEN** 系统 SHALL 先执行第一条 stdout 规则,再执行第二条,并将 failure.path 指向失败的 `expect.stdout[1]`
#### Scenario: stderr 校验为空
- **WHEN** cmd target 配置 `expect.stderr: [{empty: true}]` 且实际 stderr 为空字符串
- **THEN** 系统 SHALL 判定 stderr 阶段通过
#### Scenario: stdout 失败后不检查 stderr
- **WHEN** cmd target 同时配置 stdout 和 stderr 规则,且 stdout 规则失败
- **THEN** 系统 SHALL 快速失败并 MUST NOT 继续执行 stderr 规则
### Requirement: cmd checker 启动期配置校验
系统 SHALL 在启动期对 cmd checker 的配置契约和语义执行严格校验。Cmd target 的 `cmd` 分组 SHALL 只允许 `exec``args``cwd``env``maxOutputBytes` 字段Cmd expect SHALL 只允许 `exitCode``maxDurationMs``stdout``stderr` 字段。未知字段、非法类型和不可编译正则 MUST 导致启动期配置错误。`expect.exitCode` SHALL 保留原有有限整数数组语义,不限制到特定平台范围。
#### Scenario: cmd args 类型非法
- **WHEN** YAML 中 cmd target 配置 `cmd.args` 不是字符串数组
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd.args 格式错误
#### Scenario: cmd cwd 类型非法
- **WHEN** YAML 中 cmd target 配置 `cmd.cwd` 不是字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd.cwd 必须为字符串
#### Scenario: cmd env 值类型非法
- **WHEN** YAML 中 cmd target 配置 `cmd.env`,且任一环境变量值不是字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd.env 对应变量值必须为字符串
#### Scenario: cmd maxOutputBytes 非法
- **WHEN** YAML 中 cmd target 或 defaults.cmd 配置的 `maxOutputBytes` 不是合法 size 值
- **THEN** 系统 SHALL 以配置错误退出,提示 maxOutputBytes 格式错误
#### Scenario: cmd 分组未知字段失败
- **WHEN** YAML 中 cmd target 的 `cmd` 分组包含 `shell: true` 等未知字段
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd 分组包含未知字段
#### Scenario: cmd expect exitCode 类型非法
- **WHEN** YAML 中 cmd target 配置 `expect.exitCode` 不是整数数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.exitCode 必须为整数数组
#### Scenario: cmd expect exitCode 不限制平台范围
- **WHEN** YAML 中 cmd target 配置 `expect.exitCode` 为有限整数数组
- **THEN** 系统 SHALL 接受该数组,不额外限制为 0-255 等平台相关范围
#### Scenario: cmd expect maxDurationMs 非法
- **WHEN** YAML 中 cmd target 配置 `expect.maxDurationMs` 不是非负有限数字
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.maxDurationMs 格式错误
#### Scenario: stdout 必须为规则数组
- **WHEN** YAML 中 cmd target 配置 `expect.stdout` 但其值不是数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.stdout 必须为数组
#### Scenario: stderr 必须为规则数组
- **WHEN** YAML 中 cmd target 配置 `expect.stderr` 但其值不是数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.stderr 必须为数组
#### Scenario: stdout text rule 空对象非法
- **WHEN** YAML 中 cmd target 配置 `expect.stdout: [{}]`
- **THEN** 系统 SHALL 以配置错误退出,提示 stdout 规则必须包含至少一个合法 operator
#### Scenario: stderr text rule 未知字段非法
- **WHEN** YAML 中 cmd target 配置 `expect.stderr: [{foo: "bar"}]`
- **THEN** 系统 SHALL 以配置错误退出,提示 stderr 规则包含未知 operator
#### Scenario: stdout match 正则非法
- **WHEN** YAML 中 cmd target 配置 `expect.stdout: [{match: "[invalid"}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,而不是延迟到运行期抛错
#### Scenario: cmd expect 未知字段失败
- **WHEN** YAML 中 cmd target 的 expect 包含 `status: [200]` 或其他非 cmd expect 字段
- **THEN** 系统 SHALL 以配置错误退出,提示 expect 包含未知字段