feat(expenses): secure timeline and draft events

This commit is contained in:
caoxiaozhu
2026-07-14 00:07:07 +08:00
parent 22669a9071
commit 1347366b95
14 changed files with 1044 additions and 59 deletions

View File

@@ -0,0 +1,8 @@
## 修复记录
- 22:59记录 bug 修复AI 工作台重复保存请求会创建多张申请草稿和多条事件。
- Git 提交检查:已执行 `git fetch --all --prune`,未发现 upstream 新提交;本地 ahead 4 个既有提交,分别为 `22669a90 feat(expenses): show unified expense event timeline`(真实费用事件时间线)、`a616b30c fix(expenses): unify AI application submission transaction`AI 申请提交事务)、`653eda05 feat(auth): add opaque bearer sessions`(不透明 Bearer 会话)和 `661990b2 feat(expenses): add transactional expense case events`Expense Case 事务事件基础)。
- 修改:新增 `expense_application_draft_events.py`以租户、操作人、run ID 和稳定草稿快照生成固定长度幂等键及 UUID5 聚合 ID`user_agent_application.py` 在新建前复用已完成动作,并在并发主键竞争后回滚、重查已提交事件。持久化兜底的当前时间不参与指纹,原始申请时间仍通过申请详情快照区分。
- 操作:先在容器中分别复现“带日期相同请求”和“缺日期半成品相同请求”均生成两个不同 `claim_id`,再补动作级幂等和数据库并发仲裁路径;业务单号继续使用既有随机格式,没有修改数据库结构或执行迁移。
- 验证:相同 HTTP 保存请求连续执行两次返回同一 `claim_id``claim_no`,数据库只有一张申请草稿与一条 `claim_draft_created`;同一 run 的不同快照仍分别留痕事件失败时草稿、Case、Link 和事件整体回滚。容器内受影响后端定向回归 36 项、前端时间线兼容测试 9 项及 Python `ruff --select F,I` 通过。
- 影响:网络重试、用户重复点击或客户端重放不会制造重复申请草稿;并发请求由稳定聚合主键仲裁。真实 PostgreSQL 双会话并发集成测试仍是后续可补的非阻断验证,不影响当前顺序重放与事务契约。

View File

@@ -0,0 +1,8 @@
## 修复记录
- 22:59记录 bug 修复AI 申请预览入口可保留请求体伪造的身份和管理员权限。
- Git 提交检查:已执行 `git fetch --all --prune`,未发现 upstream 新提交;本地 ahead 4 个既有提交,分别为 `22669a90 feat(expenses): show unified expense event timeline`(真实费用事件时间线)、`a616b30c fix(expenses): unify AI application submission transaction`AI 申请提交事务)、`653eda05 feat(auth): add opaque bearer sessions`(不透明 Bearer 会话)和 `661990b2 feat(expenses): add transactional expense case events`Expense Case 事务事件基础)。
- 修改:`reimbursements.py``user_id`、租户、角色、管理员标记、用户名、姓名、部门、职位、职级、员工编号和直属经理全部强制绑定到服务端当前会话,不再对请求体同名字段使用 `setdefault``test_reimbursement_endpoints.py` 增加伪造管理员与他人身份编辑退回申请的对抗用例。
- 操作:先在容器中复现修复前接口返回 200 且允许修改他人申请,再完成服务端身份覆盖;没有修改数据库结构,没有执行迁移或重启服务。
- 验证:修复后恶意请求返回 400目标申请的事由、状态和审批节点保持不变也没有新增费用事件正常保存草稿与直接提交回归通过。本轮受影响后端定向回归共 36 项、前端时间线兼容测试 9 项和 Python `ruff --select F,I` 均在容器内通过。
- 影响AI 工作台快速申请入口不能再通过伪造 `user_id``is_admin`、角色或员工编号绕过申请所有权检查,授权事实与其他受保护接口统一来自服务端会话。