1
0
Files
DiAL/openspec/specs/cmd-checker/spec.md
lanyuanxiaoyao 60a54b483f refactor: expect 类型模型重构,Raw/Resolved 双层分离与断言基础设施内聚
- 重命名 ContentRules→ContentExpectations, KeyValueExpect→KeyedExpectations
- 新增 Raw/Resolved 双层模型:resolve 阶段物化为执行计划,store 持久化 Raw 快照
- HTTP body 按需读取:status/headers 失败或无 body expectation 时不读取 body
- 新增 displayValueExpectation() 解包 failure.expected 用户可读展示
- 修复 checkEarlyTimeout 独立 lte/lt 检查,修复 KeyedExpectations JSON Schema
- 新增 expect/value.ts(resolve/check/display)、keyed.ts、content.ts、headers.ts、status.ts
- 删除旧 normalize.ts/matcher.ts/validate-matcher.ts/key-value.ts
- 更新 DEVELOPMENT.md:expect 五层管线表、displayValueExpectation、1.7↔1.10 交叉引用
- 同步 13 个 main specs,归档 refactor-expect-type-model 变更(62/62 tasks)
2026-05-20 16:12:48 +08:00

134 lines
8.4 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 observation并在执行失败时产生结构化错误信息。
#### Scenario: 命令正常退出
- **WHEN** cmd target 执行的进程正常退出且 exit code 为 0
- **THEN** 系统 SHALL 记录 `durationMs` 和包含 exitCode、stdoutPreview、stderrPreview 的 observation并进入 expect 校验API detail SHALL 为 `exitCode=0`
#### Scenario: 命令非零退出
- **WHEN** cmd target 执行的进程正常退出但 exit code 为 1
- **THEN** 系统 SHALL 记录包含 exitCode、stdoutPreview、stderrPreview 的 observation并由 expect.exitCode 决定 matched 结果API detail SHALL 为 `exitCode=1`
#### Scenario: 命令启动失败
- **WHEN** cmd target 的 exec 不存在或无法启动
- **THEN** 系统 SHALL 记录 `matched=false`observation SHALL 为 null并在 failure 中写入 kind=`error` 和可读错误信息
#### Scenario: 命令超时
- **WHEN** cmd target 在 timeout 时间内未结束
- **THEN** 系统 MUST 终止该子进程,记录 `matched=false`,并在 failure 中写入命令超时信息如已收集输出片段observation SHALL 包含 stdoutPreview、stderrPreview 和 error
#### Scenario: 命令输出超限
- **WHEN** cmd target 的 stdout 和 stderr 合计输出超过 `maxOutputBytes`
- **THEN** 系统 MUST 停止收集输出并终止该检查,记录 `matched=false`,并在 failure 中写入输出超限信息observation SHALL 包含已截断输出预览和 error
### Requirement: cmd expect 校验
系统 SHALL 支持 cmd 专用 expect包括 `exitCode``durationMs``stdout``stderr`,并按 exitCode、durationMs、stdout、stderr 的阶段顺序快速失败。`exitCode` SHALL 保持有限整数数组语义,未配置时在 Resolved expect 中默认 `[0]``durationMs` SHALL 使用共享 `RawValueExpectation` 输入并在运行期使用 `ValueExpectation` 校验完整命令执行耗时。`stdout``stderr` MUST 使用共享 `RawContentExpectations` 数组输入并在运行期使用 `ContentExpectations`,直接 matcher 作用于对应输出文本,`json` extractor SHALL 支持对 JSON CLI 输出执行 JSONPath 断言。
#### Scenario: 默认 exitCode 成功语义
- **WHEN** cmd target 未显式配置 `expect.exitCode`
- **THEN** 系统 SHALL 在 Resolved cmd 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=`exitCode`、expected 和 actual
#### Scenario: durationMs 校验
- **WHEN** cmd target 配置 `expect.durationMs: {lte: 1000}` 且实际执行耗时为 1500ms
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `duration`
#### Scenario: stdout 按配置顺序校验
- **WHEN** cmd target 配置 `expect.stdout` 为两个 ContentExpectations第一条通过且第二条失败
- **THEN** 系统 SHALL 先执行第一条 stdout expectation再执行第二条并将 failure.path 指向失败的 `stdout[1]`
#### Scenario: stderr 校验为空
- **WHEN** cmd target 配置 `expect.stderr: [{empty: true}]` 且实际 stderr 为空字符串
- **THEN** 系统 SHALL 判定 stderr 阶段通过
#### Scenario: stdout JSON 输出校验
- **WHEN** cmd target 输出 stdout 为 `{"status":"ok"}` 且配置 `expect.stdout: [{json: {path: "$.status", equals: "ok"}}]`
- **THEN** 系统 SHALL 判定 stdout 阶段通过
#### Scenario: stdout 失败后不检查 stderr
- **WHEN** cmd target 同时配置 stdout 和 stderr expectation且 stdout expectation 失败
- **THEN** 系统 SHALL 快速失败并 MUST NOT 继续执行 stderr expectation
### Requirement: cmd checker 启动期配置校验
系统 SHALL 在启动期对 cmd checker 的配置契约和语义执行严格校验。Cmd target 的 `cmd` 分组 SHALL 只允许 `exec``args``cwd``env``maxOutputBytes` 字段。Cmd expect SHALL 只允许 `exitCode``durationMs``stdout``stderr` 字段。未知字段、非法类型、不可编译正则和 ReDoS 风险正则 MUST 导致启动期配置错误。`expect.exitCode` SHALL 保留原有有限整数数组语义,不限制到特定平台范围。语义校验 MUST NOT 修改 Raw cmd expect 输入。
#### Scenario: cmd args 类型非法
- **WHEN** YAML 中 cmd target 配置 `cmd.args` 不是字符串数组
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd.args 格式错误
#### Scenario: cmd env 值类型非法
- **WHEN** YAML 中 cmd target 配置 `cmd.env`,且任一环境变量值不是字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 cmd.env 对应变量值必须为字符串
#### Scenario: cmd expect exitCode 类型非法
- **WHEN** YAML 中 cmd target 配置 `expect.exitCode` 不是整数数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.exitCode 必须为整数数组
#### Scenario: cmd expect durationMs 非法
- **WHEN** YAML 中 cmd target 配置 `expect.durationMs` 不是合法 `RawValueExpectation`
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.durationMs 格式错误
#### Scenario: stdout 必须为 ContentExpectations 数组
- **WHEN** YAML 中 cmd target 配置 `expect.stdout` 但其值不是数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.stdout 必须为数组
#### Scenario: stderr 必须为 ContentExpectations 数组
- **WHEN** YAML 中 cmd target 配置 `expect.stderr` 但其值不是数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.stderr 必须为数组
#### Scenario: stdout text expectation 空对象非法
- **WHEN** YAML 中 cmd target 配置 `expect.stdout: [{}]`
- **THEN** 系统 SHALL 以配置错误退出,提示 stdout expectation 必须包含至少一个合法 matcher 或 extractor
#### Scenario: stderr text expectation 未知字段非法
- **WHEN** YAML 中 cmd target 配置 `expect.stderr: [{foo: "bar"}]`
- **THEN** 系统 SHALL 以配置错误退出,提示 stderr expectation 包含未知 matcher 或未知 extractor
#### Scenario: stdout regex 正则非法
- **WHEN** YAML 中 cmd target 配置 `expect.stdout: [{regex: "[invalid"}]`
- **THEN** 系统 SHALL 在启动期配置校验失败,而不是延迟到运行期抛错
#### Scenario: cmd expect 未知字段失败
- **WHEN** YAML 中 cmd target 的 expect 包含 `status: [200]``maxDurationMs: 1000` 或其他非 cmd expect 字段
- **THEN** 系统 SHALL 以配置错误退出,提示 expect 包含未知字段