Repository navigation
Commit 1539aad
docs(spec): the allowExport comment and permission docs say no built-in admin set grants export (#26935)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBPgPimeeEd4Cs2XAg5w5WtX)_
Fixes #26720
Clause-②: no
Metadata-protocol: none
Skills-docs: none — no `skills/**` file says the built-in admin sets
grant export (grep over `skills/**` hits only the two reference-index
lines that list `permission.zod.ts`); the two docs pages that said it
are corrected here.
## 维护者速读
- 改了什么:三处文字(`permission.zod.ts` 里 `allowExport` 的注释、「Permission
sets」与「Permissions matrix」两个文档页)原说内置管理员权限集带导出权限,现改为实情:不带,并写明怎么授予。
- 为什么改:实际出厂默认 `admin_full_access` / `organization_admin` 都不含
`allowExport`,管理员看不到导出按钮、导出接口回 403 `EXPORT_NOT_PERMITTED`,文档却说有,误导管理员和
AI 作者。
- 风险与回滚:纯文字,零行为变化,出厂权限集一行未动;回滚即 revert 本 PR。
-
先看:`content/docs/permissions/permission-sets.mdx`(用户最常读的一句)、`content/docs/permissions/permissions-matrix.mdx`、`packages/spec/src/security/permission.zod.ts`(只改
JSDoc,`.describe()` 原本就对)。
- 两分钟验证:`git grep -n -E 'carry the grant explicitly|carry .allowExport:
true. explicitly|therefore carry' -- packages/spec/src/security
content/docs/permissions`,预期零命中(main 上是 3 处)。
- 需要你做的:无,席位落地。
## What changes
- `packages/spec/src/security/permission.zod.ts`, the `allowExport`
JSDoc: "The built-in admin sets carry the grant explicitly instead." is
replaced by: the built-in admin sets (`admin_full_access`,
`organization_admin`) do not carry it, an admin holding only those sets
is refused export, and export is granted by binding the admin to an app
or environment permission set that names each object with `allowRead:
true, allowExport: true`. The `.describe()` string was already true (it
never mentions the admin sets), so it is unchanged and no reference page
regenerates.
- `content/docs/permissions/permission-sets.mdx`: "The built-in
`admin_full_access` and `organization_admin` sets carry `allowExport:
true` explicitly; remove that line to get the separation." becomes: no
built-in set carries `allowExport` (admin, org admin, member), what the
admin sees (no Export control, `403 EXPORT_NOT_PERMITTED`), and how to
grant it.
- `content/docs/permissions/permissions-matrix.mdx`: "The built-in
`admin_full_access` / `organization_admin` sets therefore carry
`allowExport: true` alongside their super-user bits." becomes the same
correction.
- `.changeset/26720-admin-export-docs.md`: `@objectstack/spec` patch
(the JSDoc ships in the package's `src`).
The other JSDoc the order named (`objectPermissionGrants`, the
conjunction note at ~:248) is true as written and is left alone.
## Why
What each built-in set actually grants for export, on `origin/main`
8074feb:
- `admin_full_access`: spreads `ADMIN_FULL_ACCESS_CAPABILITIES`
(`packages/spec/src/identity/eval-user.zod.ts:115`), whose `'*'` entry
has read/create/edit/delete plus `viewAllRecords` / `modifyAllRecords`
and no `allowExport` (removed by the 2026-08-15 maintainer ruling; the
migration entry is `18.admin-export-wildcard-removed`).
- `organization_admin` (and the derived `organization_admin_no_bypass`):
`'*'` with the same bits and no `allowExport`
(`default-permission-sets.ts:391`).
- `member_default`: no wildcard, no `allowExport`
(`default-permission-sets.ts:638`).
- `viewer_readonly`: `'*'` read only, no `allowExport`.
The gate that decides it: `resolveUserExportAllowed`
(`packages/plugins/plugin-security/src/permission-evaluator.ts:205`) is
true only when some held set resolves `allowExport === true` for the
object, and the REST export door (`packages/rest/src/rest-server.ts`,
`enforceExportPermission`) answers `403 EXPORT_NOT_PERMITTED` otherwise.
So the seeded admin's 403 is the shipped behaviour, and per triage the
default stays. The corrected text now gives the reader the way in: an
app or environment set with `allowExport: true` per object (a set
carrying `allowExport` cannot be bound to the `everyone` / `guest`
anchors, as the same page already says).
Not edited, on purpose: `18.admin-export-wildcard-removed.ts` quotes the
old sentence as history of what upgraders were told, and the QA
checklist JSON already describes the shipped behaviour.
## Acceptance notes
None.
## Verification
Run on head d8ef777.
<details><summary>Spec tests and typecheck (under
os-verify-lock)</summary>
`pnpm --filter @objectstack/spec test && pnpm --filter @objectstack/spec
typecheck`: VERDICT command-exit 0. Test Files 738 passed (738), Tests
22101 passed, 1 todo.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 96 commands. 93 exit 0, including
`check:doc-authoring`, `check-adr-0087-registration --base origin/main`,
`check:docs`, `check:doc-anchors`, and (after building
`@objectstack/lint`, which they import) `check:doc-security-posture`,
`check:doc-formula-expressions` and `check:docs-transcript-drift`. 3
exit 3, PREREQUISITE NOT MET (they need a full repo build, nothing was
measured): `spec check:skill-examples`, `check:dual-build-cjs-loads`,
`check:lean-entry-closure`; CI runs them. `--ran` reconciliation: 96
derived, 93 run, 3 NOT-MEASURED, 0 UNRUN.
</details>
## Human Minimum
Each item is one rule from
[CONTRIBUTING.md › Human
Minimum](https://github.com/objectstack-ai/objectstack/blob/main/CONTRIBUTING.md#human-minimum),
which links the AGENTS.md text that states it.
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
- [x] 2. Every name I added uses the casing for its kind.
- [ ] 3. No formatter ran; `pnpm lint` passes. (No formatter ran. `pnpm
lint` was not run locally: the diff is a comment and two prose pages, so
CI's lint decides.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (No `.describe()` changed, so nothing
regenerates.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English. (The 维护者速读 block is in
Chinese by the repo's dispatch rule.)
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01WGufzebdjuVyrMYo5JVUJP
Co-authored-by: Claude <noreply@anthropic.com>1 parent e4ba846 commit 1539aad
4 files changed
Lines changed: 24 additions & 7 deletions
File tree
- .changeset
- content/docs/permissions
- packages/spec/src/security
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
89 | 91 | | |
90 | 92 | | |
91 | 93 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
45 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
46 | 48 | | |
47 | 49 | | |
48 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
498 | 498 | | |
499 | 499 | | |
500 | 500 | | |
501 | | - | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
502 | 505 | | |
503 | 506 | | |
504 | 507 | | |
| |||
0 commit comments