fix(organization): 修复创建机构审计缺操作人;补全机构修复的验证并部署 Docker 测试环境
一、机构审计归属缺陷(本轮活栈验收中新发现) - 现象:audit_logs 中 CREATE_ORGANIZATION 的 operator_id 7/7 为 NULL, 而 DISABLE/ENABLE_ORGANIZATION 均正确记录操作人。审计不可归属 = 无效审计。 - 根因:OrganizationController.create 持有 @AuthenticationPrincipal OperatorPrincipal, 却只把 params 传给 Service,未透传 principal.id() → saveAuditLog(null, ...)。 - 修复:createOrganization(params, operatorId) 签名透传;新增测试断言 createOrganizationRecordsOperatorInAuditLog 长期守卫。 - 复验:新写入的 7 条 CREATE 审计全部带 operator_id,旧 14 条仍为 NULL(前后对照清晰)。 二、补全 rc.22 的验证缺口(此前记为「已修复待验证」) - 全量回归 757 / 0 / 0 / 3,BUILD SUCCESS,108 个测试类,6:44(基线 741 + 新增 16)。 - 负向注入:ORG_STATUS_ACTIVE 改回 "normal" → 16 例变 3 失败 + 7 错误 (守卫三条断言各自命中 + 服务侧 7 例被 H2 CHK_ORG_STATUS 拦下)。 注入采用「仓库只读挂载 + 容器内副本改写」,工作区哈希前后一致,源码零污染。 - 活栈实测(Docker 全栈):创建/停用/启用均 2xx、非法输入 400、不存在 404、全程零 5xx(15/15)。 - 对已部署栈 pytest tests/e2e → 65 passed。 三、Docker 测试环境部署与工具链固化 - 测试镜像 danyang-match-backend-test 与命名卷 danyang-m2-cache 因 Docker Desktop 重装丢失, 构建定义此前是临时产物 → 落盘为仓库资产 infrastructure/test-toolchain/Dockerfile。 - 本地栈统一使用 docker compose -p danyang(原项目名 infra 与另一项目撞名, 其 --remove-orphans 会误删本项目容器;已确认邻项目数据无丢失,见 known-risks KR-09)。 四、UI 门禁脆弱性修复 - ui-document-baseline-contracts.mjs 解析 docker-compose.staging.yml 时报假红 (「守卫自身失效」);真因是该文件为 CRLF 而守卫正则要求 \n 紧随 container_name 之后 (prod.yml 是 LF 所以此前能过)。解析改为行尾无关,真实断言未削弱。门禁 18/18。 五、文档 - STATUS.md 新增 rc.23 并将 rc.22 由「待验证」订正为「已验证关闭」。 - 实施计划附 B.1、PROGRESS-ASSESSMENT-2026-09-21.md 同步订正。 - known-risks.md:KR-07 解除(Docker 已恢复)、KR-01/KR-06 按复测订正, 新增 KR-08(Docker Hub 域名 DNS 被投毒,改用国内镜像源绕行)与 KR-09(compose 项目名撞名)。 验证状态:全量回归 757/0/0/3 全绿;UI 契约门禁 18/18;对已部署栈 E2E 65/65; 负向注入可变红;工作区哈希未被注入过程污染。 未验证:GitHub Actions 首次真绿(仍未推送,见 KR-06)。
This commit is contained in:
+2
-1
@@ -63,7 +63,8 @@
|
||||
| 1.1.0-rc.19 | 2026-09-19 | 批 2/3 收尾完成:E2E 互选 8 + 预约 8 场景真实实现(本机活栈 **65 passed**,负向注入 2 轮)+ INV-011 显式守卫(9 用例);隐私设置接真实落库(V047)+ 5 死开关/2 死配置移除(产品裁定)+ `PUT /feature-flags` 真持久化(V048)+ 5 个无 SQL Mapper 方法补齐;**Task 3.3 四项 + 红娘服务拦截接线**(互选 `expires_at`、随访审计、随访风险检测、Onboarding 确认、注销 blocker 接线 + 竞态兜底);UI 契约门禁 **14→18**(WXML 结构 / WXSS 选择器 / api.js 行为 / miniapp 请求层,并修复小程序 P0 请求层崩溃);全量回归 **712 / 0 / 0 / 3** 全绿(B-9 命令实测) |
|
||||
| 1.1.0-rc.20 | 2026-09-20 | **数据保留流程落地**(产品 2026-09-19 确认:注销后数据保留不得低于 36 个月):V049 `users.closed_at` + `account.retention.purge` 权限(仅 super_admin)+ `AccountConfig.dataRetentionMonths`(36,配置化)+ `DataRetentionService`(人工审核:到期清单 + 幂等匿名化清除 + 审计;保留期内服务端拒绝)+ `DataRetentionGuardTest` 5 用例(负向注入摘掉下限判断恰 1 红);顺带清偿测试库缺 `user_photos` 表(照片软删路径 BadSqlGrammar 盲区,补表 + 移出 ParityTest 可选白名单)与 MyBatis-Plus `updateById` null 不进 SQL 陷阱(改 `LambdaUpdateWrapper.set(null)`);隐私政策 §3.3 / PIA §8 「30 天删除」修订为 36 个月;迁移基线 48→49。**全量回归 717 / 0 / 0 / 3 全绿**;**E2E 本机模拟 CI 序列 65/65 全绿**(宿主机 Python 3.11);UAT 用例 V1.1 版 46 用例(9 角色 × 7 路径)编写完成 |
|
||||
| 1.1.0-rc.21 | 2026-09-21 | **V1.0.1 配置与规则纠偏**(根治「技术默认值被误当产品规则 / 配置存在但未闭环 / 文档代码漂移」):① **照片上限配置化** `profile.photo.maxCount`(默认 6 未产品确认)+ `ProfilePolicy` + 服务器端并发强校验(新增 `PHOTO_LIMIT_EXCEEDED` 码,拒绝先于对象存储上传不留孤儿)+ 前端 `mergeAppConfig` 嵌套键修复(服务端值真正下发);② **活体开关闭环** `IdentityPolicy` + `GET /verification/liveness-status` 真实判定点(默认关不阻断实名主流程,开则 `enhancedVerified` 变化,消除假开关)+ 删死 seed `livenessVerification.enabled`;③ **推荐阈值纠偏**(60 为技术默认非产品确认)+ 规则版本化 **V050** `recommendation_records.threshold_snapshot` + 删死重复配置类 `MatchConfig`;④ 新增 `docs/governance/`(config-register / open-questions / decision-register / hardcoded-rule-audit / config-drift-audit / known-risks)并消解 PENDING 阈值/照片矛盾;⑤ 守卫 `PhotoLimitGuardTest` 8 + `IdentityLivenessGuardTest` 5 + `RecommendationThresholdSnapshotGuardTest` 4(均经负向注入可红);⑥ **canonical key 字面化**:`FeatureFlagConfig.KEY_ALIASES`(`identity.liveness.enabled` / 遗留 `livenessVerification.enabled` → 实现字段 `livenessEnabled` 读兼容)+ Controller PUT/DELETE 落库归一 canonical 键 + **V051** 清理遗留键并写入 canonical 行;⑦ **PHOTO-004 真实并发突破实测** `PhotoLimitConcurrencyGuardTest`(3 线程 H2 并发冲顶)——实测咬住「锁照片行+读时计数」在 H2 MVCC 下快照漏读、3/3 全成功突破上限的缺陷,并发控制改为**锁用户行(`UserMapper.lockUserRow` FOR UPDATE)+ 锁后新语句计数**(0 张照片亦有锁可加,补齐「首张并发」缺口),改后恰 1 成功;⑧ `AGENTS.md` 规则 27(配置与规则治理纪律:技术默认值≠产品确认规则 + canonical key 唯一 + 并发上限必须服务器强校验+并发突破测试)。**全量回归 741 / 0 / 0 / 3 全绿(基线 717 + 25 新增 − 1 删死测试);UI 契约门禁 18/18** |
|
||||
| 1.1.0-rc.22 | 2026-09-21 | **运营端机构管理三处写操作 500 修复**(清偿计划附 B.1 遗留,2026-09-19 登记、本轮处置):`OrganizationService` 创建/停用/启用分别写入 `ACCOUNT_STATUS_NORMAL`("normal") 与 `ACCOUNT_STATUS_SUSPENDED`("suspended") —— 那是 `users.account_status` 的取值,而 `organizations.status` 的 CHECK 白名单(V001 `chk_org_status`)只有 `('active','inactive')` → **三个写操作全部违约必崩**;二阶影响为 `activities.organizer_org_id` NOT NULL ⇒ 无机构即无法建活动(运营端链路级阻塞)。修复:`Constants` 新增 `ORG_STATUS_ACTIVE/INACTIVE`(独立于账号状态);三处改用 `active`/`inactive`;`OrganizationService.ALLOWED_TYPES` 补 `type` 白名单前置校验(非法值 400 取代撞 `chk_org_type` 的 500);「机构不存在」由裸 `RuntimeException`(→500)改为 `NOT_FOUND`(404);异常统一为实际被 `@ExceptionHandler` 捕获的 `GlobalExceptionHandler.BusinessException`(独立类 `shared.exception.BusinessException` **无 handler**,抛它仍会 500 —— 全仓仅 `AnalyticsService` 一处既存误用)。**根因第三重盲区同步补齐**:`schema-h2.sql` 的 `organizations` 此前**未复刻**这两条 CHECK,故 H2 上写 `'normal'` 畅通无阻 —— 已补 CHECK ×2 + NOT NULL + DEFAULT。新增守卫 `OrganizationConstraintParityTest`(生产 DDL ↔ 测试库 ↔ 后端白名单 ↔ Constants 四方比对 + 解析器自检)与 `OrganizationServiceTest`(真实 DB,9 用例)。**⚠️ 未在本机运行测试**:本轮探测确认本机**无 Docker、无 JDK**,`wsl.exe` 被安全策略阻止(同 `known-risks.md` 的 WSL/Docker 故障),`mvn -o test` 与负向注入均无法执行;已用等价正则的独立脚本验证守卫判别力与两处 DDL 一致性(PASS)。**补跑全量回归 + 负向注入前,本项记为「待验证」,不计入已验收。** |
|
||||
| 1.1.0-rc.22 | 2026-09-21 | **运营端机构管理三处写操作 500 修复**(清偿计划附 B.1 遗留,2026-09-19 登记、本轮处置):`OrganizationService` 创建/停用/启用分别写入 `ACCOUNT_STATUS_NORMAL`("normal") 与 `ACCOUNT_STATUS_SUSPENDED`("suspended") —— 那是 `users.account_status` 的取值,而 `organizations.status` 的 CHECK 白名单(V001 `chk_org_status`)只有 `('active','inactive')` → **三个写操作全部违约必崩**;二阶影响为 `activities.organizer_org_id` NOT NULL ⇒ 无机构即无法建活动(运营端链路级阻塞)。修复:`Constants` 新增 `ORG_STATUS_ACTIVE/INACTIVE`(独立于账号状态);三处改用 `active`/`inactive`;`OrganizationService.ALLOWED_TYPES` 补 `type` 白名单前置校验(非法值 400 取代撞 `chk_org_type` 的 500);「机构不存在」由裸 `RuntimeException`(→500)改为 `NOT_FOUND`(404);异常统一为实际被 `@ExceptionHandler` 捕获的 `GlobalExceptionHandler.BusinessException`(独立类 `shared.exception.BusinessException` **无 handler**,抛它仍会 500 —— 全仓仅 `AnalyticsService` 一处既存误用)。**根因第三重盲区同步补齐**:`schema-h2.sql` 的 `organizations` 此前**未复刻**这两条 CHECK,故 H2 上写 `'normal'` 畅通无阻 —— 已补 CHECK ×2 + NOT NULL + DEFAULT。新增守卫 `OrganizationConstraintParityTest`(生产 DDL ↔ 测试库 ↔ 后端白名单 ↔ Constants 四方比对 + 解析器自检)与 `OrganizationServiceTest`(真实 DB,10 用例)。**✅ 2026-09-22 补跑验证全部通过(此前记为「待验证」)**:全量回归 **757 / 0 / 0 / 3 全绿**(BUILD SUCCESS,108 个测试类,6:44;基线 741 + 新增 16 = 757);负向注入 16 例变 **3 失败 + 7 错误**(守卫三条断言全中 + H2 `CHK_ORG_STATUS` 拦下 7 例;注入采用仓库只读挂载 + 容器内副本改写,源码零污染);活栈实测创建/停用/启用 **均 2xx**、非法 type 与缺字段 400、不存在 404、**全程零 5xx**(15/15);对已部署栈 `pytest tests/e2e` **65 passed**。**本项已验证关闭。** |
|
||||
| 1.1.0-rc.23 | 2026-09-22 | **机构审计归属修复 + 测试环境 Docker 化部署与全链验证**。① **活栈验收中新发现并修复**:复核 `audit_logs` 见 `CREATE_ORGANIZATION` 的 `operator_id` **7/7 为 NULL**(而 `DISABLE/ENABLE_ORGANIZATION` 均正确记录)—— 控制器持有 `@AuthenticationPrincipal` 却未向 Service 透传,**审计不可归属等于没有审计**;`createOrganization(params, operatorId)` 改为透传 `principal.id()`,并新增断言 `createOrganizationRecordsOperatorInAuditLog` 长期守卫。修后复验:新写入的 7 条 CREATE 审计全带操作人,旧 14 条仍为 NULL(前后对照清晰)。② **Docker 测试环境部署成功**:`docker compose -p danyang` 起全栈 6 容器(postgres 5434 / redis 6381 / minio 9003-9004 / backend 8085 / admin-web / nginx 6688),51 个 Flyway 迁移全部成功、`GET /admin/` 200、`pytest tests/e2e` **65 passed**。③ **测试工具链重建并固化为仓库资产**:测试镜像 `danyang-match-backend-test` 与命名卷 `danyang-m2-cache` 因 Docker Desktop 重装一并丢失 → 构建定义落盘 `infrastructure/test-toolchain/Dockerfile`(此前它是临时产物所以才会丢);卷由 108.5MB **不完整快照**补全(原缺 `spring-boot-starter-parent`,故离线跑必失败)。④ **环境坑(已同步 known-risks)**:Docker Hub 域名 **DNS 被投毒**(`registry-1.docker.io`→31.13.95.37、`auth.docker.io`→162.125.32.15,均非真实 IP)→ 改由 `docker.m.daocloud.io` 拉取后 retag;Maven 走阿里云(实测 5337 vs 685 KB/s,快 8 倍);compose 项目名原用 `infra`,与另一项目 `AI智习室`(workdir `E:\develop\AI智习室\ai-study-room\infra`)**撞名**,其 `--remove-orphans` 会把本项目的容器当孤儿删掉 → 改用 `-p danyang`。⑤ **UI 门禁脆弱性修复**:第 16 项 `ui-document-baseline-contracts.mjs` 报假红(`未能解析出端口映射(守卫自身失效)`),真因是 `docker-compose.staging.yml` 是 **CRLF** 而守卫正则要求 `\n` 紧随 `container_name` 之后(`prod.yml` 是 LF 所以此前能过)→ 解析改为行尾无关,真实断言未削弱。**全量回归 757 / 0 / 0 / 3 全绿;UI 契约门禁 18/18;E2E 65/65**。验证脚本留痕 `.workbuddy/run-regression.sh`、`negative-injection.sh`、`org-live-acceptance.py` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user