You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 5f35aff
Browse filesBrowse the repository at this point in the historyBrowse files
feat: an `external` organization role for portal users, who read their own identity rows and reach data only through explicit grants
10
+
11
+
Clause-②: yes (widening)
12
+
Metadata-protocol: added
13
+
14
+
A supplier's or a customer's portal user can now be added to an organization with the `external` role. It is a member of the organization (it has a `sys_member` row) but a separate population: before this change such a user had to be a plain `member`, and the member baseline's fellow-member scope let it read every employee and every other supplier's users through `GET /data/sys_user`.
15
+
16
+
-**`@objectstack/spec`:**`MEMBERSHIP_ROLE_EXTERNAL` (`'external'`) joins the closed membership-role vocabulary, with an `External` option. It projects to the new reserved identity `BUILTIN_IDENTITY_ORG_EXTERNAL` (`'org_external'`), and its invitation grant row is `'any'`, because it confers less than `member`.
17
+
-**`@objectstack/core`:** the authorization resolver reads the stamp from `sys_member.role` in the active organization. An `external` holder holds `org_external` and not the `everyone` anchor, so the deployment's defaults bound there (`member_default`, an app's `isDefault` set, accepted package defaults) do not reach it. The stamp is per organization, and with no active organization an external membership withholds the anchor.
18
+
-**`@objectstack/plugin-security`:** a new shipped set, `external_default`, is bound by the `org_external` position. It carries `member_default`'s own-row self-service grants without the fellow-member directory scope, plus the holder's own `sys_member` row. The plugin's additive baseline is swapped for it on an external context.
19
+
-**`@objectstack/plugin-auth`:**
20
+
- better-auth registers `external` beside owner/admin/member, with no organization statement.
21
+
- A role list carrying `external` with another role is refused at write on `sys_member` and `sys_invitation` (`400 VALIDATION_FAILED`, `invalid_value` on `role`).
22
+
- An external is never placed in the organization's business units. A business-unit membership, a position anchored at one of its units, an invitation conferring `external` with a `business_unit_id`, and a change to `external` while a placement stands are all refused. An organization-wide position or a permission set is how an external gets access.
23
+
-`GET /organization/list-members` and `GET /organization/get-full-organization` answer an external caller its own member row and the invitations addressed to its own email only.
24
+
-**`@objectstack/platform-objects`:** the `External` option label on the membership role pickers, translated.
25
+
26
+
`org_external` is a reserved name from this release on, so a position can no longer be named `org_external`.
fix: the approval request page's Timeline shows each action's step by its label, not the node's machine id
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
The Timeline tab of the `sys_approval_request` record page lists the request's `sys_approval_action` rows. Its step column asked for `step_name`, which holds the Approval node's id (for example `dual_signoff`), so every row showed that id. The column is now `step_label`, the step's label that the service writes on every row and the boot backfill fills on older rows. The strip's step chip (`current_step_label`) and the object's own lists already show this label.
fix: Setup → AI's "Reset to environment defaults" button is now translated in zh-CN, ja-JP and es-ES
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
The `ai` settings manifest declares an `action_button` with id `reset`, but no locale bundle carried `settings.ai.actions.reset.label`, so the button rendered in English beside its translated siblings. The bundles now carry it (en, zh-CN, ja-JP, es-ES).
11
+
12
+
The settings translation coverage test now reads every manifest's `action_button` labels: each shipped non-English locale must carry `settings.<namespace>.actions.<id>.label` for every action button, and no bundle may carry action copy for a button no manifest declares.
| 8 | Metadata-plane schema masking exempt (ADR-0106 D4) | metadata-core | Get: unmasked object schema. Note: the exemption is a **caller** property — it short-circuits before the security service is consulted |`packages/metadata-core/src/object-schema-fls.ts#isObjectSchemaMaskExempt`|
110
110
| 8b | Authoring-trail reads admitted | rest, runtime | Get: a metadata item's version history, audit rows and stored-version diff (`GET /meta/:type/:name/history`, `/audit`, `/diff`) without `studio.access` or `manage_metadata`, and a package's commit timeline (`GET /packages/:id/commits`) without `studio.access`. Note: narrower than the schema-mask exemption the draft switches ask (`isObjectSchemaMaskExempt`): neither door admits `setup.access`, which organization admins hold |`packages/rest/src/rest-server.ts#mayReadAuthoringTrail`, `packages/runtime/src/domains/packages.ts#requireCommitTrailReadCapability`|
111
-
| 9 |`explain()` may target a principal other than the caller | plugin-security | Get: no `manage_users` / delegated-admin check |`packages/plugins/plugin-security/src/security-plugin.ts#explainAccessForCaller`|
111
+
| 9 |`explain()` may target a principal other than the caller | plugin-security | Get: no `manage_users` / delegated-admin check |`packages/plugins/plugin-security/src/security-plugin-explain-access.ts#explainAccessForCaller`|
112
112
| 9b | The master-detail write check the `security` service serves (`checkControlledByParentWrite`, ADR-0055) answers `allow`| plugin-security | Get: `allow` for any record, with no master judged — the write path's own first exit, so a gate composing it admits exactly what the record's own system-context update would. Lose: nothing a caller reaches today: its two consumers, the `sys_attachment` and `sys_comment` parent gates, return before they ask for a system session |`packages/plugins/plugin-security/src/security-plugin-cbp-write-gate.ts#checkControlledByParentWrite`|
113
113
| 10 | Anonymous-deny treats the caller as authenticated | core | Get: passes the 401 seam with no `userId`|`packages/core/src/security/anonymous-deny.ts#shouldDenyAnonymous`|
0 commit comments