Skip to content

fix(auth): 处理 #54 review——灰度闸双向故障 + OTP dev 兜底 + INV-008 - #55

Merged
longsizhuo merged 1 commit into
mainfrom
fix/discord-canary-review
Jul 26, 2026
Merged

fix(auth): 处理 #54 review——灰度闸双向故障 + OTP dev 兜底 + INV-008#55
longsizhuo merged 1 commit into
mainfrom
fix/discord-canary-review

Conversation

@longsizhuo

Copy link
Copy Markdown
Member

#54 里属于后端的 9 条。请 review,我不合并。

Closes #54 的后端部分(前端 3 条见 involutionhell#390,含线上崩页那条)。

灰度闸:两个方向都会坏,现在都堵上

场景 改前 改后
env 丢失/拼错 静默对全网开放,唯一信号是"没有拒绝日志" 启动即播报当前模式(闸启用 N 个 id / 闸关闭全开放)
清列表手滑留个逗号 ",".split(",") 返回零长数组 → 悄悄锁死所有人,日志还说"你不在白名单" 保持拒绝 + ERROR 告警(错误方向选"没人能登",不选"所有人能登")
ALLOWLIST="123" docker-compose env_file 不剥引号 → 本该放行的人也进不去 解析时剥引号
空 uuid 参与比较 直接拒绝
已有账号回访登录 被闸挡在自己账号外面,只提示"敬请期待",无恢复路径 豁免——闸要拦的是"建新号",不是回访
被拒后 我们持有其 token,授权永久留在他 Discord「已授权应用」里 调 Discord revoke 撤销(失败不阻断拒绝)

"已有账号"当前实测影响面为 0(user_identities 里 discord 仅 1 条,discord_* 独立账号 0 个),但这是闸的语义位置问题:它保护的应是账号创建。

OTP dev 兜底:触发条件与生产事故同形

改前判据是"Resend 没配"——这也正是 prod 掉 key 的样子。接线后 prod 一旦丢 key 就会假装"验证码已发送",用户永远卡在输码页(改前是 SEND_FAILED,可重试)。

现在由显式开关 registration.otp.dev-console 驱动,关掉即恢复原行为。日志也不再打印收件邮箱(PII)——同文件下方八行就写着 // 不落收件邮箱(PII),新代码违反了它。

测试与文档

  • 新增 OAuthControllerAllowlistTests(10 条):闸此前零测试,而它长在 INV-007 保护的方法体内,今后重构挪走它 289 个测试照样全绿。回调成功路径需要真实 Discord code,MockMvc 到不了闸,所以直接测判定函数。
  • RegistrationServiceTests:dev 兜底原断言(SENT + never() sendHtml)挡不住真正会坏事的重构——把 isConfigured() 检查上提就会导致会话态不写入、拿到码也验不过,而测试照过。改为断言"限流已计数"来锁定该副作用;另补"没开开关时仍返 SEND_FAILED"。
  • application-test.properties pin 掉两个新属性:本机 set -a && . ./.env 跑测试会让 env 渗进测试 JVM,闸在本机是开的、CI 是关的,同一个测试两台机器结论不同(与既有的 justauth.type.discord.* pin 同因)。
  • .env.example 补两个变量:照文档配出来的环境此前 = 白名单为空 = 全开放
  • SECURITY.md INV-008:闸只放行白名单与已有账号,且不得静默失效。

验证

全量 300 通过(289 → +11)。未部署,等你 review。

xhigh review(#54)对已上线的 Discord 灰度(#53)查出的后端问题,逐条修:

灰度闸
- 白名单启动时解析成 Set 并**播报当前模式**:缺 env 与故意 GA 行为完全一致,
  没有这条日志,一次丢掉 AUTH_DISCORD_ALLOWLIST 的部署会静默把 Discord 对全网
  打开,唯一信号是"没有拒绝日志"。
- 配了值却解析不出任何 id(清列表时手滑留个逗号;Java 的 ",".split(",") 返回零长
  数组)不再塌缩成全开放:保持拒绝并 ERROR 告警——错误方向要选"没人能登"。
- 剥引号:docker-compose env_file 不剥,ALLOWLIST="123" 会带引号比对失败,
  把本该放行的人也锁在外面。
- 空 uuid 不放行。
- **已有账号的回访登录豁免**:灰度要拦的是"建新号"(OTP wiring 未完成会分叉账号),
  不是把已有账号的人锁在自己账号外面、还只提示"敬请期待"。
- 拒绝时撤销刚换到的 access token(AuthDiscordRequest#revokeToken):既然不让登,
  就别把用不上的 token 和授权留在人家 Discord 账号里。撤销失败不阻断拒绝流程。

OTP dev 兜底
- 改由显式开关 registration.otp.dev-console 驱动,不再只看"Resend 没配"——后者同时
  也是生产掉 key 的样子,那样 prod 丢 key 会假装发送成功,用户永远卡在输码页
  (改前是 SEND_FAILED,可重试)。关掉开关即恢复该行为。
- 日志不再打印收件邮箱(PII),只留 pendingId + code,与本文件下方及
  ResendEmailService 的既有规则一致。

测试与文档
- 新增 OAuthControllerAllowlistTests(10 条):畸形取值解析、未配即全开、配了却
  解析不出 id 时拒绝所有人、空 uuid、已有 identity 放行、identity 查询失败不放行。
- RegistrationServiceTests:dev 兜底改测"会话状态确实写入"(限流已计数),挡住把
  isConfigured() 检查上提导致本地流程静默坏掉的重构;补"没开开关时仍返 SEND_FAILED"。
- application-test.properties pin 掉两个新属性:本机 .env 会渗进测试 JVM,否则同一
  个测试在本机和 CI 结论不同(与 justauth.type.discord.* 既有 pin 同因)。
- .env.example 补 AUTH_DISCORD_ALLOWLIST / REGISTRATION_OTP_DEV_CONSOLE:照文档配出来
  的环境此前 = 白名单为空 = 全开放。
- SECURITY.md 补 INV-008(闸只放行白名单与已有账号,且不得静默失效)。

全量 300 测试通过(289 → +11)。
Copilot AI review requested due to automatic review settings July 26, 2026 06:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discord 灰度(#53 / frontend#389)xhigh review 的 15 条待修项

2 participants