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

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_definition 的 deleteMany 全部非 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.

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