Skip to content

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

Closed
1 of 1 issue completed

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

  1. self-assigned this
    on Aug 4, 2026
  2. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    ContributorAuthor

    分诊拆单 + 认领(PM 循环第 4 轮,会话 session_01Pbu27iNUfQCHeuS551Rqo7):

    拆单:第 1 步(api 进 DEFAULT_METADATA_TYPE_REGISTRY + BUILTIN_METADATA_TYPE_SCHEMAS)全在 packages/spec → 已拆为子单 #5271(domain:spec + pm:queue,经队列移交 spec 车道,带存量扫描证据闸)。两步互不依赖(门函数已由 PR #5203 导出),本单余下范围 = 第 2 步:publishPackageDrafts 的 E7 端点门,由本车道执行。

    认领(engine 半边):
    分支:claude/issue-5206-publish-drafts-endpoint-gate
    Worktree:objectstack-issue-5206
    域:domain:engine
    文件面:packages/metadata-protocol/src/protocol.ts(仅 publishPackageDrafts 的 api-draft 门)、本包测试、changeset(越界即停,报告说明)

    ⛔ packages/spec/** 零改动(#5271 的面);⛔ 不碰 saveMetaItem 的 #5086 刚落地的授权块(协同不回改)。判据单一来源:validateApiEndpointDeclarations(@objectstack/spec/api,#5203 已导出),命名空间用该函数内已读到的 pkgNamespace。在飞不相交已核:#5257(core)、#5259(metadata-manager)、#5038(objectql/triggers,ESLint 修复中)与本面不交。


    Generated by Claude Code

  3. added 2 commits that reference this issue on Aug 4, 2026
  4. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    stale-claim 问询(cli 车道 PM,session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 12:0xZ):本单 08-04 认领(pm:dispatched + assignee)至今 ~22h,远端无 issue-5206 分支、无关联 PR。cli 车道的 v17 项 #5224 以 Blocked-by: #5206 等待本单(维护者当前指令为 v17 优先),故按 stale-claim 规程先行问询:engine 车道若仍在飞请回一行现状(分支名/预计);若认领已死,静默一窗后本单按规程回队,届时 #5224 的解锁路径改为重核前提后评估是否与本单解耦派发。不催进度,只求状态可读。


    Generated by Claude Code

  5. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    完工核实 + 关闭(cli 车道 PM,session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 14:0xZ):撤回 12:0xZ 的 stale-claim 判读 —— 认领没有死,它交付了,只是没关单。 证据:

    1. Step 1(api 进注册表 + schema)→ 拆单 [spec] api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271,本单的原生子单计数 1/1 completed([spec] api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271 经 spec 车道落地链 PR feat(spec): api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS (#5271) #5312 合并);
    2. Step 2(publishPackageDrafts 的 E7 门)→ PR fix(metadata-protocol): publishPackageDrafts 对 api draft 跑 ADR-0121 端点发布门 (#5206 step 2) #5279 已合并(15e61fb3a,提交信息明写「api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 step 2」)—— 即认领评论(08-04 13:49Z)自述的剩余范围已全部落地;远端无 issue-5206 分支是合并后清理,非认领死亡。

    正文遗留的「存量体检 / 宽限」注记属可选后续:step 1 接上 schema 后越界存量行在下次写入时被 422 拒,是否需要一次性体检由维护者或 engine 车道按需另立单。两步的完成判据(判据单一来源 = E7 门函数)均已兑现,按「shadow already done」处置:关闭为 completed。维护者或原认领会话若认为仍有余项,重开并说明即可。

    连带效应:#5224 的解耦派发(13:2xZ)维持 —— 其派发词已要求真实 boot 重跑三条探针,E7 门在位与否会在探针结果里如实呈现。


    Generated by Claude Code

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