You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.3 KiB

Phase A 企业注册与入驻基础闭环独立代码复验报告

日期:2026-09-22

1. 复验范围与边界

本次复验针对 Phase A:企业专用注册、company-register 验证码用途、验证码原子消费、用户/角色/企业/会话事务、企业入驻聚合查询、测试与 OpenAPI。

未进入 Phase B 已认证企业业务门禁,也未进入 Phase C 管理员用户与角色管理;未修改生产代码、未暂存、未提交、未推送。

2. 前置状态

  • 分支:master
  • HEAD:00153aaf5d92d13e66d6cdc42ecd1fe903d6e666
  • 暂存区:空
  • 迁移:V1–V46 未修改,未新增 V47
  • pom.xml:无修改
  • 两个既有 Windows stat 缓存假阳性文件的工作区 blob 与 HEAD 相同,未触碰、未暂存
  • 历史未跟踪验收文件和 backend-infra 文件均保留

3. 独立静态核对

通过项:

  1. 注册服务使用事务,按 COMPANY 角色创建用户,并显式写入仅含 COMPANY 的 user_roles。
  2. 用户、企业保存后 flush,再创建登录会话;企业初始 verified=false。
  3. 注册审计使用固定脱敏文案,未发现密码、验证码、Token 或摘要输出路径。
  4. 验证码消费使用条件更新,条件包含 id、used=false、未过期和 attempts 上限,受影响行数必须为 1。
  5. 短信用途采用固定白名单,包含 company-register,不接受任意非空用途。
  6. 匿名规则仅新增 /auth/company/register;/companies/me/onboarding 仍要求认证。
  7. 入驻状态对无记录、PENDING/RESUBMITTED、REJECTED、VERIFIED 和 APPROVED 不一致状态分别处理;不一致状态失败关闭。
  8. DTO 未暴露 userId、客户端 role、verified、passwordHash 等不应由客户端控制的字段。
  9. OpenAPI 中新增注册和入驻查询契约,未改变 V1–V46 或既有业务路径。

4. 定向测试与真实黑盒

实施测试与复验前已执行的 Phase A 定向测试为 23/23,Failures=0,Errors=0,Skipped=0,其中包含真实 MySQL/Testcontainers 并发注册测试。

此前全量结果:

  • mvn test:2860/0/0/0
  • mvn clean verify:2860/0/0/0
  • OpenAPI:182 paths / 220 operations,All checks passed

隔离 MySQL 8.4、Redis 7.4、RabbitMQ 3.13 和最新 JAR 的黑盒结果:健康检查通过;发送 company-register 验证码后注册成功;密码登录成功;/auth/me 返回 COMPANY;入驻查询返回 200;目标数据为 1 个 COMPANY 用户、1 个 COMPANY 角色、1 个企业且 verified=0,验证码已消费。临时容器、进程、端口和日志已清理。

5. 阻断项:功能开关绑定不满足严格字面量要求

生产文件:mydreamjob-server/src/main/java/com/mydreamjob/auth/company/CompanyRegistrationProperties.java

当前字段为:

private boolean enabled = false;

Spring Boot 标准布尔绑定会把 TRUE、True、yes、1、on 均转换为 true。独立临时测试使用 ApplicationContextRunner 真实绑定配置,逐一设置:

app.company-registration.enabled=TRUE
app.company-registration.enabled=True
app.company-registration.enabled=yes
app.company-registration.enabled=1
app.company-registration.enabled=on

复验结果:五个非字面量值均绑定为 enabled=true,测试失败:

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
Expecting empty but was: ["TRUE", "True", "yes", "1", "on"]

这与设计要求“只有字面量 true 才开启,其他值不得误开启”不一致,因此 Phase A 独立复验判定 FAIL。临时测试已删除,未留在工作区。

整改建议:将配置原始值改为 String,并通过唯一方法严格判断:

private String enabled = "false";

public boolean isEnabled() {
    return "true".equals(enabled);
}

同时增加真实 Spring 属性绑定测试,覆盖未设置、false、true、TRUE、True、yes、1、on;只有小写字面量 true 应开启。

6. 整改前的次要测试覆盖缺口

