#3391 的独立 follow-up ①。 ## 问题 权限集(`packages/spec/src/security/permission.zod.ts`,`ObjectPermissionSchema`)目前**没有用户级 import/export 位**。P1 的 export 派生自 `list`(`export ⊆ list`),意味着「任何能 list 的用户即可一键全表导出」——这与全球主流平台不符:Salesforce "Export Reports"、Dynamics "Export to Excel"、NetSuite "Export Lists"、SAP `S_GUI` 61 都有独立的导出权限轴。 ## 方案 P1 已**预留槽**,接入即零契约变更: - `@objectstack/spec/data` `resolveEffectiveApiMethods(enable, { userExportAllowed })` 的 `ResolveApiOptions.userExportAllowed`(本期恒 `true`);`export` 派生 = `list ∧ userExportAllowed`。 - [x] 在权限集 schema 增加用户级 export(必要时 import)位。(#3553) - [x] 解析 `/me/permissions` 时按用户权限计算 `userExportAllowed`,传入 resolver;`export` 随之从有效集里去留。(#3553) - [x] **服务端真正执法** —— 见下方补充。(#3709) - [x] 前端已消费 `apiOperations`(objectui#2823),无需再改前端契约。 ## 影响 接上后,不再是「能 list 即能导出」;默认策略需设计(建议默认开、由权限集收紧,保持向后兼容)。 关联:#3391、#3498(预留 `userExportAllowed`)、objectui#2823。 --- ## 补充:#3553 之后仍缺执法层,由 #3709 补齐 #3553 落地后清单看起来齐了,但只做了**可见的那一半**:`allowExport` 位、`/me/permissions` 注解、前端隐藏 Export 按钮都在,**服务端一行都没有拦**。 因为 `export ⊆ list`,导出路由 `GET /data/:object/export` 经 `findData` 流式读,引擎中间件看到的是一次普通 `find`,只按 `allowRead` 放行 —— 全仓没有任何代码路径读过 `allowExport`。所以 `allowExport: false` 的用户直接 `curl` 仍能拉走整表,本 issue「不再是能 list 即能导出」的目标并未成立(AGENTS.md 铁律 #10 的 `declared ≠ enforced`)。 #3709 补上了调用点:evaluator 的 `export` 判定(读权限 ∧ 未被显式拒绝)、`ISecurityService.canExport`(fail closed)、导出路由在取第一个 chunk 之前返回 403 `EXPORT_NOT_PERMITTED`,以及 `'*'` 通配符回落对齐,消除客户端/服务端分歧。 **遗留(不属于本 issue 范围):** `plugin-reports` 的定时报表把 CSV 作为邮件附件发出,同样不经过本轴 —— `allowExport:false` 的用户仍可建报表定时发给自己。已开 **#3710** 单独跟进。
Activity
chore(spec): classify permission.objects.allowExport in liveness regi…
feat(spec,hono): user-level export permission axis (#3544) (#3553)
feat(security): 让用户级 export 权限轴真正在服务端生效 (#3544) (#3709)
feat(security)!: export 权限轴改为 opt-in,接入 explain,并堵上报表侧门 (#3544, #3710) (
feat(spec,plugin-security): export the kernel platform-admin capabili…
feat(spec,plugin-security): export the kernel platform-admin capabili…
docs(spec): the user-level export slot is a real opt-in grant, not "a…
fix(plugin-hono-server): /auth/me/permissions speaks for an unrestric…
docs(spec): the user-level export slot is a real opt-in grant, not "a…
fix(core): apiOperations offers only what the REST door serves — noth…
test(spec): security, ai, identity, integration, migrations, marketpl…