Skip to content

feat(spec): declare requiredPermissions on BulkActionDefSchema (#6257) - #6332

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-6257-bulk-action-required-permissions
Aug 7, 2026
Merged

feat(spec): declare requiredPermissions on BulkActionDefSchema (#6257)#6332
baozhoutao merged 1 commit into
mainfrom
claude/issue-6257-bulk-action-required-permissions

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Closes#6257(objectui 侧镜像单:objectstack-ai/objectui#3564)。

改了什么

BulkActionDefSchema 增加可选 requiredPermissions?: string[],语义与 action.requiredPermissions 逐字一致:缺省/空数组恒通过、多项取 AND、客户端解析不出调用者能力时 fail-open(服务端为准)。渲染层一行未动——objectui#3492 起 BulkActionBar 就在按这个键过滤,本单只是补上「合法写法」这一半(enforced ≠ declarable 的镜像缺口)。数据面 def(update/delete)上这个键只管显隐;写入本身仍由数据 API 的对象权限与服务端 hook 授权。

配套(容易漏的 CI 门,均已过):

  • BULK_ACTION_DEF_KEYS did-you-mean 键池加入新键;ActionSchema 的近似拼写别名(permissions/capabilities/requiresPermissions/requiredCapabilities/acl)在本 schema 上同样重命名到位 —— alias-integrity 全绿
  • gen:schema 产物 authorable-surface/ui.json + gen:docs 产物 content/docs/references/ui/bulk-action.mdx 已再生;check:generated 10/10 全绿
  • 手写指南 content/docs/ui/views.mdx 补「Gating a def by capability」一段
  • changeset:@objectstack/spec minor

showcase 夹具(永久保留)

showcase_project.default 补上 #6157 显隐矩阵钉不住的那一格——内联数据面 def 的能力门:

  • relabel_opsupdate + patch,门 showcase.export_data(Ops 持有)
  • purge_restricteddelete,门 showcase.restricted_ops(特意无人持有,见 security/capabilities.ts)

另加 e2e/bulk-capability-gate.spec.ts(playwright),钉住 admin 负向两格:未加门 4 个按钮可见 + 两个带门按钮同时不可见。

真机 UI 实测(console dev :5190 → showcase --fresh :4010,admin 勾选全部 5 行)

步骤admin 授予purge_restricted 声明批量条实测
① baseline仅平台能力['showcase.restricted_ops']4 个未加门按钮;两个带门按钮都不在
② 授予 showcase_ops+showcase.export_data同上Relabel (Ops) 出现;Purge 仍不在
③ 声明翻转同 ②[]Purge (Restricted) 出现
④ 声明还原同 ②['showcase.restricted_ops']Purge 再次消失;Relabel 仍在

同一用户、同一批记录,只动声明或授权——门是活的,admin 也不豁免(能力门读的是授予,不是 admin 位),与 #6257 正文实测结论一致。

测试

  • @objectstack/spec 全量 8500 passed (332 files),含新增 8 条 schema 测试(delete/update+patch/aggregate 三形态、AND、空数组、可选性、非数组拒绝、别名重命名)
  • showcase verify:validate ✓(rc.5 下同样写法硬失败 Unrecognized key(s): requiredPermissions)+ typecheck ✓ + 146 passed (13 files)
  • check:generated 10/10 ✓,changed-files eslint ✓

过程中记录的既有缺口(另开 issue,不在本 PR 修)

hono current-user-endpoints 的独立上下文解析器不读 sys_user_position/sys_position_permission_set,岗位绑定的能力到不了 /me/permissions(上面 ② 一步因此改用 sys_user_permission_set 用户直绑做正向对照)。随后以独立 issue 记录。

🤖 Generated with Claude Code

https://claude.ai/code/session_01PD7tZG1vENc5peMaLQC1uD


Generated by Claude Code

The selection bar has filtered buttons on def.requiredPermissions since
objectui#3492, but the .strict() schema never declared the key, so no
legal metadata could reach that filter — enforced ≠ declarable. The forms
with no workaround were the inline data-plane defs (operation:
'update' | 'delete'): they dispatch no action, so unlike a def promoted
from bulkActions: ['<name>'] they have nothing to inherit a gate from,
and a declarative bulk delete stayed visible to every caller who could
open the list, rejected only per record after the click.
- BulkActionDefSchema: optional requiredPermissions: string[], with
action.requiredPermissions semantics verbatim (absent/empty pass,
entries AND, unresolvable caller capabilities fail open; on a
data-plane def the gate governs visibility only — the write is still
authorized by the data API). ActionSchema's near-miss aliases
(permissions/capabilities/requiresPermissions/requiredCapabilities/acl)
rename onto the key here too, and it joins the did-you-mean pool.
- Regenerated authorable-surface/ui.json and the bulk-action reference
page; new guide paragraph in content/docs/ui/views.mdx.
- Showcase: the two inline gated defs the #6157 matrix could not pin, on
showcase_project.default — relabel_ops (update + patch, gated on the
Ops-held showcase.export_data) and purge_restricted (delete, gated on
the granted-to-nobody showcase.restricted_ops) — plus a playwright spec
pinning the admin-negative cells of the selection bar.
- Schema tests: every def form accepts the gate, empty array and
optionality pinned, non-array rejected, aliases rename.
No renderer change: objectui's BulkActionDef type and BulkActionBar
filter shipped in objectui 11 (objectui#3548).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PD7tZG1vENc5peMaLQC1uD
@vercel

vercelBot commented Aug 7, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 7, 2026 1:56pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

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

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

2 participants

@baozhoutao@claude