Related: #1154 , #1155 , #1156 , #1162 , #1182 , #1185
Canonical code-block runtime / API contract: #1393
Issue 元数据
计划类型:Single Issue
分级:grade:g4
任务形态:hybrid-foundation
标签:plan:single、grade:g4、phase:discussion、type:feature、area:backend、area:frontend、area:api、area:settings、area:schema-ui、area:runtime、contract、security、user-data、migration、needs-backend、needs-frontend、needs-qa
预期结果
把公开认证页收敛为“认证器实例选择壳层 + 认证器拥有的完整代码区块”:
每个已启用认证器实例持久化一个完整 public_ui_block,它同时表达该认证器的登录、注册、扫码、跳转或其他公开认证交互,是该认证器公开 UI 的唯一真值。
Core /sign-in 不再生成账号密码表单,也不按 auth_type 拼装登录/注册 UI;它只获取可用认证器、选择实例、注入后端公开变量与 canonical Block context,并复用 canonical 代码区块组件渲染。
只有一个认证器时直接显示其 Block,不显示选择器;多个认证器时显示一列实例按钮并渲染当前实例 Block;没有可用实例时显示明确不可用状态,不回退到另一份 Core 表单。
后端认证插件可以随 provider contribution 注册后台 config_schema、默认完整代码区块、公开变量投影和 public Auth API operation;安装后端插件不需要修改或重新发布 Core 前端。
password-local 默认区块同时承载登录与自行注册。self_registration_enabled 由后端认证器配置决定,仅作为 public_variables 注入 Block 供其决定是否展示注册入口。
浏览器修改 Block、变量或请求不能开启后端能力:注册动作必须重新读取持久化认证器配置,配置未开放时直接拒绝。
插件默认区块只在创建实例或一次性补齐历史空值时注入;插件升级不得静默覆盖认证器已经保存的用户区块。
最终数据流:
Auth Provider contribution
-> config_schema + default_public_ui_block
-> public variable projection + public Auth API operations
-> Authenticator instance persists public_ui_block and private config
-> GET /api/public/auth/login-instances returns public projection
-> Core selects one instance and mounts the shared Block host
-> Block reads immutable public inputs and invokes provider APIs through canonical ctx.api
-> Auth Center reloads config, authorizes the action, then owns user/identity/session writes
现状与证据
已确认事实
待验证假设
password-local 自行注册可以复用现有用户/成员创建、密码策略与 user_auth_identities 写入入口,在同一后端事务内完成,而不新增旁路 repository write。
若公开注册必须创建 workspace membership,默认归属、默认角色、激活/验证策略必须来自后端显式配置;请求体不得携带可生效的角色、owner 或权限。若当前没有安全的 canonical provisioning policy,进入实现前先在本 Issue 补齐该字段与默认值。
[Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 最终合入的代码区块 program、inputs 和 ctx.api contract 能在未登录页面由 Auth host adapter 复用;若最终合同发生实质变化,只调整共享 adapter,不改变“一个完整 Block 是 UI 唯一真值”的产品边界。
范围、权限与边界
范围内
为 HostExtension Auth Provider contribution 增加并校验:后台 config_schema、default_public_ui_block、后端公开变量投影、可供该 Block 通过 ctx.api 调用的 public Auth API operations。
在认证器领域模型、repository、migration、settings DTO/API 中增加一等 public_ui_block,其值直接使用 canonical 完整代码区块 program/descriptor,不复制出 Auth 专用 AST。
让认证器后台 schema-driven 配置表单能够展示、编辑、校验和保存 public_ui_block;该控件复用已有代码区块编辑/预览组件,不把源码复制进 options 形成第二真值。
扩展 GET /api/public/auth/login-instances 的职责单一 public projection:只返回已启用实例的公开元数据、完整 public_ui_block 和后端生成的 public_variables;不返回 raw options、后台 schema、secret 或第二份接口目录。
抽取或复用 feature-neutral 的代码区块 mount/render 组件,并实现 Auth host adapter:使用 canonical Block context/inputs/ctx.api contract 注入认证器上下文,不依赖 Frontstage page、page document 或 block-code API。
改造 /sign-in 的单实例、多实例、零实例、加载失败和区块运行失败交互;删除 Core 自有账号密码登录表单以及按认证类型解释 UI 的分支。
为 password-local 提供默认完整 Block,覆盖现有登录与可选自行注册;增加自行注册 public Auth API、后端 command、事务写入、错误语义与审计。
历史内置认证器回填默认 Block;self_registration_enabled 安全默认 false。历史非空用户 Block 不覆盖。
覆盖插件首次安装、创建实例、复制实例、升级插件、禁用实例和删除实例时的 Block 生命周期。
非目标
不建立 Auth 专用 TSX 方言、Schema UI 公开登录表单、受限能力子集、认证类型 renderer 或另一套 Block runtime。
不让 Core 根据 self_registration_enabled 等变量生成、隐藏或拼接任何认证控件;变量的显示解释只属于认证器 Block。
不让公开登录页读取 Frontstage page/document/block-code 资源,也不为了认证 UI 创建隐藏 Frontstage 页面。
不在本 Issue 接入一个真实 OIDC/SAML/短信/企业微信插件;协议和 fixture 必须证明后端插件可贡献不同 UI/API,但具体 provider 另开 Issue。
不允许认证插件绕过 Auth Center 直接写 users、user identities、sessions、roles 或 workspace memberships。
不在插件升级时自动“同步最新版模板”;如未来需要手动比较或重置到新模板,另行确认其覆盖语义。
已授权动作
当前仅授权创建和完善本线上 Single Issue;不授权在本轮修改产品代码、执行 migration 或发布。
用户确认本 Issue 正文并将其推进到 phase:ready 后,授权在既定范围内完成前后端、migration、fixture、测试和 QA 闭环。
需要额外确认的动作
若现有后端没有可复用的安全注册 provisioning policy,需要用户确认新用户默认归属、角色、激活和验证语义后才能进入实现。
覆盖任意非空历史 public_ui_block、删除历史认证/身份数据、放宽现有代码区块 capability/security contract,必须另行确认。
方案结论
采用方向与关键取舍
采用“协议驱动的单一组合合同”,不采用“简单表单走 schema-ui、复杂认证走 TSX”或“Core 默认表单 + 插件 TSX”两套维护模式。
一个认证器实例只有一个完整 public_ui_block。登录与注册可以同时在该 Block 内,也可以由 Block 自己切换步骤;Core 不拥有第二份登录/注册 UI。
authenticators.public_ui_block 是公开 UI 内容真值;认证器私有配置是动作许可真值;public_variables 是后端从配置生成的只读公开投影,不是另一份持久化配置。
Provider contribution 的 default_public_ui_block 只是实例初始化种子,不是运行时覆盖真值。新实例复制当前默认值;既有实例保留保存值。
Auth host adapter 复用 canonical Block program、renderer、module、permission 与 capability contract。它只负责构造未登录认证上下文并提供 canonical ctx.api transport,不解释认证业务字段。
Block 源码复用 [Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 最终 ctx.api.<method>(path, request) 合同调用 provider 注册的 public Auth API;后端 route/OpenAPI 和 Auth Center/Provider registry 是接口与授权真值。不得新增 ctx.auth.*、接口 descriptor 目录、持久化 binding 或另一套 dispatch 体系。
对 password-local,self_registration_enabled=false 是安全默认。Block 可以根据公开变量隐藏注册入口,但后端拒绝才是安全保证。
建议合同形状
字段名以领域语义为准;实现不得为了前端展示另起别名:
AuthenticatorProviderContribution
config_schema
default_public_ui_block // canonical Block program/descriptor
public_variable_projection // server-side projection, never raw options
public_auth_operations // backend routes/OpenAPI; Auth Center mediated
AuthenticatorRecord
id / auth_type / title / enabled / sort_order
private config
public_ui_block // persisted user-owned UI truth
PublicLoginInstance
id / auth_type / title / sort_order
public_ui_block
public_variables
Auth Block inputs
authenticator_id
public_variables
locale/theme and other canonical Block context
Auth Block API
ctx.api.<method>(path, request) // canonical Block contract, no Auth-specific fork
auth_type 可以作为公开元数据返回,但 Core 不得用它选择组件、字段或提交流程。
复杂度归属
Provider-specific UI、公开变量与 public API 属于后端 Auth Provider contribution / authenticator instance。
用户、身份绑定、session、注册许可、角色/归属约束和审计属于 Auth Center。
源码执行、inputs、ctx.api、module 与 renderer 属于共享代码区块协议/runtime。
/sign-in 只拥有认证器选择、加载态、错误边界和共享 Block mount,不拥有认证业务表单。
Domain Matrix
Object / behavior
Owner
Source of truth
Persisted
User editable
Public/runtime contract
Historical impact
Unacceptable failure mode
default_public_ui_block
Auth Provider contribution
installed provider package
provider artifact
no
initialization only
new/missing instances
plugin upgrade overwrites a saved instance Block
authenticators.public_ui_block
Auth Center / authenticator instance
authenticator record
yes
yes, via settings
yes
password-local backfill
Core/Frontstage owns another UI copy or migration overwrites non-empty content
private authenticator config
Auth Center/provider
persisted backend config
yes
permitted fields only
no raw public exposure
add safe registration default
browser variable/request becomes permission truth
public_variables
provider server-side projection
current persisted config
no second truth
no
yes, read-only
none
raw options/secret/schema leaks or frontend invents compatibility values
public Auth API operations
provider registry + Auth Center
registered backend route/OpenAPI
registry/runtime
no
yes
none
plugin route bypasses Auth Center writes or trusts browser state as authorization
selected authenticator
Core login shell
public ordered instance list
page state only
user selects
yes
none
Core branches by auth type or submits against a different instance
self-registered user/identity/session
Auth Center
domain service + repository transaction
yes
public input under policy
yes
new user data
disabled registration succeeds, duplicate partial writes, client grants itself role/owner
验收点账本
编号
可观察结果
证据
结算阶段
AC-001
一个 fixture Auth Provider 只安装后端 contribution,即可注册 config schema、默认完整 Block、公开变量和 public Auth API;非法/重复/缺字段 contribution fail closed
plugin-framework/domain/control-plane contract tests
本地 + QA
AC-002
认证器实例持久化 canonical public_ui_block,后台 schema-driven 表单可编辑、校验、保存并重开;私有配置与公开 Block 无双写
migration/repository/route tests + settings Vitest
本地 + QA
AC-003
public login-instances 只投影已启用实例的公开字段、Block 和变量,不泄漏 raw options、secret、后台 schema 或第二份接口目录
public API allow/deny fixture + response snapshot
本地 + QA
AC-004
一个实例时直接显示 Block;多个实例时显示一列按钮并切换对应 Block;零实例/API 失败时显示正式错误状态且没有 Core 表单 fallback
SignInPage Vitest + desktop/390px browser evidence
QA + 用户验收
AC-005
Auth 页面与 Frontstage 消费同一 canonical Block component/runtime/module/capability contract,仅 host adapter 不同;仓库中不存在 Auth 专用源码方言、renderer 或 runtime fork
package build/tests + architecture review
QA
AC-006
password-local 默认 Block 在同一 Block 内完成登录,并只在后端注入 self_registration_enabled=true 时展示自行注册交互
Block/runtime fixture + public browser flow
QA + 用户验收
AC-007
即使浏览器把变量改为 true、篡改 authenticator_id 或直接调用注册 API,后端在持久化配置为 false、实例禁用或 route/provider 不匹配时均拒绝且不产生用户/identity/session
backend negative route/service/repository tests
本地 + QA
AC-008
注册开放时通过 Auth Center 原子创建合法用户与 password-local identity,遵守密码/唯一性/provisioning policy,不接受客户端角色、owner 或权限提升
transaction/concurrency/duplicate/permission tests + audit assertion
本地 + QA + CI-beta
AC-009
历史 password-local 实例得到默认 Block 且注册默认关闭;迁移前后 id/身份绑定不变,已有非空 Block 不被覆盖
migration fixture + preflight count + rollback rehearsal
QA + CI-beta
AC-010
新建实例获取当前插件默认 Block;复制实例复制当前保存 Block;插件升级后已有实例内容逐字节保持不变
install/create/copy/upgrade lifecycle tests
本地 + QA
AC-011
无效或运行失败的 Block 被隔离到当前认证器错误边界;多实例选择仍可切换,系统不静默执行另一份登录表单
runtime/error-boundary Vitest + browser evidence
QA
验证与资源边界
实现前使用 test-driven-development 固定有限 acceptance matrix:单/多/零实例、登录、注册开/关、变量伪造、实例禁用、secret 投影、无效 Block、历史回填、插件升级不覆盖。
后端最小证据:plugin contribution contract、domain/repository、Auth Center settings/public routes、注册 command/transaction、权限与审计的定向 Rust 测试;同一 worktree 同时只运行一条 Cargo 命令。
前端最小证据:page-protocol/page-runtime/shared host、api-client、Settings Auth Center、SignInPage 的定向测试;desktop 与 390px 验证单实例、多实例、注册开关和失败状态。
安全 red-team:直接伪造 public_variables、篡改/跨认证器 authenticator_id、调用未知或不匹配的 public Auth route、禁用实例、secret-shaped config、重复注册、并发注册、客户端 role/owner 字段。
migration preview:先统计需要回填、已有非空 Block、缺失 provider default 和异常 config 的实例;任何非空覆盖计数必须为 0。
rollback:发布前保留旧公开发现 contract 的可回退数据库版本;一旦用户已编辑 public_ui_block,回滚必须先导出/保留该用户内容,不能通过降级丢弃。运行时不保留第二份 Core 表单作为“回滚”。
进入验收使用 qa-evaluation,warning/coverage 与最终 QA 证据写入 tmp/test-governance/。
延后证据:workspace 级 full Cargo、full frontend build、coverage 和完整 repo verify 可交给 CI-beta;若定向证据无法覆盖 contract/migration 风险,则不得延后。
停止与重构条件
必须新建 Auth 专用 TSX/AST/renderer/runtime,或必须降低 canonical 代码区块既有能力,才能继续。
Core 必须按 auth_type、注册开关或其他业务变量解释并生成认证 UI。
公开登录页必须依赖 Frontstage page/document/block-code 资源,或必须维护第二份 UI 内容真值。
Provider 必须直接写 users、identities、sessions、roles/workspace memberships,绕过 Auth Center 才能完成注册。
当前系统没有安全的注册 provisioning policy,且无法从后端配置明确默认归属、角色、激活/验证语义。
public projection 无法证明不泄漏 secret/raw options,或 public Auth route 无法重新校验当前认证器、provider 与持久化配置。
migration/reconcile 会覆盖任意非空用户 Block、改变历史身份绑定,或无法对缺失 provider default 的实例 fail closed。
[Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 canonical Block/ctx.api contract 在实现前发生破坏性变化,导致本 Issue 需要拥有第二套协议;此时回到本 Issue 更新合同,不做前端兼容猜测。
生命周期
当前阶段:phase:implementation
实施授权:用户已于 2026-07-24 确认本 Single Issue 并明确要求开始实现;实现中若发现缺少安全 provisioning policy,按停止条件回到 discussion。/
关闭条件:AC-001~AC-011 全部结算,migration preview/rollback 和集中 QA 证据齐备,合入 protected beta 后由用户完成最终验收。
Related: #1154, #1155, #1156, #1162, #1182, #1185
Canonical code-block runtime / API contract: #1393
Issue 元数据
grade:g4hybrid-foundationplan:single、grade:g4、phase:discussion、type:feature、area:backend、area:frontend、area:api、area:settings、area:schema-ui、area:runtime、contract、security、user-data、migration、needs-backend、needs-frontend、needs-qa预期结果
把公开认证页收敛为“认证器实例选择壳层 + 认证器拥有的完整代码区块”:
public_ui_block,它同时表达该认证器的登录、注册、扫码、跳转或其他公开认证交互,是该认证器公开 UI 的唯一真值。/sign-in不再生成账号密码表单,也不按auth_type拼装登录/注册 UI;它只获取可用认证器、选择实例、注入后端公开变量与 canonical Block context,并复用 canonical 代码区块组件渲染。config_schema、默认完整代码区块、公开变量投影和 public Auth API operation;安装后端插件不需要修改或重新发布 Core 前端。password-local默认区块同时承载登录与自行注册。self_registration_enabled由后端认证器配置决定,仅作为public_variables注入 Block 供其决定是否展示注册入口。最终数据流:
现状与证据
已确认事实
web/app/src/features/auth/pages/SignInPage.tsx当前仍由 Core 固定渲染 identifier/passwordForm;即使已经发现多个登录实例,表单形状仍是一份前端硬编码真值。api/apps/api-server/src/routes/identity/auth.rs的公开实例投影当前只接受auth_type == "password-local",返回flow/sign_in_path/public_options,没有完整 Block,也没有公开注册 route。api/apps/api-server/src/routes/settings/auth_center.rs与api/crates/control-plane/src/auth/settings.rs已支持认证器实例配置和生命周期,但没有认证器拥有的public_ui_block字段或默认区块注入生命周期。web/packages/page-protocol、web/packages/page-runtime、web/packages/block-renderer、web/packages/block-sdk已形成代码区块协议/运行时边界;[Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 正在收敛 canonicalBlockModule + main、typed inputs 与ctx.api.<method>(path, request)API 合同。本 Issue 必须复用其最终合入合同,不能建立 Auth 专用运行时分叉。待验证假设
password-local自行注册可以复用现有用户/成员创建、密码策略与user_auth_identities写入入口,在同一后端事务内完成,而不新增旁路 repository write。ctx.apicontract 能在未登录页面由 Auth host adapter 复用;若最终合同发生实质变化,只调整共享 adapter,不改变“一个完整 Block 是 UI 唯一真值”的产品边界。范围、权限与边界
范围内
config_schema、default_public_ui_block、后端公开变量投影、可供该 Block 通过ctx.api调用的 public Auth API operations。public_ui_block,其值直接使用 canonical 完整代码区块 program/descriptor,不复制出 Auth 专用 AST。public_ui_block;该控件复用已有代码区块编辑/预览组件,不把源码复制进options形成第二真值。GET /api/public/auth/login-instances的职责单一 public projection:只返回已启用实例的公开元数据、完整public_ui_block和后端生成的public_variables;不返回 rawoptions、后台 schema、secret 或第二份接口目录。ctx.apicontract 注入认证器上下文,不依赖 Frontstage page、page document 或 block-code API。/sign-in的单实例、多实例、零实例、加载失败和区块运行失败交互;删除 Core 自有账号密码登录表单以及按认证类型解释 UI 的分支。password-local提供默认完整 Block,覆盖现有登录与可选自行注册;增加自行注册 public Auth API、后端 command、事务写入、错误语义与审计。self_registration_enabled安全默认false。历史非空用户 Block 不覆盖。非目标
self_registration_enabled等变量生成、隐藏或拼接任何认证控件;变量的显示解释只属于认证器 Block。已授权动作
phase:ready后,授权在既定范围内完成前后端、migration、fixture、测试和 QA 闭环。需要额外确认的动作
public_ui_block、删除历史认证/身份数据、放宽现有代码区块 capability/security contract,必须另行确认。方案结论
采用方向与关键取舍
public_ui_block。登录与注册可以同时在该 Block 内,也可以由 Block 自己切换步骤;Core 不拥有第二份登录/注册 UI。authenticators.public_ui_block是公开 UI 内容真值;认证器私有配置是动作许可真值;public_variables是后端从配置生成的只读公开投影,不是另一份持久化配置。default_public_ui_block只是实例初始化种子,不是运行时覆盖真值。新实例复制当前默认值;既有实例保留保存值。ctx.apitransport,不解释认证业务字段。ctx.api.<method>(path, request)合同调用 provider 注册的 public Auth API;后端 route/OpenAPI 和 Auth Center/Provider registry 是接口与授权真值。不得新增ctx.auth.*、接口 descriptor 目录、持久化 binding 或另一套 dispatch 体系。password-local,self_registration_enabled=false是安全默认。Block 可以根据公开变量隐藏注册入口,但后端拒绝才是安全保证。建议合同形状
字段名以领域语义为准;实现不得为了前端展示另起别名:
auth_type可以作为公开元数据返回,但 Core 不得用它选择组件、字段或提交流程。复杂度归属
ctx.api、module 与 renderer 属于共享代码区块协议/runtime。/sign-in只拥有认证器选择、加载态、错误边界和共享 Block mount,不拥有认证业务表单。Domain Matrix
default_public_ui_blockauthenticators.public_ui_blockpublic_variables验收点账本
public_ui_block,后台 schema-driven 表单可编辑、校验、保存并重开;私有配置与公开 Block 无双写password-local默认 Block 在同一 Block 内完成登录,并只在后端注入self_registration_enabled=true时展示自行注册交互authenticator_id或直接调用注册 API,后端在持久化配置为 false、实例禁用或 route/provider 不匹配时均拒绝且不产生用户/identity/session验证与资源边界
test-driven-development固定有限 acceptance matrix:单/多/零实例、登录、注册开/关、变量伪造、实例禁用、secret 投影、无效 Block、历史回填、插件升级不覆盖。public_variables、篡改/跨认证器authenticator_id、调用未知或不匹配的 public Auth route、禁用实例、secret-shaped config、重复注册、并发注册、客户端 role/owner 字段。public_ui_block,回滚必须先导出/保留该用户内容,不能通过降级丢弃。运行时不保留第二份 Core 表单作为“回滚”。qa-evaluation,warning/coverage 与最终 QA 证据写入tmp/test-governance/。停止与重构条件
auth_type、注册开关或其他业务变量解释并生成认证 UI。ctx.apicontract 在实现前发生破坏性变化,导致本 Issue 需要拥有第二套协议;此时回到本 Issue 更新合同,不做前端兼容猜测。生命周期
phase:implementation