test-spec.md 9.3 KB

测试 Spec — MCP 用户委托身份

status: done created: 2026-07-12

1. P0:规范与授权码

1.1 实现 HARD-GATE 基线

  • Identity 依赖树中不得出现 spring-security-oauth2-authorization-serversa-token-oauth2
  • Forge OAuth 2.1 Profile 契约测试必须覆盖 PUBLIC + PKCE、CONFIDENTIAL、resource、精确 redirect、单次 code 与未知 grant 失败关闭;
  • 后续 OAuth 行为测试必须覆盖 metadata → authorize → token → /mcp 闭环,不能以类存在或可编译代替协议证明。

  • RFC 9728 资源元数据包含 canonical resource 和 authorization server;

  • 401 包含正确 WWW-Authenticate resource metadata;

  • RFC 8414 元数据只声明真实支持的 grant、PKCE 和客户端认证方法;

  • authorization request/token request 缺少或改变 resource 时拒绝;

  • 只允许 PKCE S256,plain/空 challenge/verifier 不匹配拒绝;

  • redirect URI 必须逐字匹配,前缀、子域、端口、path、fragment 变化拒绝;

  • code 120 秒过期且只能使用一次,20 路并发兑换只有一个成功;

  • state 原样返回但不进入服务端身份、日志或授权判断。

2. P0:Token 与双身份

  • authorization_code 只生成 USER Token,actorUserId 为授权用户 A;
  • client_credentials 只生成 SERVICE Token,actorUserId 等于 serviceUserId;
  • USER/SERVICE 均保留 clientId、serviceUserId、tenantId、activeOrgId;
  • Token 至少 256 bit、TTL ≤ 15 分钟,数据库无原始 Token/code/verifier;
  • HMAC 常量时间比较;未知 keyId 仍走 dummy HMAC;
  • Token 过期、撤销、客户端禁用、密钥轮换、credentialVersion 变化立即拒绝;
  • 用户禁用/删除、租户成员失效、组织解绑、强制改密、超级管理员服务账号拒绝;
  • 用户加载发生组织回退时拒绝,不能静默使用主组织。

