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 07d0ee1
Browse filesBrowse the repository at this point in the historyBrowse files
feat(plugin-security): under a walled posture, raise the access upgrade report in-app in the organization OS_PLATFORM_OWNER_ORGANIZATION names
Under group/isolated the boot access upgrade report reached the operator
only as one error line. OS_PLATFORM_OWNER_ORGANIZATION (an id or slug,
read only under a wall) now names the operators' own organization: the
report emits the same notification, same dedupKey, stamped with it and
addressed to the OS_PLATFORM_OWNER_EMAIL operators, beside the operator
line. A value naming no organization logs one error and raises nothing
in-app. A configured operator who is not a verified member of it, and an
administrator of it who is not a configured operator, each get a warn.
Unset, and under single, nothing changes.
The walled and single delivery moves into upgrade-report-delivery.ts so
the non-access report (#24447) can call it.
Claude-Session: https://claude.ai/code/session_01XHebWJmL3ZgbVpjM6JERNA
Co-authored-by: Claude <noreply@anthropic.com>
feat: under a walled posture, `OS_PLATFORM_OWNER_ORGANIZATION` raises the access upgrade report in-app in the platform operators' own organization, beside the operator log line
7
+
8
+
Clause-②: yes (widening: a new optional environment variable, `PLATFORM_OWNER_ORGANIZATION_ENV` and `resolvePlatformOwnerOrganization()` exported from `@objectstack/types`; unset, every posture behaves as before)
9
+
Metadata-protocol: none
10
+
11
+
Under `group` and `isolated` the boot access upgrade report reached the operator only as one `error` line in the server log. The notification family is organization-owned, a walled system write that names no organization is refused (ADR-0131 D9), and the operator belongs to no organization by default.
12
+
13
+
-**New setting:**`OS_PLATFORM_OWNER_ORGANIZATION`, the id or slug of the operators' own organization, beside `OS_PLATFORM_OWNER_EMAIL`. It is read only under a walled posture.
14
+
-**What it does:** with it set, the report emits the same `security.access_upgrade` notification, with the same `dedupKey` per finding set, stamped with that organization and addressed to the `OS_PLATFORM_OWNER_EMAIL` operators. It lands in that organization's Notification Events and the operators' inbox, and in no other organization. The operator line stays beside it.
15
+
-**Use a dedicated organization that holds the operators only.** Every administrator of it can read the notification in Setup, and the findings can name other organizations' ids and rule names. Boot logs a `warn` for a configured operator who is not a verified member of it. It logs another `warn` for an administrator of it who is not a configured operator: an `owner` or `admin` member, or an `admin_full_access` or organization-admin grant scoped to it.
16
+
-**A value naming no organization** logs one `error` naming the value and the fix, and raises nothing in-app. It never falls back to another organization.
17
+
-**Unchanged:** unset, the operator line is the only channel, worded as before. Under `single` the setting is ignored, and the Default Organization's administrators are told as before.
18
+
19
+
The walled and `single` delivery now lives in one helper, `upgrade-report-delivery.ts`, so the non-access upgrade report (#24447) can raise its findings the same way.
Copy file name to clipboardExpand all lines: content/docs/deployment/environment-variables.mdx
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -102,6 +102,7 @@ Read by `@objectstack/service-print` when `PrintServicePlugin` is composed; see
102
102
|`OS_MULTI_ORG_ENABLED`| boolean |`false`| Superseded by `OS_TENANCY_POSTURE`, and still honoured: `true` selects the `isolated` posture. When `true`, organization creation/switching UI is exposed. |
103
103
| `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` | boolean | `false` | Whether this deployment runs **package-authored scheduled work**: time-triggered flows (a `type: 'schedule'` flow with a `config.schedule` cadence, and the `timeRelative` sweep) and packaged `defineJob` cron jobs. **OFF by default in every posture and every kernel** — a clock-driven workload's cost is a fact about the deployment, not about the flow, so an author cannot decide it and no metadata key asks them to. Accepts `true`/`1`/`on`/`yes` (case-insensitive); anything else, including unset, is off. While it is off nothing arms, and every such flow is listed by `getTriggerBindingAudit()` and the CLI startup summary as **disabled by deployment policy** — never as a binding failure, and nothing about the flow needs fixing. While it is on, what a time-triggered flow owes depends on the posture: under `isolated` it must declare `config.organization` on its start node or it is not armed; under `group` the declaration is optional and an undeclared sweep reads group-wide with each run acting as its own swept record's organization (a record-less cron there carries none, and its tenant-scoped writes are refused — declare one if it writes); under `single` it needs no declaration and its runs carry no organization. ⛔ Platform-internal scheduled work — approvals escalation, the lifecycle Reaper, the messaging dispatch loop, membership backfill — is **not** gated by this: the boundary is *authored by a package*, not *runs on the job service*. `os doctor` prints the effective value. |
104
104
| `OS_PLATFORM_OWNER_EMAIL` | csv | — | The deployment's platform administrators: one email address, or a comma-separated list. A caller resolves `PLATFORM_ADMIN` when their own stored `sys_user` row carries a declared address **and** reads email-verified. Comparison is trimmed and case-insensitive; duplicates collapse and blank entries are dropped. One **unparseable** entry refuses the **whole** variable rather than just that entry — the deployment then has zero configured administrators, loudly — because a silently narrower administrator set is the worse failure. **Required under the walled postures** (`group` / `isolated`): unset or blank there **refuses to boot**, since the first self-registrant is not promoted and no grant row is written. Unset under `single` is normal — that posture still promotes the first human account. Read live per resolution, so revocation is a config change plus a process reload; there is no runtime endpoint that changes it. See [First boot: create the admin](/docs/deployment/self-hosting#first-boot-create-the-admin). |
105
+
| `OS_PLATFORM_OWNER_ORGANIZATION` | string | — | Walled postures only (`group` / `isolated`): the id or slug of the platform operators' own organization. The boot upgrade reports raise deployment-level findings, such as the access upgrade report, as one `error` line addressed to the operator. With this set they are also raised in-app: one notification stamped with that organization and addressed to the `OS_PLATFORM_OWNER_EMAIL` operators, deduplicated per finding set across boots. No other organization is told. **Use a dedicated organization that holds the operators only**: every administrator of it can read the notification in Setup, Notification Events, and the findings can name other organizations' ids and rule names. Boot logs a `warn` for a configured operator who is not a verified member of it, and for an administrator of it who is not a configured operator. A value that names no organization logs one `error` naming the value and raises nothing in-app; it never falls back to another organization. Unset, the log line is the only channel. Ignored under `single`, where the Default Organization's administrators are told. |
105
106
|`OS_OIDC_PROVIDER_ENABLED`| boolean | tracks MCP | When `true`, expose this instance as an OIDC identity provider. When unset it follows the MCP server surface (`OS_MCP_SERVER_ENABLED`, on by default) — the MCP human-client track is OAuth 2.1, so every MCP-enabled deployment is its own authorization server. |
0 commit comments