Skip to content

SCIM: 停在 @better-auth/scim rc.1,等正式版再整体迁移 —— rc.2 换掉了整套模型 #3653

Description

@os-zhuang

重写。 原帖(以及第一次更新)问的是"要不要补齐 SCIM group 的四张平台对象表"。去调研 rc.2 之后,这个问题的前提没有了 —— rc.2 把 SCIM 整个重设计了,rc.1 的那四张表在上游已经不存在。所以本 issue 现在记录的是一个决定和它的理由,不是一个待办。

决定

停在 @better-auth/scim@1.7.0-rc.1,不补 group 表,不升 rc.2。等 SCIM 出正式版之后,作为一次独立的架构迁移一起做。

为什么不补 rc.1 的四张表

照 rc.1 实现,等于照着上游已经废弃的 schema 建四张表:

  • scimGroupRole / scimGroupRoleGrant 在 rc.2 里已经没了;
  • scimGroup / scimGroupMember 名字还在,但列完全不同(rc.2 的 scimGroup 多了 connection_id / revision / display_name_key / order_key)。

写出来就是即刻过时的迁移债,而且是带数据的那种。

为什么不升 rc.2

rc.2 不是一次版本升级,是一次架构迁移。三点,按严重程度排:

1. scimProvider 整个消失了

rc.2 里全文 0 处引用。而 sys_scim_provider 是 ObjectStack 唯一有的 SCIM 平台对象 —— 也就是 #3688 刚给它补上 provider_key 的那张表。它在 rc.2 下没有对应的上游模型

2. 模型换了一套

模型
rc.1(当前) scimProviderscimGroupscimGroupMemberscimGroupRolescimGroupRoleGrant
rc.2 scimConnectionBindingscimIdentityTombstonescimSubjectscimUserscimProjectionGrantscimGroupscimGroupMember

5 个换 7 个,只有两个名字重合,而这两个的列也不一样。

3. 连接从"运行时数据行"变成了"启动时配置"

rc.2 的 scim() 在构造时强制要求静态声明 connections:

BetterAuthError: The scim plugin requires at least one provisioning connection.

auth-manager.ts 现在传的是 scim({ storeSCIMToken: 'hashed' }) —— 没有 connections,rc.2 下直接抛错

这一条比 schema 变更严重得多:它把 SCIM 连接从「数据库行 + /scim/generate-token 端点 + Setup UI 管理」搬到了「进程启动配置」。token 由谁产生、存在哪、怎么轮换,全都变了,连带影响 Setup UI 和 generate-token 那一整条链路。

现在是什么状态(不是"坏的",是"有边界的")

所以开启 SCIM 的部署,今天不要让 IdP 推送 group。 这是接受这个决定的代价,写在这里而不是让人踩。

parity gate 怎么守住这段时间

gate(better-auth-schema-parity.test.ts)没有假装覆盖到了。四个无对象的 model 在一个 KNOWN_UNMAPPED_MODELS 精确集合里,并且集合本身被断言:

  • 出现新的无对象 model → 构建失败;
  • 某个 model 不再在集合里(说明已经 provision 了)→ 也失败,提示把它挪进列检查。

也就是说:真去升 rc.2 的那一刻,gate 会立刻把这七个模型的差异全部报出来,不会有第二个"悄悄长出来的洞"。这正是它该起的作用。

重启这件事的触发条件

@better-auth/scim 发布正式版(非 rc)。到那时一并处理,作为一个独立的迁移任务:

  1. 按正式版的模型集补齐平台对象(届时以正式版为准,不是 rc.2);
  2. 决定 sys_scim_provider 的去向 —— 迁移还是废弃;
  3. 重做连接配置模型(静态 connections vs 现有的 generate-token + Setup UI);
  4. auth-manager.tsscim({...}) 调用补上必需参数。

一处独立的遗留张力(与版本无关)

sys_scim_provider 上有 { fields: ['provider_id'], unique: true },但 rc.1 上游的唯一性边界是 <organization>:<provider_id> —— 同一个 provider_id 在两个不同组织下,上游认为合法,而这个索引会拒绝

比库假设的约束更严。#3688没有动它:放宽一个已经生效的唯一约束是独立的决定,而且要先确认当初是不是有意为之。记在这里,不随 SCIM 迁移绑定 —— 它今天就可以单独判断。

已经做完的部分(原帖的问题)

原帖最初问的是"parity gate 覆盖不到 sso/scim"。这一点已经修好并合并:两个 plugin 虽然不接受 schema option,但它们自己暴露 .schema,而 adapter 对 bridged model 的列名规则是机械的 camelCase → snake_case。gate 现在读前者、套后者,算出它们真正会写的列。

Refs #3624, #3647, #3688, ADR-0071。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions