feat(rest): PUT /meta/:type/:name 要求 manage_metadata 能力 (#6603) - #7027
Merged
os-project-manager merged 5 commits intoAug 9, 2026
Merged
Conversation
…-meta-manage-metadata-gate
既有的 header 转发 / 收据信封 / 错误信封等路由机制单测都以「只有 session」的 调用方驱动 PUT /meta/:type/:name,新门落下后它们先吃 403。给这些 boot 桩加上 manage_metadata,测的仍是原来的机制。 同时在 rest-route-ledger 的该行记下这道门,与 _migrate-stored 的记法一致。
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 12 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-project-manager
marked this pull request as ready for review
August 9, 2026 10:32
This was referenced Aug 9, 2026
os-project-manager
deleted the
claude/issue-6603-put-meta-manage-metadata-gate
branch
August 9, 2026 10:48
os-zhuang
pushed a commit
that referenced
this pull request
Aug 9, 2026
…scope fixture (#7018) `main` moved under this branch: #6603 / PR #7027 put a `manage_metadata` gate in front of `PUT /meta/:type/:name`, ahead of everything this file measures. The fixture's session carried `systemPermissions: []`, so on the PR's merge ref the door answered 403 and the scoping decision was never reached. The capability is now granted explicitly rather than inherited from whatever another suite registered, so the file is order- and shard-independent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PiRUoQkTSBBmpyXBY3cVn2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6603
按 2026-08-08T09:33Z 维护者裁决(Option B —— 拒绝写入,评论
5225531464)与 2026-08-09T05:39Z 复核(5229988826)实施。四条路线不再论证。1. 调用方普查(裁决采纳的实施第一步)
搜索面:
objectstack与objectui两仓,saveMetaItem/saveItem/saveMetadataItem/method: 'PUT'交叉meta,覆盖.ts/.tsx/.js/.vue,排除node_modules与dist。meta.saveItempackages/client/src/index.ts:698、:4963os meta registerpackages/cli/src/commands/meta/register.ts:76apps/console/src/services/MetadataService.ts:139/149/164/178/210、components/schema/objectDetailWidgets.tsx:204/341/360apps/console/src/pages/developer/PublicFormsPage.tsx:190/253(view)packages/plugin-designer/src/pages/{CreateAppPage,EditAppPage}.tsx(app)packages/app-shell/src/services/MetadataService.ts:139/149、hooks/useNavigationSync.ts:216packages/qa/dogfood/test/dashboard-designer-roundtrip.dogfood.test.ts:54stack.signIn()= dev admin看了但没有找到调用方的地方(同样是证据):
apps/、examples/、core/全部无/metaPUT 调用;Setup 应用的导航贡献(packages/platform-objects/src/apps/setup-nav.contributions.ts)只有数据面object项与只读developer:packages,没有任何/meta写入面;packages/metadata/src/loaders/remote-loader.ts:125的RemoteLoader.save()虽从packages/metadata/src/index.ts:19导出,但仓内无消费者(库面,非调用方);packages/runtime/src/domains/packages.ts:246是进程内直调protocol.saveMetaItem,不经这条路由。为什么这些都在门内 —— 关键测量:所有元数据编写面都在 Studio 应用里(
packages/platform-objects/src/apps/studio.app.ts:54,requiredPermissions: ['studio.access']),而仓内唯一带studio.access的权限集是admin_full_access,它同时带manage_metadata(packages/plugins/plugin-security/src/objects/default-permission-sets.ts:120-129)。另注:objectui 的导航同步已经把这条路由的 403 当作正常可处理情况(
isNavigationSyncableApp的注释:写保护应用「would 403 every PUT — skip them instead of spraying failure toasts」),所以即便有边角调用方吃到 403,也不是崩溃路径。2.⚠️ 必须写明:本 PR 建立的不是裁决理由里那句话
裁决的理由句是「能写 schema 的人就是能看见完整 schema 的人」。本 PR 建立的是「能写者需持
manage_metadata」—— 这两句不是同一个集合,不变量本身没有被建立。OBJECT_SCHEMA_MASK_EXEMPT_CAPABILITIES = ['studio.access','setup.access'](packages/metadata-core/src/object-schema-fls.ts:72),不含manage_metadata;organization_admin(['manage_org_users','setup.access','setup.write'])是 D4 豁免、从来没有往返丢失风险,却被这道门 403;manage_metadata的调用方能写,但读仍被掩码,它自己的往返仍会丢字段;admin_full_access上重合 —— 让不变量在默认部署里成立的是权限集的巧合,不是这道门。门照裁决落
manage_metadata,不动(它在第二条理由上独立成立:关掉「任何已认证会话都能覆写任意 schema」这个与掩码无关的旧洞)。这条差已按实测钉进测试矩阵,并另立 #7020 记录,不在本 PR 替维护者选对齐方向。3. 真红:先写下预测,再跑
预测写在实施前(方向:RED,三条断言应同时翻)。实测(去掉门,同一往返,真实路由 + 真实内存库):
加门后:
403+{ error: { code: 'FORBIDDEN' } },saveMetaItem零调用,库中四个字段完好、label未变。整份新测试在删门后 6/12 转红,方向与预测一致,无反转、无「诊断增多」情形。钉的是丢失本身,不只是状态码 —— 断言直接读库(
storedFields()),因为「先写了再 403」正是最值得防的失败形态,只断言状态码看不见它。拒绝类断言一律同时断code与status(ADR-0112 信封);这条路由是发送而非抛出,toThrow形状的断言在这里分不清「拒绝但信封错」与「根本没拒绝」。豁免调用方:⚠️ 该用例加门前后都绿,所以它是护栏,不是证据 —— 按要求明说。
admin_full_access形状的调用方往返无损(读不被掩码、写 200、库中四字段完好)。4.⚠️ 本 PR 关的是一扇门,缺陷没有被关闭
已实测:同一次 GET → 改 → PUT 的数据丢失,在本门落下后仍可经复合名路由
PUT /meta/:type/:section/:name原样复现(compound GET fields : id, name→compound PUT status : 200→STORE after PUT : id, name)。此外 dispatcher 自己的/metaPUT(packages/runtime/src/domains/meta.ts:264)与无门的DELETE /meta/:type/:name同形。三处同族出口按 PD #10 归档为 #7019,不在本 PR 修 —— 区域纪律:本卡与 #6599 / #6920 并发占用同一文件的不同区域。#7019 正文已写明「#6603 落地后缺陷仍可复现,只是换一扇门」,复合名那条是实测,dispatcher 与 DELETE 两条明标未实测、须实测,没有用静态观察冒充实测。
5. 改了什么
packages/rest/src/rest-server.ts——PUT /meta/:type/:name处理器开头加能力门,复用POST /meta/_migrate-stored的同一机制(!ctx?.isSystem && !held.has('manage_metadata')→ 403FORBIDDEN),不另造第二种写法。门在resolveProtocol之前,所以未授权调用方无法用 501-vs-200 探测内核能力,且拒绝时什么都没写。packages/rest/src/meta-item-save-capability-gate.test.ts—— 新建文件(不碰任何共享测试文件),12 例。packages/rest/src/rest-route-ledger.ts—— 该行补note,与_migrate-stored的记法一致。.changeset/meta-save-manage-metadata-gate.md——minor,写明谁开始吃 403、需要什么(给权限集加manage_metadata),以及尚未关闭的部分。5.1 另有 5 个既有测试文件各改 1–4 行 —— 为什么必须改
rest.test.ts(4 处)、rest-meta-save-receipt-envelope.test.ts、rest-unknown-object-heuristic.test.ts、rest-5xx-message-sanitization.test.ts、rest-4xx-message-truncation.test.ts。这不是「顺手修了几个测试」,是同一处行为变更的必然连带。 这些用例测的是本路由的机制(If-Match 转发、保存收据信封、4xx 截断与 5xx 脱敏),但它们的 boot 桩把
resolveExecCtx打成只带一个userId的调用方 —— 也就是把「只要有 session 就能写元数据」当作既成前提。而这个前提正是本 PR 要消灭的东西。门落下后,这些请求在到达被测机制之前就先被 403 拦住,断言全部失效:不改它们,PR 一落地@objectstack/rest即红(实测:14 例失败)。因此改动只给 boot 桩补上
systemPermissions: ['manage_metadata'],让调用方合法地到达被测代码;被测机制、断言、期望值一字未动。每处都留了一行说明:// [#6603] this route now demands manage_metadata — an authoring capability, not just a session.6. 本地验证
pnpm --filter @objectstack/rest test→ 74 文件 / 1154 例全绿(先建了@objectstack/types等依赖)pnpm --filter @objectstack/rest typecheck→ 通过check:route-envelope/check:error-code-casing/check:empty-changeset/check:meta-type-normalized/check:spec-parsed-alias/check:nul-bytes→ 全部 PASSESLint(含更多族门)与TypeScript Type Check(含check:api-surface)本地不覆盖,交 PM。