diff --git a/docs/ios-relay-architecture.md b/docs/ios-relay-architecture.md index 8e3588c..9cfa0e4 100644 --- a/docs/ios-relay-architecture.md +++ b/docs/ios-relay-architecture.md @@ -302,6 +302,23 @@ P2/P3 可并行。P4 是唯一动到现有 iOS 数据模型的部分,风险集 > 在途 `reqID` 即可抢先应答,把它变成 orphan 并让合法应答被丢弃。修复方式是在 > `registry.resolve` 上增加 nodeID 校验(`relay/src/registry.js`)。 > +> 另有一个**端到端测试**(`test/e2e.test.js`):它编译并运行真实的 Go agent,经 TLS 接到真实 +> 中继,由模拟手机发起签名请求。它一次抓出三个"单元测试全绿、合起来坏了"的缺陷,值得逐条记录, +> 因为三个都是接缝问题: +> +> 1. `transport.Client` 把会话 token 写进了 `c.token`(bearer 字段),于是轮询拿会话 token 当 +> bearer 发,中继一律 401;症状是 agent 连上后无限重连,日志说"凭据被拒"。两个凭据现在分开。 +> 2. `main.loop` 每个周期都重新握手。中继每节点只保留一个会话,新握手顶掉旧的并丢弃其挂起的 +> 轮询,于是两次握手之间到达的请求被投进已不存在的会话、以"agent 离线"超时,而 agent 全程 +> 在线。改为仅在会话失效或传输失败时重新握手。 +> 3. `auth.registerDevices` 把"已存在"一律跳过,随后又被"本轮未声明"的回收循环删除,所以节点的 +> 第二次握手会注销自己刚注册的设备。改为本节点已持有即确认(幂等)——重连与重握手是常态。 +> +> 结论:契约与单元测试能证明两侧各自正确,证明不了两侧接得上。上线前必须跑一次端到端。 +> +> 另:agent 支持 `relayCAFile`(PEM 钉 CA,**替代**系统信任库而非关闭校验),端到端测试用自签 +> 证书 + 钉 CA 走的就是这条真实校验路径。 +> > **Swift 侧签名不是逐字节可复算的**:CryptoKit 的 Ed25519 签名是随机化的(同一密钥同一消息 > 两次签名结果不同),Go 与 Node 用的是 RFC 8032 确定性实现。因此 `RelayWireTests` 校验的是 > 更强的性质——双方各自验证对方产出的签名,以及签名输入与向量中的规范化字节完全相等——而不是