26 · 工程开发规格 · 质量 / 安全

测试计划 + 编码规范 + 安全合规清单

把质量与安全写成可执行的门禁:测什么、覆盖到多少、代码怎么写、提交怎么管、上线前过哪些安全与红线检查。CI 强制执行。

🧪 单测 + 集成(Miniflare) 📏 编码/提交规范 🔐 安全 + 红线门禁

1测试矩阵

层级工具测什么
单元(packages/core)Vitestrouter 候选/回退顺序、cacheKey 规范化、billing 成本/倍率、provider adapter 的请求转换与 usage 解析、Zod schema 边界
集成(workers/gateway)Vitest + @cloudflare/vitest-pool-workers(Miniflare)端到端:鉴权→限流→缓存→路由→记账;用 mock 上游验证回退、429、配额、流式
契约Vitest 快照OpenAI 兼容响应结构、错误体结构、响应头
限流并发Vitest(DO 模拟)令牌桶补充、突发、并发上限
冒烟(部署后)脚本 curlpreview/prod 的 /healthz、一次最小 chat 调用

关键用例对齐 20 验收 AC-1~AC-5:直通+记账、回退、缓存命中、配额/限流、红线护栏拒绝。

2覆盖目标

  • packages/core(纯逻辑):行/分支覆盖 ≥ 85%(路由/缓存/计费是钱与可用性的核心,必须高覆盖)。
  • workers/gateway:关键路径集成测试必过;整体 ≥ 70%。
  • 每个 provider adapter:至少 1 个成功 + 1 个错误归一用例。
  • CI 跑覆盖率,低于阈值则失败。

3编码规范

  • TypeScript strict;禁用隐式 any;公共函数显式返回类型。
  • 校验在边界:所有外部输入(API 请求、配置)入口处 Zod 解析;core 内部信任已校验类型。
  • 纯逻辑下沉 core:workers 层只做 IO/绑定胶水;core 不依赖 CF 运行时(便于单测)。
  • 错误统一:用 errors.ts 的错误类型 + 错误码,禁止裸 throw 字符串。
  • 命名:文件 kebab-case;类型 PascalCase;常量 UPPER_SNAKE;逻辑模型/渠道 id 用前缀(ch_/m_/key_)。
  • 日志:结构化(JSON),禁止打印 secret / 完整 prompt(可打长度/哈希)。
  • ESLint + Prettier:沿用根仓库风格;CI pnpm lint 必过。

4提交 / PR 规范

  • 分支feat/*fix/*chore/*;主干 main 受保护,禁直接推。
  • 提交信息:Conventional Commits(feat(router): add weighted fallback)。
  • PR:必须过 CI(lint/typecheck/test/redline);至少 1 review;关联 27 的 issue。
  • PR 模板:变更说明、影响的规格文档(22/23)、是否需迁移、测试说明。
  • 小步提交:对齐 24 的 MVP 分步,一步一 PR。

5安全清单(上线前逐项过)

🔑密钥
  • 上游 key / ADMIN_TOKEN / pepper 不入仓、不下发、不打日志
  • 内部 key 仅存哈希(加 pepper)+ 前缀
  • 支持吊销与轮换;异常用量告警
🛡️接入
  • 数据面与管理端分离鉴权
  • 管理写操作记 config_audit
  • 全链路 TLS;CORS 按需收紧
🚦滥用防护
  • 每 key 令牌桶 + 并发上限
  • 配额日/月双周期
  • 成本异常熔断(可临时禁用渠道/降配额)
🔏数据
  • 不持久化用户 prompt 正文(仅记 usage/元数据),除非产品明确需要并合规
  • 明示哪些渠道会用于训练(见 01/08)

6红线门禁(CI 强制 redline:check

⛔ 构建期红线

脚本扫描代码与配置,命中即 CI 失败:

  • provider 白名单channels.provider 与 adapter 仅允许 PROVIDER_ALLOWLIST(OpenRouter/DeepSeek/Groq/Workers AI/OpenAI/Anthropic/Google/Mistral/Together/DeepInfra)。出现逆向/养号类标识(如已知逆向库名、临时邮箱/注册自动化关键字)即失败。
  • 无养号/多账号自动化:仓库不得含批量注册、接码、住宅代理调度代码。
  • secrets 扫描:阻止把 key/token 提交进仓(git-secrets / 简单正则)。

这把 02/08 的红线从"文档承诺"变成"代码层强制"——合规不依赖人记得,而是 CI 拦住。