以下是首次独立复验时发现的证据缺口,不作为已证明的生产缺陷:

  1. CompanyRegistrationTransactionRollbackTest 目前主要覆盖审计失败,未分别注入并断言 users 保存、user_roles 保存、companies 保存、会话创建和审计写入五类失败;对 user_roles/auth_tokens 的零残留断言也不完整。
  2. 注册请求中客户端附带未知的 role/verified/passwordHash 字段的既有测试,可能因验证码未准备而返回 400,不能单独证明未知字段被拒绝;DTO 本身未声明这些字段。
  3. tombstone、Redis/数据库/会话依赖异常和每种冲突角色的完整 HTTP 黑盒覆盖仍需单独补齐或明确证据。

7. 复验结论

Phase A 的主要注册、验证码原子消费、事务、并发、入驻聚合和真实中间件路径基本可用,但严格功能开关绑定存在阻断缺陷;另有事务回滚测试覆盖不足。

最终判定:FAIL,暂不能进入独立通过或提交检查点。

本次独立复验未修改生产代码、未暂存、未提交、未推送,未进入 Phase B/C。

8. 阻断整改复验(2026-09-22)

针对第 5 节阻断,已按最小范围修改:

  • CompanyRegistrationProperties.enabled 改为字符串,默认值为 "false";
  • isEnabled() 仅返回 "true".equals(enabled);
  • CompanyRegistrationFeatureFlagTest 增加真实 ApplicationContextRunner 绑定测试,覆盖 TRUE、True、yes、1、on、false 和 true。

整改后验证:

  • 功能开关及关联测试:9/9,F=0、E=0、S=0;
  • Phase A 定向测试:24/24,F=0、E=0、S=0;
  • mvn clean verify:2861/2861,F=0、E=0、S=0;
  • OpenAPI:182 paths / 220 operations,All checks passed。

独立绑定测试确认只有字面量 true 开启,五种非字面量值均保持关闭。未新增迁移,未进入 Phase B/C,未提交或推送。

功能开关阻断已清除;第 6 节的事务回滚覆盖缺口已在第 9 节补齐。

说明:第 7 节“FAIL”是整改前复验结论;当前状态以第 8、9 节整改复验结果为准。

9. 事务回滚覆盖整改复验(2026-09-22)

CompanyRegistrationTransactionRollbackTest 已补齐五类独立故障注入:

  • users 保存失败;
  • user_roles 真实插入触发器失败(H2 真实 SQL);
  • companies 保存失败;
  • 会话创建失败;
  • 审计写入失败。

每种场景均验证 users、user_roles、companies、auth_tokens 无残留,验证码 used=false,并按精确测试手机号清理。测试结果:5/5,F=0、E=0、S=0。

10. 阻断修复后的完整回归收口(2026-09-22)

为避免把整改前的历史数字误读为当前结果,最终收口结果单独列示如下:

  • 功能开关整改后的独立定向:9/9;
  • 五类事务回滚注入:5/5;
  • Phase A 完整定向测试:28/28,F=0、E=0、S=0;
  • mvn clean verify:2865/2865,F=0、E=0、S=0,BUILD SUCCESS;
  • OpenAPI:182 paths / 220 operations,All checks passed;
  • 真实 MySQL/Testcontainers 并发注册:已执行并通过;
  • V1–V46 未修改,未新增 V47;未进入 Phase B/C,仍未暂存、未提交、未推送。

期间 H2 user_roles 触发器用于证明真实 SQL 插入失败,触发日志中的预期 SQL 错误属于测试注入证据,不是生产异常;未修改生产错误映射,也未放宽任何断言。

11. 复验重跑收口(2026-09-22)

  • 独立静态门禁通过:功能开关严格按小写字面量 true 开启;匿名放行仅包含 /auth/company/register;注册 DTO 未暴露 userId/role/verified/passwordHash;验证码白名单、条件消费和 attempts < maxAttempts 均已分别在 Service 与 Repository 位置核对;未发现 V47。
  • 首次静态脚本曾把 attempts < c.maxAttempts 错查在 SmsVerificationService.java,造成脚本假阴性;修正为检查 SmsVerificationCodeRepository.java 后门禁通过。该问题仅存在于复验脚本,不是产品缺陷。
  • Phase A 定向重跑:28/28,Failures=0、Errors=0、Skipped=0;真实 CompanyRegistrationConcurrencyMySqlTest 启动 MySQL 8.4 Testcontainers 并实际执行。
  • OpenAPI:182 paths / 220 operations,All checks passed。
  • 收尾:无 Java/Maven 残留进程,8080/8081 无监听,暂存区为空;本轮未修改生产代码、未提交、未推送,未进入 Phase B/C。