Files
yovision/docs/tasks/T-016.md
QiuSW 4be2386421
Harness governance / validate (push) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled
feat: deliver Sense audits to Bell (T-016)
2026-08-11 00:24:32 +08:00

8.4 KiB
Raw Permalink Blame History

id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
id title phase deps status created issue context_ref claim_branch work_branch write_paths
T-016 冻结并实现 Sense Outbox 到 Bell 全局审计幂等 relay 3
T-015
DONE 2026-08-10 55 aca22f4667 claims/T-016 agent/codex/T-016
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 合并并关闭后拆出本任务;实现尚未开始。
  • 2026-08-11:冻结 sense-audit-relay-v1.openapi.json,实现 Sense 外部 key/HMAC client、30 秒数据库 lease/fencing worker、逐项结果/dead letter/1~300 秒退避,以及 PostgreSQL v6 Outbox relay repository;默认关闭且远端 URL 强制 HTTPS。
  • 2026-08-11:实现 Bell 最小 cmd/bell-api、300 秒时间窗与 constant-time HMAC 校验、600 秒 nonce 幂等收据、逐项 v1/v2 校验,以及 PostgreSQL v4 不可变 bell.audit_events;Sense/Bell 登录权限保持单向隔离,只有 Bell 可清理过期收据。
  • 2026-08-11:./init.ps1、三条 Python 治理命令、Sense/Bell test/vet/build 与 git diff --check 全部通过;Python 共 68 项测试通过。
  • 2026-08-11:./scripts/test_postgres.ps1 -PgRoot D:\pgsql17 通过;PostgreSQL 17.10 临时集群将 001~015 重放两次,Sense fencing、Bell receipt/重复/冲突/不可变性和双方权限断言通过,随机端口与临时目录已清理,现有 5432 listener 未改变。