From e3cb1c5bc543a8936a92a2bf17ce2a3575f7c8fb Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Mon, 10 Aug 2026 23:58:03 +0800 Subject: [PATCH] docs(tasks): define T-016 audit relay --- docs/tasks/T-016.md | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 docs/tasks/T-016.md diff --git a/docs/tasks/T-016.md b/docs/tasks/T-016.md new file mode 100644 index 0000000..7113a6c --- /dev/null +++ b/docs/tasks/T-016.md @@ -0,0 +1,96 @@ +--- +id: T-016 +title: 冻结并实现 Sense Outbox 到 Bell 全局审计幂等 relay +phase: 3 +deps: [T-015] +status: TODO +created: 2026-08-10 +issue: null +context_ref: null +claim_branch: null +work_branch: null +write_paths: + - docs/tasks/T-016.md + - docs/contracts/README.md + - docs/contracts/sense-audit-relay-v1.openapi.json + - Sense/cmd/sense-api/main.go + - Sense/internal/config/config.go + - Sense/internal/config/config_test.go + - Sense/internal/auditrelay/ + - Sense/internal/store/audit_relay_postgres.go + - Sense/internal/store/audit_relay_postgres_test.go + - Sense/README.md + - Bell/cmd/bell-api/ + - Bell/internal/audit/ + - Bell/internal/store/audit_postgres.go + - Bell/internal/store/audit_postgres_test.go + - Bell/README.md + - deploy/postgres/014_audit_relay.sql + - deploy/postgres/015_privileges_audit_relay.sql + - deploy/postgres/tests/assertions.sql + - deploy/postgres/README.md + - scripts/test_postgres.ps1 + - tests/test_sense_audit_relay_contract.py + - tests/test_postgres_contract.py + - docs/00-ai-start-here.md + - docs/03-tech-stack.md + - docs/04-architecture.md + - docs/06-tasks.md + - docs/api.md + - docs/current-state.md +--- + +## 问题 / 背景 + +T-010 已保证 Sense 设备创建、配置和期望态变更与脱敏 `sense.device_operation_outbox` 同事务,但 Outbox 仍不会离开 Sense;Bell 因而没有完整的跨系统全局审计事实。直接让 Sense 写 `bell` schema 会破坏三系统所有权,简单“POST 后标记成功”又无法处理崩溃重试、重复投递、多实例竞争、消息篡改或重放攻击。 + +T-015 已提供 Bell 的独立运行角色和不可变事实模式。本任务只冻结并实现设备操作审计 relay,不顺带定义 Brain 事件 transport、业务规则、Alert 或公共管理 API。 + +## 关联需求与交互(如适用) + +- 用户故事:为 US-009、US-010 的全局审计追溯提供后端事实基础。 +- 交互清单:IX-020 的审计归属后端基础;本任务不实现 `/audit` UI、筛选或深链页面。 +- 相关页面 / 路由:公共 UI 不适用;新增仅内部使用的 `/internal/v1/audit-events:batch`。 + +## 方案 + +1. 冻结 `sense-audit-relay-v1.openapi.json`:Sense 通过 HTTP POST 批量发送 1~100 个 v1/v2 设备审计事实,Bell 返回与输入逐项对应的 `accepted | duplicate | rejected`;完整批次响应可按签名 nonce 幂等重放。 +2. 请求使用 key ID、Unix 秒时间戳、随机 nonce 与 HMAC-SHA256。canonical string 固定为 `METHOD + path + timestamp + nonce + SHA256(body)` 的换行拼接;允许时钟偏差 5 分钟,nonce 收据保留 10 分钟。相同 key/nonce/请求摘要返回原响应,不同摘要返回 `409 replay_conflict`。密钥只从仓库外绝对路径文件读取,至少 32 个随机字节,不进数据库、日志或 Issue。 +3. 非回环 transport 必须使用 HTTPS;回环 HTTP 只用于同机私有部署和测试,不提供跳过远端 TLS 的 flag。单次请求体最大 1 MiB、超时 10 秒,Bell 不回显原始 body、签名或敏感字段。 +4. PostgreSQL v6 为 Sense Outbox 增加数据库时钟 lease、fencing token、last error 和 dead-letter 状态。最多 100 行用 `FOR UPDATE SKIP LOCKED` 领取;过期 worker 不能确认。`accepted/duplicate` 标记 delivered,逐项永久拒绝进入 dead letter,网络/5xx/整批认证失败按指数退避重试且不删除事实。 +5. Bell 新增不可变 `bell.audit_events` 和可过期 `bell.audit_relay_receipts`。全局审计用 `(source_system,event_id)` 唯一;相同摘要为 duplicate,不同摘要逐项 `id_conflict`。审计事实没有 UPDATE/DELETE/TRUNCATE 权限并复用不可变 trigger;收据允许 Bell runtime 在限定表内维护过期记录。 +6. 建立最小 `cmd/bell-api`,默认仅回环监听,暴露 health/ready 与内部 relay endpoint;数据库、监听地址、TLS 和 key 文件均来自私有环境。Sense relay 默认关闭,仅在 PostgreSQL v6、合法 Bell URL 和外部 key 文件齐备时启动后台 worker。 +7. 单元测试覆盖签名向量、时间窗/nonce、body 限制、逐项确认、重复/冲突、配置失败关闭、退避和崩溃重领;隔离 PostgreSQL 17.10 测试覆盖 migration 重放、两端 repository、fencing、权限和安全清理。 + +## 不可变约束 + +- 阈值 / 数值边界:每批 1~100 项;body ≤1 MiB;HTTP deadline 10 秒;lease 30 秒;签名时钟偏差 ≤300 秒;nonce 收据 TTL 600 秒;退避从 1 秒指数增长并封顶 300 秒。16 不是审计批量或队列上限。 +- 判定式 / 状态转换:只有 `accepted`/`duplicate` 可设置 `delivered_at`;`rejected` 必须带稳定错误码并 dead-letter;批次级网络/5xx/认证/响应缺项不得误标成功。所有完成/失败写入必须匹配 worker + fencing token + 未过期数据库 lease。 +- 安全边界:非回环只允许 HTTPS;HMAC 使用至少 32 字节外部 secret 和 constant-time compare;时间戳、nonce、key ID、签名格式失败统一安全拒绝。Sense 不获得 Bell schema 权限,Bell 不读取 Sense Outbox;日志、响应、测试和指标不包含 secret、Authorization、原始 DSN、完整 payload 或租户/设备标签。 +- 既有契约:本地事实继续符合 `sense-device-audit-v1/v2`,不原地修改两份 schema;relay v1 只增加传输 envelope/确认语义。Bell 全局审计是追加事实,不能改写 Sense 原事件或设备状态。 + +## 验收要点 + +- 任务相关验证:`go -C Sense test ./internal/auditrelay ./internal/store ./internal/config ./cmd/sense-api`、`go -C Bell test ./internal/audit ./internal/store ./cmd/bell-api`;`python -m unittest discover -s tests -p "test_sense_audit_relay_contract.py" -v`;OpenAPI JSON 可解析且签名/状态/阈值与实现一致。 +- 完整门禁:因命中 Sense/Bell Go、PostgreSQL schema/权限和内部 HTTP 安全边界,运行 `./scripts/test_postgres.ps1 -PgRoot D:\pgsql17`、`./init.ps1`、三条 Python 治理命令及 `git diff --check`。临时 PostgreSQL 必须重放 `001`~`015` 两次,现有 5432 listener 不变。 +- 人工 / 设备验收:不适用;回环 `httptest` 和隔离 PostgreSQL 足以验收协议与持久化。跨主机证书、客户网络、防火墙和密钥轮换演练留给部署任务,不能据此宣称生产网络已验收。 +- 构建产物:`go -C Sense build ./...` 与 `go -C Bell build ./...`;Bell 最小 receiver 可由 `go -C Bell build ./cmd/bell-api` 构建,未配置 DSN/key 时必须拒绝启动。 + +## 边界(不改什么) + +- 不实现 Brain→Bell 事件 transport、规则引擎、Alert/ack/升级、Bell 公共审计查询 API、Web/H5、JWT/OIDC、消息总线或客户网络部署。 +- 不删除本地 delivered/dead-letter Outbox 行,不擅自冻结法务审计留存期;本版本只自动清理 10 分钟后 relay nonce 收据,全局审计事实不自动删除。 +- 不提交 key 文件、DSN、客户标识、真实 payload 或私有实例配置;不为测试修改现有 PostgreSQL data 目录或 5432 服务。 + +## 协作约束 + +- 责任 Agent:codex +- 唯一写入者:codex +- 委派:不启用。 +- Gitea:Issue、`context_ref`、claim 与工作分支在双向映射及 dispatcher 分配后回填。 + +任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 `write_paths`。 + +## 执行记录 + +- 2026-08-10:在 T-015 合并并关闭后拆出本任务;实现尚未开始。