Commit Graph
3 Commits
Author SHA1 Message Date
chick 3473816167 feat: 独立成仓库,自己拥有契约文件
agent 从 simadmin-relay 拆出来,作为公开仓库:安装命令要由节点执行,而节点没有凭据,所以
二进制必须放在匿名可读的地方,而 relay 源码与 IPA 继续私有。

拆出来之后有一处必须改,不是搬文件:`contracts/agent-policy.json` 原先由 relay 仓库拥有、
agent 侧是 vendored 副本(Makefile 从 `../contracts/` 拷、policy_test.go 断言两份相等)。
现在反过来——**agent 拥有策略**,因为 agent 是执行它的那一方,让它去拷贝一份住在别处的文件
本来就是别扭的。relay 保留 vendored 副本(它的限额从同一组数字推导),而两侧的一致性不再
靠构建期比较(跨仓库的构建期比较谁也做不了),改由运行时保证:agent 在握手时上报策略摘要,
relay 拿自己那份比对,在 `/v1/status` 里逐节点给出 `policyMatches`。这比原来的测试更强,
因为它比的是**实际部署的那两份**,而不是两个 checkout 里的文件。

`contracts/test-vectors.json` 同理:Go 实现生成它(`make vectors`),relay 的 Node 参考实现
与 app 的 Swift 测试从 vendored 副本重算。实测重新生成的结果与 relay 那份逐字节相同。

systemd 单元的 `Documentation=` 指向本仓库。`VERSION` 提到 1.0.0。

20 个提交的历史完整保留(filter-branch 按子目录抽取)。
2026-09-17 23:24:57 +08:00
chick 274e25961a fix(agent): 手机已经放弃的请求不再执行
中继答 504 并说"可能已经执行了,重试前请先确认"——这句话诚实的前提是它保持为真。
批次是串行处理的,所以满邮箱里第八个信封可以在它被签名之后 8 个上游超时才轮到;
那时手机早已被告知失败、用户可能已经重试。再执行它,就把一次诚实的"未知"变成了
一条重复发出的短信。

现在 agent 在动任何东西之前先比对自己的截止时间(策略里的 requestTtlSeconds),
超龄一律以 expired 拒绝并落审计。判定放在新鲜度检查之后、策略判定之前:它比签名
更便宜,而且一个过期请求无论路径是否在白名单里都不该执行。

为了让这条规则**可达**,策略新增一条断言:TTL 不得大于时钟偏移窗口。否则新鲜度
检查会先触发,这条规则永远不会被执行——而"永不触发的规则"是出事时才会被发现坏了
的那种东西。

单个上游调用的超时也移进了策略(agentUpstreamTimeoutSeconds)。"中继期限必须长于
一次上游调用"这个比较,与二进制里的常量是比不了的;现在两侧从同一个文件读,策略
加载时就能拒绝一组自相矛盾的数值。原来那个 20s 常量保留为默认值的来源,不再硬编码。

测试两项:一个请求在期限内被转发、一个超龄请求被拒且**没有被转发**(计数按路径,
否则首次转发前的 /api/auth/status 探测会让断言以错误的理由通过);另一项断言策略
本身满足上述两个关系。变异验证:关掉判定,第一项失败。

Go 全包、Node 119 项、Swift 101 项通过。
2026-09-17 07:12:44 +08:00
chick 54d9696a4d baseline: P1 契约、agent 核心与中继投递(既有工作首次入库) 2026-09-16 08:41:13 +08:00