3. P0:MCP 与路径隔离

  • /mcp 从通用 Sa-Token 拦截器排除后,无 OAuth Token 仍由专用 Filter 返回 401;
  • 长期 fcp_... Secret 不能直接调用 /mcp
  • fdu_... Token 只能从 Authorization Bearer 读取,query/cookie/arguments 不接受;
  • MCP Token 请求普通 /system/**/ai/** 管理接口被拒绝;
  • 错误 audience、scope、resource 返回 401/403,内部异常不泄露;
  • 每个 Streamable HTTP POST/GET 都重新认证,Mcp-Session-Id 不能替代 Token;
  • Origin 存在时必须匹配 allowlist;恶意 Origin 拒绝;
  • initialize → initialized → tools/list → tools/call 仍使用协议 2025-06-18
  • 不出现旧 /sse、message endpoint、SSE transport Bean、STATELESS 或 stdio。

4. P0:Forge 执行上下文

  • USER Token 建立 A 的 LoginUser/tenant/activeOrg/scopes;
  • SERVICE Token 建立绑定服务账号上下文;
  • ORM insert 自动填充 create_by/update_by=Acreate_dept=activeOrgId
  • ORM update 自动填充 update_by=A
  • OperationLog 的 userId 为 A,不是服务账号或 null;
  • 正常、异常、401、403、SDK 抛错和异步路径 finally 后无身份/Tenant/MDC 泄漏;
  • 嵌套上下文退出后恢复外层用户;线程池连续执行 A/B 不串身份;
  • 普通 Forge Sa-Token 登录的 SessionHelper 行为保持不变。

5. P1:数据与接口

  • V1.0.22 唯一,表/实体/XML/逻辑删除一致;
  • redirect URI 和 access token 查询均显式 tenant 条件;仅 token keyId 认证定位允许受控跨租户查找;
  • PUBLIC 客户端禁止 client_credentials;CONFIDENTIAL 客户端错误 Secret 拒绝;
  • OAuth 未启用、无 redirect、无 scope 或客户端无 grant 时拒绝;
  • revoke 幂等,普通行删除逻辑删除;
  • 管理 API 不返回 tokenHash、原始 Token、code 或 verifier。

6. 回归矩阵

范围 命令 预期
Core/ORM/Log mvn -Penable-tests -pl forge-starter-log -am test 显式/普通身份上下文全绿
Identity mvn -Penable-tests -pl .../forge-plugin-capability-identity -am test OAuth、Token、上下文 P0 全绿
MCP mvn -Penable-tests -pl .../forge-plugin-mcp -am test Streamable HTTP 13+ tests 全绿
Control Plane mvn -Penable-tests -pl .../forge-plugin-capability-control-plane -am test 20+ tests 全绿
AI mvn -Penable-tests -pl .../forge-plugin-ai test 84 tests 全绿
Admin mvn -pl forge-admin-server -am package -DskipTests 全部预期 reactor modules SUCCESS
Frontend nvm use v20.19.0 && pnpm build production build PASS

7. 跳过条件

  • 没有受控 MySQL/Redis 时,只能跳过真实 Flyway、Redis code 原子兑换和完整服务联调;必须记录具体原因;
  • 单元测试和 MockMvc 不能冒充真实 Redis 原子性或真实数据库迁移;
  • 本变更不调用真实模型,不产生模型 Token 费用;
  • 本变更不测试业务写副作用和 Flowable 办理,因为明确不在范围内。

8. Apply 增量验证结果(2026-07-12)

范围 结果 证据摘要
Identity PASS 18/18;Token codec/service/controller、PKCE/redirect/resource、Redis HMAC+Lua、MCP resolver、上下文、双身份审计、依赖隔离
Capability PASS 13/13;Observer 接入后注册、授权、Schema 和调用回归
MCP PASS 13/13;协议版本 2025-06-18、单 Streamable HTTP、裸请求 401 和 transport guard
Control Plane PASS 20/20;客户端、grant、审计、Schema 回归
Admin PASS 39/39 reactor package -DskipTests;单模块启用测试生命周期通过,旧 fcp_ Resolver 测试已清除
Dependency PASS Identity dependency tree、全部 POM、Admin JAR 均无 SAS/Sa-Token OAuth2
SQL/XML PASS Mapper XML xmllint;V1.0.22 唯一;无 Flyway placeholder、tenant 0、物理 DELETE
Frontend PASS Node 20.19.0 目标 ESLint 无输出;Vite production build PASS

条件跳过:未对用户现有数据库执行 V1.0.22;未用真实 Redis 做 20 路并发兑换;未启动 Admin 做真实浏览器授权与完整 metadata → authorize → token → /mcp initialize E2E。以上不计为 PASS,留待 Review/受控环境验收。

9. Review 增量验证(2026-07-12)

本轮未修改实现,只复跑高风险模块和静态边界:

检查 结果
Identity tests PASS,18/18
MCP tests PASS,13/13
Identity dependency tree PASS,无 SAS、无 Sa-Token OAuth2
git diff --check、Mapper xmllint、V1.0.22 placeholder/tenant 0/物理 DELETE PASS
MCP 集成测试身份来源核查 FAIL HARD-GATE:使用测试 Resolver,不是 fdu_/Identity 聚合链
client grant + 用户权限交集核查 FAIL HARD-GATE:运行时仅检查 Token scope
PUBLIC/USER revoke FAIL:当前端点只接受 CONFIDENTIAL client secret
当前组织前置校验 FAIL:授权阶段未比较 user/client activeOrgId

Review 结论:已有单元测试继续通过,但不能覆盖或推翻 R1–R5;Fix 后必须为每项增加 Red/Green 证据。

10. Fix 增量验证(2026-07-12)

Review 项 Red/Green 证据 结果
R1 聚合链 McpDelegatedIdentityIntegrationTest:合法 fdu、完整 Sa-Token 排除链、initialize/list/call、真实审计 Observer、Session/Tenant/MDC 清理 PASS,3/3
R2 权限交集 ForgeCapabilityAuthorizationPolicyTest + AutoConfiguration Test:scope、grant、permission、tenant/org、ping 显式例外、Bean 替换 PASS
R3 用户撤销 Token Service/Controller:当前 A、tenant、client、USER 类型、幂等、跨用户/跨客户端拒绝 PASS
R4 组织前置 Authorization Controller:预览与确认均在 validator/code store 前失败 PASS
R5 错误分类 OAuth DB 故障为 503;MCP 401/Origin 403/基础设施 503;安全日志不含凭据 PASS
R6 加固 长度上限、issuer query、SYNC-only、LoginUser 快照、last_used_at 节流、30 天留存清理 PASS

10.1 回归结果

范围 结果
Identity PASS,34 tests(最终复跑后以 execution-log 为准)
Capability PASS,13 tests
MCP PASS,14 tests
Control Plane PASS,20 tests
AI PASS,84 tests;全部为 mock/stub 单测,未调用真实模型
Admin PASS,39/39 reactor package -DskipTests
Frontend PASS,目标 ESLint 无输出;Node 20.19.0 production build 成功
Dependency PASS,无 SAS、无 Sa-Token OAuth2
XML/Flyway PASS;Mapper XML 可解析,无 placeholder/tenant 0;唯一物理 DELETE 是带代码注释和 Spec 回滚说明的短期 Token 超期留存任务

10.2 继续条件跳过

  • 未在用户真实 MySQL 执行 V1.0.22;
  • 未使用真实 Redis 做 20 路 code 并发兑换;
  • 未启动真实 Admin/浏览器执行 metadata → authorize → code → token 全闭环;
  • 上述项目不记为 PASS,也不影响本轮 R1–R6 代码修复结论;复审通过前不进入 secure actions。

11. 归档验收(2026-07-12)

  • Identity:PASS,34/34;
  • MCP:PASS,14/14,协议版本 2025-06-18,单 /mcp Streamable HTTP;
  • Admin:PASS,JDK 17 clean install 39/39;
  • 依赖隔离:PASS,无 Spring Authorization Server、无 Sa-Token OAuth2;
  • Mapper 资源唯一性:PASS,AiCapabilityClientMapper.xml 只存在于 control-plane;
  • 条件跳过保持不变:真实 MySQL、真实 Redis 并发、真实浏览器 OAuth E2E 未执行;
  • 结论:归档验收通过,允许进入 forge-ai-hub-secure-actions Proposal/Apply。