Skip to content

refactor(metadata-core): 回收 sys_view_definition 的等价全开白名单 + 派生契约端到端实测 (#3026) - #3772

Merged
os-zhuang merged 1 commit into
mainfrom
claude/ui-button-api-whitelist-consistency-8ftbmc
Jul 28, 2026
Merged

refactor(metadata-core): 回收 sys_view_definition 的等价全开白名单 + 派生契约端到端实测 (#3026)#3772
os-zhuang merged 1 commit into
mainfrom
claude/ui-button-api-whitelist-consistency-8ftbmc

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

改动

sys_view_definition 删除 apiMethods 声明(#3745 把它补成六原语后,已与"无白名单"等价),并重写其测试。

零行为变化:undefined 解析为 unrestricted,其有效操作集与"restricted 且持有全部六原语"完全相同(resolveEffectiveApiMethods 对两者走同一张 computeOperations,未映射的自定义 action 两种模式下也都放行)。

为什么这个对象删、#3745 的七个不删

不是双标,是有没有兜底可保:

reconcileManagedApiMethods(ADR-0103 D3)在 apiMethods 非数组时早退——

const methods = (schema as any).enable?.apiMethods;
if (!Array.isArray(methods) || methods.length === 0) return schema;

所以对 managedBy 对象,删掉白名单会连带关掉 managed-write 兜底(#3745 那七个都是 managedBy,故保留显式数组)。sys_view_definition 没有 managedBy → D3 本就不适用 → 没有任何东西argues for保留声明 → 按 #3543 审计惯例(等价全开的样板直接删)回收。

测试改为双向守卫:白名单必须保持缺席(重新加回"全六个"是无操作且不再跟踪未来原语,加回更窄的则会静默关掉今天开着的路由),且 resolver 必须报 unrestricted;另加一条钉住它派生得到的数据可携带性动词。

派生契约端到端实测(本 PR 的另一半)

之前 #3745 / #3755 的结论都来自单测。这次按仓内 dogfood-verification 流程起真实服务(showcase + --fresh --seed-admin,独占端口 38977),以种子管理员登录后打真实 REST 面,14/14 通过:

检查 结果
/me/permissions 下发 per-object apiOperations 57 条,样本 sys_user → [get,list,update,bulk,aggregate,history,search,import,export]
每个非通配符条目都被注解 57/57(* 按设计跳过)
sys_permission_set effective 含 bulk #3745 的效果在真实下发里可见
sys_business_unit export(白名单里从未声明过 export) 200 —— export ⊆ list 派生成立
sys_business_unit import(从未声明过 import) 非 405(400 = 空 rows 校验)—— import ⊆ create∨update 成立
sys_permission_set / sys_position / sys_user_position / sys_view_definitiondeleteMany 全部非 405(403/400,即请求已越过 API 门禁抵达引擎鉴权/校验层)—— 正是 #3745 与本 PR 要的效果
sys_api_key(白名单 [get,list])export 200(派生自 list)
sys_api_key create / import / deleteMany 405 / 405 / 405 —— 门禁的另一侧仍然关着
sys_oauth_consent(apiEnabled:false) 404 —— 404 优先于 405 的两轴顺序成立

过程中有一条断言先报 FAIL(sys_business_unit/me/permissions 里查不到 apiOperations),按 dogfood 流程当作假设去证伪后确认是我的断言写错了:该对象整个条目就不在 map 里(map 只含调用方权限集显式命名的对象),而契约对"apiOperations 缺失 → 前端回退现行为"是明文规定,服务端也确实放行(上表 export 200 / import 非 405)。断言已改为"每个非通配符条目都必须被注解",重跑 14/14。

未覆盖:按钮显隐那一半在 objectui 仓,packages/console/dist 需要从该仓构建;本会话没有 objectui 接入,所以前端渲染未做浏览器验证,上表全部是服务端权威行为。

验证

changeset:@objectstack/metadata-core patch。

关联

#3026#3745(补 bulk 的那批对象)、#3755(防复发棘轮)、#3543(P2 审计惯例)、ADR-0103 D3


Generated by Claude Code

…s whitelist (#3026)

#3745 completed this object's boilerplate CRUD-five whitelist to all six
primitives so its batch routes stopped 405-ing. A whitelist naming all six is
equivalent to no whitelist — except it stops tracking primitives the enum grows
later — so the #3543 audit rule ("delete the equivalent-to-open boilerplate")
applies and the declaration goes.

No behaviour change: `undefined` resolves to `unrestricted`, whose effective
operation set is identical to `restricted` holding all six primitives.

Removing it is safe HERE specifically because the object has no `managedBy`:
`reconcileManagedApiMethods` (ADR-0103 D3) early-returns on a non-array
`apiMethods`, so for a managed object an absent whitelist would take the
managed-write backstop with it. That is why the RBAC objects reclaimed by #3745
keep their explicit arrays and this one does not — the two treatments are not
inconsistent, they follow the presence of a backstop.

The object's test is rewritten to guard the new shape in both directions
(whitelist must stay absent; the resolver must report `unrestricted`) and to
pin the derived verbs the contract grants it.

Verified end-to-end against a real running server (showcase, seeded admin), not
only by unit test: 14/14 checks over the live REST surface, including this
object's deleteMany reaching the engine rather than the API gate, derived
import/export on a whitelist-free object, a tightened object still answering
405, and apiEnabled:false still answering 404 ahead of the method gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CkdX2VCuKfcsFBbvtATe7V
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 28, 2026 4:02am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/s labels Jul 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-core.

2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-core)
  • content/docs/releases/v12.mdx (via @objectstack/metadata-core)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 28, 2026 04:17
@os-zhuang
os-zhuang merged commit c073b8c into main Jul 28, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/ui-button-api-whitelist-consistency-8ftbmc branch July 28, 2026 04:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants