1d85329a6a
Build and Test Quality Gate / Contract Web typecheck and build (pull_request) Successful in 9m12s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (pull_request) Failing after 4m53s
Build and Test Quality Gate / Python tests and Contract API migration (pull_request) Failing after 24m55s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 8m42s
194 lines
13 KiB
Markdown
194 lines
13 KiB
Markdown
# P1-04.8 企业日历 OAuth、双密钥灰度、反馈质量、死信告警与增量关系图交付报告
|
||
|
||
日期:2026-08-24
|
||
状态:已实现、已迁移、已完成 Chrome 登录态 UAT;自动化与生产构建验证通过
|
||
|
||
## 1. 阶段结论
|
||
|
||
P1-04.8 已完成五项能力:
|
||
|
||
1. Google Calendar、Microsoft 365 日历的服务端 OAuth 授权码 + PKCE、加密令牌、定时同步和增量游标;
|
||
2. Webhook 当前/上一版本签名密钥的限时并行灰度、握手验证和显式收口;
|
||
3. 根因反馈的租户级质量快照和 issue_code 级质量分解;
|
||
4. 影响分析与外部派发死信的滚动窗口、阈值、冷却和告警证据;
|
||
5. 关系社区的全量/自动/增量物化、受影响社区重算和未变化成员复用。
|
||
|
||
本阶段把 P1-04.7 的人工同步、单密钥轮换、反馈计数和全量图物化推进到可持续运营状态。系统仍不静默覆盖合同正文或规则正文;OAuth 状态、同步游标、密钥灰度、质量评估、告警触发和图快照均形成独立证据。
|
||
|
||
## 2. 产品与业务流程
|
||
|
||
### 2.1 企业日历 OAuth 与定时增量同步
|
||
|
||
管理员可创建 `google_calendar` 或 `microsoft_graph` 日历源,填写日历 ID(主日历可填写 `primary`),选择手动或定时同步、15~1440 分钟间隔及是否保存增量游标。
|
||
|
||
OAuth 流程为:
|
||
|
||
1. 管理员点击连接;服务端生成一次性 state、PKCE verifier/challenge,state 只保存 SHA-256 摘要,verifier 加密保存并在 10 分钟后失效;
|
||
2. 浏览器跳转到固定的 Google 或 Microsoft 官方授权端点;
|
||
3. 提供方回调管理页后,前端将 code/state 交给服务端;
|
||
4. 服务端校验一次性 state、交换令牌并加密保存 access token、refresh token 和后续增量游标;
|
||
5. 治理 Worker 使用数据库租约认领到期日历源,刷新令牌并执行同步;成功后推进 next_sync_at,失败时记录原因、连续失败次数并退避。
|
||
|
||
Google 使用 `syncToken`;遇到提供方返回 410 时自动清除失效游标并重建全量快照。Microsoft 使用 calendarView delta 返回的 `@odata.deltaLink`。外部请求只允许代码内固定的官方主机,不接受用户提供任意 OAuth/token/API 端点。
|
||
|
||
本地 UAT 环境没有真实企业 OAuth 客户端凭据,因此 UI 和配置失败边界已验证,但没有伪造外部授权成功。生产接入必须提供客户端 ID/secret、HTTPS 回调和独立令牌加密密钥。
|
||
|
||
### 2.2 通知双密钥灰度
|
||
|
||
Webhook 轮换现在支持 1~168 小时宽限期:
|
||
|
||
- 当前密钥立即升级为新版本;
|
||
- 上一版本及有效期被保留,宽限期内请求同时携带当前与上一版本的 HMAC-SHA256 签名;
|
||
- 已启用通道可选择在宽限期继续工作,不因轮换造成通知中断;
|
||
- 新密钥握手通过后状态变为 `ready_to_finalize`,管理员显式收口后删除上一版本引用;
|
||
- 宽限期过期后治理 Worker 自动清理上一版本;
|
||
- 新密钥仍只在轮换响应中显示一次,数据库只保存版本而不保存可直接使用的明文派生密钥。
|
||
|
||
接收方可以通过 `X-Yuqei-Key-Version`、`X-Yuqei-Signature-SHA256` 验证当前密钥;灰度期间额外读取 `X-Yuqei-Previous-Key-Version`、`X-Yuqei-Signature-Previous-SHA256`。
|
||
|
||
### 2.3 根因反馈质量评估
|
||
|
||
每次根因反馈新增 1~5 分复核置信度。管理员可生成不可变质量快照,指标包括:
|
||
|
||
- 反馈数、独立评审人数和评审人多样性;
|
||
- 有帮助率、纠正率、评论覆盖率、建议采纳率;
|
||
- 平均复核置信度、分类一致率和综合质量分;
|
||
- 每个 issue_code 的样本、评审人数、帮助率、纠正率、一致率和质量分。
|
||
|
||
质量分不等同于“有帮助率”,避免单一正向点击掩盖样本过少、缺少评论、低置信度或评审人单一等问题。快照保留生成者和生成时间,可用于后续比较而不覆盖历史。
|
||
|
||
### 2.4 死信告警策略
|
||
|
||
每个租户可独立配置是否启用、影响任务阈值、外部派发阈值、滚动窗口和冷却时间。治理 Worker 汇总窗口内死信,任一维度达到阈值且不在冷却期时:
|
||
|
||
1. 生成 `playbook_dead_letter_threshold` 治理通知;
|
||
2. 记录影响/派发死信数量、触发原因、通知 ID、生成者和时间;
|
||
3. 更新 last_alert_at;
|
||
4. 冷却期内不重复告警,避免通知风暴。
|
||
|
||
告警策略默认停用,不会因升级自动向企业外部通道发消息。
|
||
|
||
### 2.5 万级关系图增量物化
|
||
|
||
关系社区物化接口增加 `auto/full/incremental` 和 `force`。自动模式在图摘要未变化时直接返回最新快照;图变化时,以最近快照为基线识别变更规则,扩展到受影响的旧社区和当前连通分量,只重算受影响区域,并复用未变化社区成员。
|
||
|
||
快照记录 build_mode、base_snapshot_id、变化节点/边、复用节点和耗时。成员写入使用批量插入,避免万级节点逐行提交。查询接口公开快照构建模式和变化节点数;前端继续提供物化社区筛选、WebGL 大图及 SVG 降级。
|
||
|
||
## 3. 技术实现
|
||
|
||
### 3.1 数据与迁移
|
||
|
||
Alembic 版本:`20260823_0059`。
|
||
|
||
新增表:
|
||
|
||
- `playbook_calendar_remote_events`:外部日历事件的租户/来源级增量物化;
|
||
- `playbook_calendar_oauth_states`:短期一次性 OAuth state 与加密 PKCE verifier;
|
||
- `playbook_root_cause_feedback_quality_snapshots`:不可变质量快照;
|
||
- `playbook_dead_letter_alert_policies`:租户告警策略及版本;
|
||
- `playbook_dead_letter_alert_events`:阈值触发证据。
|
||
|
||
扩展字段:
|
||
|
||
- `playbook_calendar_sources`:提供方日历 ID、调度、OAuth 加密令牌、加密游标、next_sync_at、失败计数和租约;
|
||
- `playbook_calendar_sync_runs`:full/incremental、游标推进、定时触发和 Worker 名称;
|
||
- `playbook_notification_channels`:上一密钥版本、有效期和轮换状态;
|
||
- `playbook_conflict_root_cause_feedback`:复核置信度;
|
||
- `playbook_relationship_community_snapshots`:增量基线、变化/复用计数和耗时。
|
||
|
||
运行时 schema-check 已覆盖新增表和关键字段。迁移已在 PostgreSQL 正向升级,并在 SQLite 完成 head 升级及跨版本降级测试。0059 downgrade 会先删除本版本创建的列索引,再删除列,兼容 SQLite 对残留索引的严格校验。
|
||
|
||
### 3.2 接口与前端
|
||
|
||
新增或扩展的主要接口:
|
||
|
||
- `POST /governance/calendar-sources/{source_id}/oauth/start`;
|
||
- `POST /governance/calendar-oauth/complete`;
|
||
- `POST /governance/calendar-sources/{source_id}/oauth/revoke`;
|
||
- `POST /governance/calendar-sources/{source_id}/sync` 返回增量与调度证据;
|
||
- `POST /governance/notification-channels/{channel_id}/rotate-secret` 接收灰度参数;
|
||
- `POST /governance/notification-channels/{channel_id}/finalize-secret-rotation`;
|
||
- `GET/PUT /governance/dead-letter-alert-policy`;
|
||
- `GET /governance/dead-letter-alert-events`;
|
||
- `GET /governance/root-cause-feedback-quality`;
|
||
- `POST /governance/root-cause-feedback-quality/evaluate`;
|
||
- `POST /relationship-graph/materialize` 接收物化模式和 force。
|
||
|
||
Contract Web 增加对应的同源代理、OAuth 回调处理、日历调度表单、连接状态、双密钥宽限状态、质量面板、告警策略和增量快照提示。OpenAPI 更新为 103 个路径、156 个 schema,所有 schema 引用可解析。
|
||
|
||
### 3.3 配置与安全边界
|
||
|
||
新增运行时变量位于 Contract API `.env.example`:
|
||
|
||
- `CONTRACT_API_PLAYBOOK_CALENDAR_OAUTH_TOKEN_ENCRYPTION_SECRET` 或 `_FILE`,只能二选一;
|
||
- `CONTRACT_API_PLAYBOOK_CALENDAR_OAUTH_REDIRECT_URI`;
|
||
- Google/Microsoft 客户端 ID 与 secret;
|
||
- Microsoft tenant,默认 `organizations`。
|
||
|
||
配置检查会拒绝只配置 ID 或只配置 secret、同时配置两种加密密钥来源、提供方存在但没有加密密钥,以及 staging/production 使用非 HTTPS 回调。没有提供方配置时返回 warning,并让 OAuth 发起接口以 409 明确失败,不会降级为明文保存或虚假连接。
|
||
|
||
## 4. Chrome 超级管理员 UAT
|
||
|
||
工作空间:Playbook 隔离 UAT
|
||
账号:`uat.legal.20260823@example.test`
|
||
页面:`http://127.0.0.1:3000/admin/playbook?tab=operations`
|
||
|
||
### 4.1 可见流程证据
|
||
|
||
- 页面标题显示 `Enterprise governance · P1-04.8`;
|
||
- Google Calendar 表单可切换到 `primary`、定时增量、60 分钟及“保存加密游标并执行增量同步”;
|
||
- 生成根因反馈质量快照成功:1 条反馈、1 名评审人、评论覆盖 100%、分类一致 100%、综合质量 82 分;
|
||
- 保存死信告警策略成功;UAT 保持策略停用,未制造死信或触发外部通知;
|
||
- 生成关系社区快照返回 `playbook-community-cc4774beb595`。当前规则图未变化,因此自动模式复用既有全量快照并显示变化 0、耗时 0ms;专项测试覆盖真实增量分支;
|
||
- 关系图和治理配置在 Chrome 可见区域内无控件重叠、文本截断或不可达按钮。
|
||
|
||
### 4.2 未伪造的外部边界
|
||
|
||
本地环境没有企业 Google/Microsoft OAuth 凭据,也没有真实 Webhook 接收方。本次没有创建虚假连接、没有对外发送邮件/Webhook,也没有为了演示制造死信。OAuth code 交换、刷新、全量到增量游标推进、定时 Worker 认领、双密钥双签名、握手后收口、阈值告警和增量社区变化由隔离自动化覆盖;上线前仍需在预发布环境完成真实提供方与接收端联调。
|
||
|
||
## 5. 验证结果
|
||
|
||
- 当前后端收集 349 项:345 项通过、4 项按环境条件跳过;其中第二轮全量回归 348 项为 344 项通过、4 项跳过,随后新增的双签名网络层测试 1/1 通过;
|
||
- P1-04.8 Playbook operations 专项:12/12 通过;
|
||
- 迁移失败用例修复后精确复跑:3/3 通过;
|
||
- OAuth 专项额外断言 access token、refresh token 和增量 cursor 均未以原始明文持久化;
|
||
- 前端现有测试:41/41 通过;
|
||
- TypeScript:通过;
|
||
- Next.js 生产构建:通过,静态生成/收集 135 个页面;
|
||
- OpenAPI YAML:103 个路径、156 个 schema、0 个悬空 schema 引用;
|
||
- PostgreSQL Alembic:`20260823_0059 (head)`;
|
||
- Contract API `/health`:200,status=ok;
|
||
- Contract Web 3000、Contract API 8100、AI API 8101 和治理 Worker 保持运行。
|
||
|
||
## 6. 市场与架构评估
|
||
|
||
企业合同治理采购会重点询问企业日历能否自动进入 SLA、令牌与密钥是否可安全轮换、失败是否会主动告警、人工反馈是否可衡量,以及大规模规则库是否需要人工反复全量重算。本阶段直接补齐这些可采购性与可运营性门槛。
|
||
|
||
当前继续使用 PostgreSQL 事务表和治理 Worker 是合理的:
|
||
|
||
- OAuth 状态、同步证据、告警证据和图快照需要与租户治理事实一致,事务数据库优先于过早拆分;
|
||
- 数据库租约允许多 Worker 安全竞争,达到更高吞吐后可把调度迁移到专用队列而不改变 API;
|
||
- 关系社区仍是确定性连通分量,增量物化和批量写入足以支撑当前万级目标,无需现在引入图数据库;
|
||
- 反馈质量是可解释统计,不是不可审计的在线模型自训练,符合合同治理的人审边界。
|
||
|
||
## 7. 发布门槛与下一步
|
||
|
||
正式开放企业 OAuth 前必须完成:
|
||
|
||
1. 在 Google Cloud 与 Microsoft Entra 注册生产 HTTPS 回调,采用最小只读日历权限并完成管理员审批;
|
||
2. 把 OAuth 令牌加密密钥与 Webhook 主密钥分别托管到 KMS/Vault 或只读 secret file,建立轮换与恢复演练;
|
||
3. 用两个预发布租户分别完成授权、初次全量、事件增删、增量同步、游标失效回退、令牌撤销和租户隔离验证;
|
||
4. 与真实 Webhook 接收端演练旧密钥、双密钥、新密钥、握手和宽限期到期;
|
||
5. 以 10k/50k 节点和高变更率数据压测增量命中率、物化耗时、快照大小和 WebGL 交互延迟;
|
||
6. 将日历连续失败、OAuth 失效、同步租约堆积、双密钥即将过期、质量分下降和告警派发失败接入统一可观测平台。
|
||
|
||
后续可进入 P1-04.9:企业 OAuth 真实预发布接入与管理员同意治理、日历同步 SLO/回放、通知 KMS/Vault 与专用通道、反馈离线基准集、告警升级链路及 50k 图 Worker/LOD 压测。
|
||
|
||
## 8. 设计依据
|
||
|
||
- Google Calendar incremental synchronization:<https://developers.google.com/workspace/calendar/api/guides/sync>
|
||
- Google OAuth 2.0 web-server applications:<https://developers.google.com/identity/protocols/oauth2/web-server>
|
||
- Microsoft identity platform authorization-code flow:<https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow>
|
||
- Microsoft Graph calendarView delta:<https://learn.microsoft.com/en-us/graph/api/event-delta?view=graph-rest-1.0>
|
||
- Microsoft `offline_access` scope:<https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc>
|