Skip to content

plugin-auth: 后台溢出的种子用户可能错过一次性 membership backfill(单组织 auto 模式,重启自愈) #2996

Description

@os-zhuang

背景

复测 #2926 / #2909 期间修复了三个 kernel:ready 生命周期时序缺陷后,对其余 kernel:ready 消费者做了一轮预防性审计,专找同一类隐患——「在 kernel:ready 里读取别的插件同期 bootstrap/seed 产出的数据、且注册顺序不保证消费者晚于生产者」。

结论:0 CONFIRMED、7 SAFE、1 PLAUSIBLE。本 issue 记录唯一的 PLAUSIBLE 项。它是一个独立的、预存的、低紧急度边角,与 #2926/#2909 的缺陷线无关,属 ADR-0093 D6(membership backfill)领域。

现象

plugin-auth 的一次性 membership backfill 是 member-less 用户的唯一兜底网,在极端时序下可能漏掉经种子插入的用户。

根因链:

  1. 种子用户绕过 per-create 兜底。app 种子经 raw engine.insert(system context)插 sys_user,绕过 better-auth 的 user.create.after hook —— 因此每建一个用户就跑一次的 reconcileMembership对种子用户不触发。它们唯一的网就是下面这条一次性 backfill。

  2. backfill 是一次性 kernel:ready hook,无种子完成回调
    packages/plugins/plugin-auth/src/auth-plugin.ts:604ctx.hook('kernel:ready', …)backfillMemberships(packages/plugins/plugin-auth/src/reconcile-membership.ts:158)。读 sys_user + sys_member,把 member-less 用户绑到默认组织。跑完即止,种子后续完成不会重触发。

  3. 种子会在超预算时脱离到后台
    packages/runtime/src/app-plugin.ts:849-858:inline seed 只对 OS_INLINE_SEED_BUDGET_MS(默认 8s)预算 Promise.race;超时即 warn 后继续在后台跑(仅挂 .catch),溢出到 kernel:ready / kernel:listening 之后。AppPlugin 注册在 auth/security 之前,是唯一能让 kernel:ready 消费者观察到「部分种子」状态的现实路径。

净结果:大 bundle 的种子若 >8s 预算而脱离后台、在 backfill 的 kernel:ready 之后才插完用户 → 这些用户在单组织 auto 模式下保持 member-less(登录时 active org 为空)。

自限条件(为什么定为低紧急度)

  • 三条同时成立:种子超 8s 预算脱离 + membershipPolicy: 'auto' 单组织 + 用户仅来自种子(非交互注册)。
  • 重启即自愈:下次 boot 的 backfill 会补上;backfill 幂等。
  • multi-org 与 invite-only 模式自动 no-op,不受影响。
  • 可用 OS_SKIP_MEMBERSHIP_BACKFILL=1 显式退出(与本缺陷正交)。

修复方向(需设计取舍,勿顺手改)

  • ⚠️ 仅迁到 kernel:bootstrapped 锚点不够:后台种子能 outlast kernel:listening,换锚点只收窄窗口不封死。
  • 候选真解(择一,值得单独讨论):
    1. 种子完成回调重跑 backfill —— 种子 promise settle 后再跑一次 backfill(即便已在后台);最贴合"兜底网"语义。
    2. 种子用户不绕过 membership 兜底 —— 让 raw-insert 的 sys_user 也过 reconcileMembership(或种子通道显式补 membership),消除对一次性 backfill 的依赖。
    3. 不脱离种子 —— 但这会重新引入种子阻塞 kernel 启动的问题(8s 预算正是为规避它而设),不推荐。

关联


Filed from the preventive kernel:ready ordering audit following #2926/#2909. Triage only — not yet scheduled.

Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions