Skip to content

api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206

Description

@os-zhuang

越范围发现,记录于 #5189(E7b,PR #5203)实现期,不在该 PR 内修(#5189 的文件面声明为 packages/metadata + packages/spec/src/api/index.ts)。

事实(两条,同一处出水口)

#5189 的正文推断:Studio 写接口对 api 条目「按 ApiEndpointSchema 校验、但不过 E7 的门」。读代码后实情更弱一层:

1. api 根本不在类型注册表里,所以直写路径一道校验都不跑。

  • packages/spec/src/kernel/metadata-plugin.zod.ts 的 DEFAULT_METADATA_TYPE_REGISTRY 里没有 { type: 'api', … } 条目;
  • packages/spec/src/kernel/metadata-type-schemas.ts 的 BUILTIN_METADATA_TYPE_SCHEMAS 里没有 api: ApiEndpointSchema;
  • 于是 packages/metadata-protocol/src/protocol.ts 的 saveMetaItem → resolveOverlaySchema('api', …) → getMetadataTypeSchema('api') 返回 undefined,落进它自己文档写明的那条分支:「未注册 schema 的类型不经校验直接落库」。

也就是说 PUT /meta/api/{name} 可以把任意 JSON 存成一条 api 条目。同时,因为类型不在注册表里,getMetaTypes() 也枚举不到它 —— Studio 的 metadata-admin 既不显示这个类型,也不为它渲染表单。这是同一个缺失的两面。

2. publishPackageDrafts(Studio「全部发布」的真实入径)没有端点门。

protocol.publishPackageDrafts(ADR-0033 / ADR-0067 D2)在提升 draft 前只跑了对象命名空间前缀检查(validateObjectNamespacePrefix,仅 d.type === 'object')。api 类型的 draft 直接提升为 active,不经 E7 的任何一道门 —— 与 #5189 在 MetadataManager.publishPackage 上修掉的是同一形状,另一条路。

影响

安全后果已被 #5189 的第二层兜住。 PR #5203 在匹配器装载期(buildEndpointIndex)对每条存量条目重跑免身份门(不支持子集 / 映射 / policy 含 D6),未过门者被排除出索引并 error 点名。所以经本路径写入的「匿名 + 零配额」端点不会被服务,它答 404 + 一条响亮日志。

因此本单剩下的是两个非安全缺口,但都是本程序在消灭的形状:

建议(不预判)

一处修,两步:

  1. 给 api 补上 DEFAULT_METADATA_TYPE_REGISTRY 条目与 BUILTIN_METADATA_TYPE_SCHEMAS['api'] = ApiEndpointSchema,让 saveMetaItem 的既有 422 路径自动生效;
  2. 在 publishPackageDrafts 里对 api 类型 draft 调用 validateApiEndpointDeclarations —— PR fix(metadata,spec): publish 门兜底 —— publishPackage 接门 + 匹配器装载期拒绝(#5040 E7b) #5203 已把它从 @objectstack/spec/api 导出,命名空间取该 package 已经读到的 pkgNamespace(那段代码就在同一函数里,this.engine?.registry?.getPackage?.(…)?.manifest?.namespace),所以这条路有身份,可以跑全量门,不像 publishPackage 需要调用方传入。

判据仍然只有一份(E7 的门函数),不产生第二套。

注意第 1 步不是纯加性:给一个此前不校验的类型接上 schema,会让既有的越界存量行在下次写入时被 422 拒绝。是否需要一次性的存量体检 / 宽限,留给裁决。

前置

PR #5203(#5189)落 main —— 门函数的公共导出与装载期兜底都在其中。

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions