|
2 | 2 |
|
3 | 3 | import { z } from 'zod'; |
4 | 4 | import { lazySchema } from '../shared/lazy-schema'; |
| 5 | +import type { PermissionSet } from '../security/permission.zod'; |
5 | 6 |
|
6 | 7 | /** |
7 | 8 | * EvalUser — the one user-context contract (ADR-0068 D1). |
@@ -59,6 +60,72 @@ export type BuiltinIdentityName = (typeof BUILTIN_IDENTITY_NAMES)[number]; |
59 | 60 | */ |
60 | 61 | export const ADMIN_FULL_ACCESS = 'admin_full_access'; |
61 | 62 |
|
| 63 | +/** |
| 64 | + * [#11663 Choice 6A] The kernel platform-admin CAPABILITY DECLARATION — the |
| 65 | + * capability content (object grants + `systemPermissions`) of the |
| 66 | + * {@link ADMIN_FULL_ACCESS} permission set, declared ONCE here in the contract |
| 67 | + * package so exactly one copy exists: |
| 68 | + * |
| 69 | + * - `@objectstack/plugin-security`'s `admin_full_access` declaration |
| 70 | + * (`objects/default-permission-sets.ts`) spreads this object into its |
| 71 | + * `PermissionSetSchema.parse({ name, label, ... })` entry — the metadata |
| 72 | + * declaration that wins at enforcement time. |
| 73 | + * - `@objectstack/core`'s platform-admin derivation (the re-anchor's L2 leg) |
| 74 | + * reads the same list to fill `grants.systemPermissions`, so the derived |
| 75 | + * envelope and the declared set can never drift apart. |
| 76 | + * |
| 77 | + * Shape note: these are the two capability-bearing fields of the authored |
| 78 | + * permission-set contract (`PermissionSetSchema`); `name`/`label` remain with |
| 79 | + * the declaring package. Behaviour-neutral by construction — the values are |
| 80 | + * byte-for-byte the ones previously inlined in plugin-security, pinned by |
| 81 | + * `objects/default-permission-sets.test.ts` there. |
| 82 | + */ |
| 83 | +export const ADMIN_FULL_ACCESS_CAPABILITIES: Pick<PermissionSet, 'objects' | 'systemPermissions'> = { |
| 84 | + objects: { |
| 85 | + '*': { |
| 86 | + allowRead: true, |
| 87 | + allowCreate: true, |
| 88 | + allowEdit: true, |
| 89 | + allowDelete: true, |
| 90 | + viewAllRecords: true, |
| 91 | + modifyAllRecords: true, |
| 92 | + // [#3544] Export is an OPT-IN grant and is deliberately NOT implied by |
| 93 | + // the super-user bits — "may see all data" and "may take a bulk copy of |
| 94 | + // it" are separable on purpose (SAP S_GUI 61 / segregation of duties). |
| 95 | + // |
| 96 | + // [#8681] NO `allowExport` HERE, and it is not an oversight. This set |
| 97 | + // shipped `allowExport: true` on the wildcard through 17.0.0 GA, which |
| 98 | + // made the export axis undeniable for anyone holding it: an app could |
| 99 | + // declare an object exportable by nobody and the platform exported it |
| 100 | + // anyway, with no supported opt-out (editing a code-package set answers |
| 101 | + // `403 [not_overridable]`, and the admin holds no app-authored set to |
| 102 | + // put the per-object `false` into). Measured on GA, hotcrm#1152: an org |
| 103 | + // owner exported three objects no app set grants export on, 200 with |
| 104 | + // full rows. Maintainer ruling (2026-08-15) removes the grant — the |
| 105 | + // export axis's half of #5491, which removed `member_default`'s CRUD |
| 106 | + // wildcard for the identical "a wildcard nobody can get under" reason. |
| 107 | + // |
| 108 | + // ⛔ Do not restore it, and do not restore a NARROWER wildcard either — |
| 109 | + // "which platform objects should ship an explicit export grant" is an |
| 110 | + // OPEN question the ruling deliberately left to a separate decision, and |
| 111 | + // any `'*'` export grant here re-opens the hole for every object the |
| 112 | + // platform does not know about. Where admin export is intended, grant |
| 113 | + // `allowExport` per object in an APP permission set. |
| 114 | + }, |
| 115 | + }, |
| 116 | + systemPermissions: [ |
| 117 | + 'manage_users', |
| 118 | + 'manage_metadata', |
| 119 | + 'manage_platform_settings', |
| 120 | + // [ADR-0111 D9] Sharing administration — gates the sharing-rule surface |
| 121 | + // and (in the DEPTH extension) non-owner share management. |
| 122 | + 'manage_sharing', |
| 123 | + 'setup.access', |
| 124 | + 'setup.write', |
| 125 | + 'studio.access', |
| 126 | + ], |
| 127 | +}; |
| 128 | + |
62 | 129 | /** |
63 | 130 | * Permission-set name whose grant is the source of truth for the `TENANT_ADMIN` |
64 | 131 | * posture rung (ADR-0095 D3). Auto-granted (org-scoped) to every `sys_member` |
|
0 commit comments