Skip to content

feat(spec,hono): user-level export permission axis (#3544) - #3553

Merged
os-zhuang merged 2 commits into
mainfrom
claude/complete-scheduled-development-xqcwch
Jul 27, 2026
Merged

feat(spec,hono): user-level export permission axis (#3544)#3553
os-zhuang merged 2 commits into
mainfrom
claude/complete-scheduled-development-xqcwch

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景

#3391 的 follow-up ①(见 #3544)。P1 里 export 派生自 list(export ⊆ list),意味着「任何能 list 的用户即可一键全表导出」——与 Salesforce "Export Reports" / Dynamics "Export to Excel" / NetSuite "Export Lists" / SAP S_GUI 61 的独立导出权限轴不符。本 PR 接入 P1 预留的 userExportAllowed,把 export 变成用户级可门控的操作。

改动

  • specObjectPermissionSchema 新增可选 allowExport 位。故意不设默认值 —— 是向后兼容的 opt-out:
    • 未设(undefined)→ 继承 read(保持今天「能 list 即能导出」),加这个 key 对现有权限集零影响;
    • false → 保留读、但禁止导出;
    • true → 显式授予。
  • plugin-hono-serverannotateEffectiveApiOperations 从解析后的 per-object 权限推导 userExportAllowed = allowExport !== false,传入 resolveEffectiveApiMethods(export ⊆ list ∧ userExportAllowed)。当该轴把 export 从本来全开的对象移除时,现在会给该对象下发注解(effective 集去掉 export),前端据此隐藏 Export 按钮;export 仍允许的全开对象保持不注解(前端 default-allow)。
  • 重生成 content/docs/references/security/permission.mdx

契约 / 兼容

对派生表与前端零契约变更(前端已消费 effective apiOperations,objectui#2823)。现有权限集(无 allowExport)处处保持今天行为。默认取 opt-out(而非 opt-in)以保证零 breaking;若要改为严格 opt-in,建议放到 P2(#3543)窗口一并做。

测试

  • spec:allowExport 可选、无默认(未设 = undefined;true/false 正常解析);api-derivationuserExportAllowed=false 用例已覆盖 resolver 侧。
  • hono:allowExport:false 从收紧对象移除 export;从全开对象强制注解移除 export 而保留其余;未设则继承 read(全开对象仍不注解);true 保留 export。
  • 全量:spec 6842 / hono 111 通过;type-check + check:docs + check:api-surface 全绿。

关联

🤖 Generated with Claude Code

https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH


Generated by Claude Code

Make `export` a user-gated operation, not just "anyone who can list", wiring the
`userExportAllowed` slot reserved in #3391 P1.
- spec: ObjectPermissionSchema gains an optional `allowExport` bit — no default,
so it is a backward-compatible opt-out: unset inherits read (today's
can-list ⇒ can-export), false denies export while keeping read, true grants.
- plugin-hono-server: annotateEffectiveApiOperations derives
userExportAllowed = allowExport !== false and threads it into
resolveEffectiveApiMethods (export ⊆ list ∧ userExportAllowed). When the axis
removes export from an otherwise-open object, that object is now annotated
(effective set minus export) so the client hides Export; an open object with
export still allowed stays unannotated (default-allow).
- Regenerated content/docs/references/security/permission.mdx.
Zero change to the derivation table or the frontend (already consumes the
effective apiOperations). Existing permission sets keep today's behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH
@vercel

vercelBot commented Jul 27, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specBuildingBuildingPreview, CommentJul 27, 2026 4:21am
1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredJul 27, 2026 4:21am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-hono-server, @objectstack/spec.

105 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 packages/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 packages/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/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/plugin-hono-server, @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 packages/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/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 packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/permissions/authentication.mdx(via @objectstack/plugin-hono-server)
  • 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/plugin-hono-server, @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/plugin-hono-server, @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/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/kernel/runtime-capabilities.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/plugin-hono-server, @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/plugin-hono-server, @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)
  • content/docs/ui/actions.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/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.

…stry (#3544)
The new allowExport property on ObjectPermissionSchema is a governed-type
property and must carry a liveness classification. It is `live` — enforced
end-to-end via the hono /me/permissions annotate (userExportAllowed) → effective
apiOperations → REST export gate + UI. Fixes the "Spec property liveness" gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH
@os-zhuang
os-zhuang marked this pull request as ready for review July 27, 2026 04:44
@os-zhuang
os-zhuang merged commit d8c4957 into mainJul 27, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/complete-scheduled-development-xqcwch branch July 27, 2026 04:44
os-zhuang pushed a commit that referenced this pull request Jul 27, 2026
The hand-written object-permission-bits table never picked up `allowExport`
(#3553 only regenerated the auto-gen reference). Now that the bit is actually
enforced server-side, document what it is: the tri-state, the most-permissive
merge with an explicit deny in the middle, that it narrows read and never
widens it, and that the 403 and the hidden client button are one decision.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDbwCy9Jrc1chhR2vnAUos
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude