From 0351a764cb5f9eb17d140e2c3c17aa782bc8adef Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 13:00:34 +0000 Subject: [PATCH 1/3] docs(access): align access, audit and approval pages with ObjectStack 17.0-17.7 Masking as a third field state, the query-door 403, the deny baseline and the guest anchor, deactivation, RLS fail-closed, audit-row visibility and view_all_audit_log, approval participant visibility, API-key organization binding, and the closed-by-default sign-up audience. Deletes the locale siblings of positions.mdx and permissions/index.mdx: both English corrections reverse the claim that binding a set to `guest` opens data to anonymous visitors. Claude-Session: https://claude.ai/code/session_01CXCwzqwMhkphKoBC11oPSz Co-authored-by: Claude --- content/docs/build/automation/approvals.mdx | 11 ++ content/docs/configure/api-access.mdx | 18 ++ content/docs/configure/authentication.mdx | 47 +++++ .../permissions/field-level-security.mdx | 92 ++++++++-- .../docs/configure/permissions/index.de.mdx | 161 ---------------- .../docs/configure/permissions/index.es.mdx | 150 --------------- .../docs/configure/permissions/index.fr.mdx | 173 ------------------ .../docs/configure/permissions/index.ja.mdx | 131 ------------- .../docs/configure/permissions/index.ko.mdx | 131 ------------- content/docs/configure/permissions/index.mdx | 22 ++- .../configure/permissions/index.zh-Hans.mdx | 134 -------------- .../configure/permissions/index.zh-Hant.mdx | 135 -------------- .../configure/permissions/permission-sets.mdx | 25 +++ .../configure/permissions/positions.de.mdx | 67 ------- .../configure/permissions/positions.es.mdx | 67 ------- .../configure/permissions/positions.fr.mdx | 67 ------- .../configure/permissions/positions.ja.mdx | 66 ------- .../configure/permissions/positions.ko.mdx | 64 ------- .../docs/configure/permissions/positions.mdx | 45 ++++- .../permissions/positions.zh-Hans.mdx | 123 ------------- .../permissions/positions.zh-Hant.mdx | 124 ------------- .../configure/permissions/record-access.mdx | 28 +++ content/docs/configure/users.mdx | 6 + content/docs/operate/audit-logs.mdx | 39 +++- content/docs/operate/observability.mdx | 5 +- content/docs/reference/security.mdx | 15 +- content/docs/use/approvals.mdx | 10 +- 27 files changed, 328 insertions(+), 1628 deletions(-) delete mode 100644 content/docs/configure/permissions/index.de.mdx delete mode 100644 content/docs/configure/permissions/index.es.mdx delete mode 100644 content/docs/configure/permissions/index.fr.mdx delete mode 100644 content/docs/configure/permissions/index.ja.mdx delete mode 100644 content/docs/configure/permissions/index.ko.mdx delete mode 100644 content/docs/configure/permissions/index.zh-Hans.mdx delete mode 100644 content/docs/configure/permissions/index.zh-Hant.mdx delete mode 100644 content/docs/configure/permissions/positions.de.mdx delete mode 100644 content/docs/configure/permissions/positions.es.mdx delete mode 100644 content/docs/configure/permissions/positions.fr.mdx delete mode 100644 content/docs/configure/permissions/positions.ja.mdx delete mode 100644 content/docs/configure/permissions/positions.ko.mdx delete mode 100644 content/docs/configure/permissions/positions.zh-Hans.mdx delete mode 100644 content/docs/configure/permissions/positions.zh-Hant.mdx diff --git a/content/docs/build/automation/approvals.mdx b/content/docs/build/automation/approvals.mdx index 38603e4..3f95398 100644 --- a/content/docs/build/automation/approvals.mdx +++ b/content/docs/build/automation/approvals.mdx @@ -313,6 +313,17 @@ While a request is pending: for `per_group` — so the inbox and your own UIs render progress without re-implementing the tally. +**Who can see a request (17.0).** A request carries a snapshot of the record, +its whole decision history and its attachments, so only its participants +read it: the submitter, a current approver (including the holders of a +position the request waits on), and anyone who has already acted or +commented on it. Platform and organization administrators see every request. +Everyone else gets nothing, and being able to read the record does not change +that. Filtering a request list by approver is a filter, not a grant: leaving +it out returns only the requests you take part in, never the whole tenant. +Inside a visible request, the snapshot drops every field the reader cannot +read on the record — and, since 17.6, every field they read only masked. + **Decisions are declared actions (16.0).** The full decision set — approve, reject, reassign, send-back for revision (`/revise`), request-info, remind, recall, resubmit — is declared as `type: 'api'` actions on diff --git a/content/docs/configure/api-access.mdx b/content/docs/configure/api-access.mdx index b39dd10..841ddf1 100644 --- a/content/docs/configure/api-access.mdx +++ b/content/docs/configure/api-access.mdx @@ -104,6 +104,24 @@ To revoke a key, run the `revoke_api_key` action on the corresponding `sys_api_key` record (also available in Setup). Revocation takes effect immediately on the next request. +### Keys belong to an organization (ObjectStack 17.1) + +A key is minted against the caller's **active organization**: +`POST /api/v1/keys` takes no organization parameter, so there is no +cross-organization key, and the caller's membership is re-checked at mint +time. On a single-organization deployment that changes nothing you can see. +Under a walled tenancy posture (`OS_TENANCY_POSTURE`, see +[Environment Variables](/docs/reference/environment-variables#multi-organization-deployments)), +it decides which keys still work: + +| Key | `group` | `isolated` | +|---|---|---| +| Minted on 17.1 or later, owner still a member of its organization | Works | Works | +| Owner has since left the key's organization | Refused | Refused | +| Minted before 17.1 — it carries no organization | Works | Refused — re-mint it | + +Keys minted before 17.1 are never back-filled with an organization. + ## MCP clients & OAuth 2.1 (ObjectStack 13+) Any OAuth-capable MCP client — Claude.ai custom connectors, Claude diff --git a/content/docs/configure/authentication.mdx b/content/docs/configure/authentication.mdx index 0c65b5b..b0f369c 100644 --- a/content/docs/configure/authentication.mdx +++ b/content/docs/configure/authentication.mdx @@ -24,6 +24,51 @@ support: - phone number sign-in with SMS OTP (opt-in); - CLI/browser device flow. +## Who may sign up (ObjectStack 17.3+) + +Self-registration is **closed by default**. Who may create their own +account is one setting, **Setup → Authentication → Audience**: + +| Audience | Who may sign up | +|---|---| +| `invite_only` (default) | Only an address holding a pending invitation | +| `email_domain` | Addresses on the domains you allow — exact match, case-insensitive; subdomains need their own entry | +| `open` | Anyone | + +The audience judges every self-serve path: email/password sign-up, a +first sign-in through a social provider, magic link, OTP and phone. A +refused sign-up answers `403 SELF_REGISTRATION_CLOSED` (or +`403 EMAIL_DOMAIN_NOT_ALLOWED` under `email_domain`). Two rules come with +opening it: + +- `email_domain` and `open` both need a **self-registration permission + set** — the set each self-registrant receives (`member_default` is + fine; `admin_full_access` is refused). +- Both turn email verification on: `email_domain` always, `open` unless + the deployment's own configuration turns it off. + +The **Allow self-service registration** toggle under *Email and password* +does not override the audience: with the audience at `invite_only`, +sign-up stays closed even while that toggle is on. + +Creating people yourself is never gated by the audience — invitations, +**Create User**, bulk import and enterprise SSO work under every setting +(see [Users](/docs/configure/users#add-people)). The very first account on +a fresh install is exempt too. + +> **Upgrading from 17.2 or earlier:** an undeclared audience used to mean +> open email/password sign-up. It now means `invite_only`, and nothing +> fails at upgrade — a deployment that relied on open sign-up simply stops +> accepting it. Choose `open` (with a self-registration permission set) +> to keep it. + +The audience is a different decision from the **membership policy** +(**Setup → Authentication → Membership**, or `OS_AUTH_MEMBERSHIP_POLICY` +— see +[Environment Variables](/docs/reference/environment-variables#multi-organization-deployments)). +The audience decides *whether* someone may become a user at all; the +membership policy decides *which organization* a new user joins. + ## Phone sign-in & SMS (ObjectStack 14.3+) Enable phone-number authentication via the `auth.plugins.phoneNumber` @@ -145,6 +190,8 @@ wants every project to own a completely separate login boundary. Before production: - confirm expired tokens return `401`; +- confirm the sign-up audience matches who should be able to create an + account; - confirm logout revokes the active session; - confirm password reset revokes other sessions if required by policy; - confirm callback URLs match the public project domain; diff --git a/content/docs/configure/permissions/field-level-security.mdx b/content/docs/configure/permissions/field-level-security.mdx index b95a296..0f4ab3a 100644 --- a/content/docs/configure/permissions/field-level-security.mdx +++ b/content/docs/configure/permissions/field-level-security.mdx @@ -1,7 +1,7 @@ --- title: Field-Level Security seoTitle: "Field-Level Security: Grants and API Enforcement" -description: Hide or lock down individual fields — grant semantics, server-side enforcement, and how FLS behaves in forms, views, and the API. +description: Hide, mask or lock down individual fields — grant semantics, server-side enforcement, and how FLS behaves in forms, views, and the API. --- Field-level security (FLS) controls the visibility and editability of @@ -47,6 +47,55 @@ The two flags produce three states: > `security-fls-unqualified-key` lint rejects bare keys at compile > time, because they silently matched nothing. +## Masked fields + +Since ObjectStack 17.1 a field can also be **masked**: served with most +of its value replaced, so it stays recognizable without being +disclosed. Masking is declared on the field itself, not in a permission +set: + +```ts +// Fields of an object; the object around them is omitted. +mobile: Field.phone({ + label: 'Mobile', + maskingRule: 'phone', // served as 138****5678 + requiredPermissions: ['view_pii'], // holders of view_pii see the stored value +}), +tax_id: Field.text({ + label: 'Tax ID', + maskingRule: { keepHead: 2, keepTail: 2 }, // keep two characters at each end +}), +``` + +`maskingRule` takes one of five presets — `phone`, `id_card`, +`bank_account`, `email`, `name` — or `{ keepHead, keepTail }`, the +number of characters to keep at each end. The mask is deterministic and +keeps the value's length. + +Who sees the stored value: + +| Caller | Sees | +|---|---| +| Holds **every** capability in the field's `requiredPermissions` | The stored value | +| Anyone else, when the field declares `requiredPermissions` | The mask | +| Everyone except system context, when the field declares no `requiredPermissions` | The mask | +| A caller from whom a `readable: false` grant hides the field | Nothing — the field stays hidden | + +The capability in `requiredPermissions` is granted like any other, by a +permission set. Masking never widens a hidden field: a `readable: false` +grant still removes it entirely. + +Masking is one value on every surface — API responses, list views and +forms, CSV and XLSX exports, and the context an AI agent reads all serve +the same mask. Two more rules keep it from leaking: + +- **A masked field cannot be queried.** Filtering, sorting, grouping or + aggregating on it is refused, as for a hidden field — see + [Enforcement in the API](#enforcement-in-the-api). +- **The mask never overwrites the value.** A write that sends the masked + placeholder back — a client re-submitting a whole record it read — is + refused with `400 VALIDATION_ERROR` instead of storing `138****5678`. + ## How grants combine FLS uses **default-visible (block-list) semantics**: fields without an @@ -56,7 +105,7 @@ Permission sets only constrain fields they explicitly enumerate. Field grants union **most-permissively** across a user's sets: one set's `readable: true` out-votes another set's `false`. Until a subtractive muting layer lands (reserved as ADR-0066 ⑧), a -`{ readable: false }` rule masks the field only as long as **no other +`{ readable: false }` rule hides the field only as long as **no other set the user holds** declares it `readable: true`. The practical consequences: @@ -66,7 +115,7 @@ consequences: - Treat a sensitive field on a broadly-granted object as a review smell. -Declared rules themselves are enforced fail-closed: a masked field is +Declared rules themselves are enforced fail-closed: a hidden field is stripped on read and a write to a non-editable field throws. ## Enforcement in the API @@ -76,7 +125,21 @@ regardless of how the request arrived — REST, ObjectQL, or any other path. There is no back door through a lower-level API. **On read** — `find` / `findOne` results have non-readable fields -stripped from every record before the response leaves the engine. +stripped from every record before the response leaves the engine, and +masked fields replaced by their mask. + +**On query** — a field the caller cannot read, or reads only masked, +cannot be used to select rows either, because which rows match would +disclose its value one probe at a time. Filtering, sorting, grouping or +aggregating on it is refused with `403 PERMISSION_DENIED`. Since +ObjectStack 17.6 that holds at every query door, not only the data +API's filter and sort: + +- a field named as the right-hand side of a comparison, in a filter or + an aggregation; +- analytics queries; +- filters and sorts over the value columns of the activity stream, the + [audit log](/docs/operate/audit-logs) and approval snapshots. **On write** — `insert` / `update` requests are checked **before** the operation reaches the driver. If the payload contains any field the @@ -118,23 +181,26 @@ The generated forms and inline grids hide non-editable fields from the UI — but that is a **UX layer only**. The server-side check above is the source of truth, so behavior stays consistent everywhere: -| Surface | Hidden field | Read-only field | -|---|---|---| -| Record forms / inline grids | Not rendered | Rendered without an editable control; a direct write attempt is rejected with 403 | -| List views, related lists, exports | Column value stripped from the response | Value shown normally | -| REST / ObjectQL | Stripped from results | Returned on read; write throws `PERMISSION_DENIED` with `forbiddenFields` | -| MCP / AI agents | Stripped — agents [run as the calling user](/docs/configure/mcp#permission-enforcement) | Same as REST | +| Surface | Hidden field | Masked field | Read-only field | +|---|---|---|---| +| Record forms / inline grids | Not rendered | Value shown masked; writing the mask back is rejected with `400 VALIDATION_ERROR` | Rendered without an editable control; a direct write attempt is rejected with 403 | +| List views, related lists, exports | Column value stripped from the response | Masked value shown, in CSV and XLSX exports too | Value shown normally | +| REST / ObjectQL | Stripped from results | Masked value returned | Returned on read; write throws `PERMISSION_DENIED` with `forbiddenFields` | +| MCP / AI agents | Stripped — agents [run as the calling user](/docs/configure/mcp#permission-enforcement) | Same as REST | Same as REST | +| Filter, sort, group, aggregate | Refused with `403 PERMISSION_DENIED` | Refused with `403 PERMISSION_DENIED` | Allowed | Because reads are stripped rather than errored, a hidden field simply -looks absent to that user — which is the point. +looks absent to that user — which is the point. Querying on it is the +exception: that answers `403`, as above. ## Verifying and reviewing FLS - **Per decision, at runtime** — the [explain engine](/docs/configure/permissions#diagnose--audit) reports the FLS layer's verdict alongside every other layer, with the - contributing permission set named. Use it when a user reports a - "missing" field. + contributing permission set named, and reports a masked field as + masked rather than hidden. Use it when a user reports a "missing" + field. - **Per change, at build time** — if your app has opted into the access-matrix snapshot gate, `os compile` diffs the derived (permission set × object) capability matrix against a committed diff --git a/content/docs/configure/permissions/index.de.mdx b/content/docs/configure/permissions/index.de.mdx deleted file mode 100644 index ffbac49..0000000 --- a/content/docs/configure/permissions/index.de.mdx +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Berechtigungen -description: Identität, Rollen, Berechtigungssätze, Datensatzzugriff und Feldsicherheit — das gesamte Zugriffsmodell auf einer Seite. -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS verfügt über ein mehrschichtiges Zugriffsmodell, das aus dem -Vorgehen übernommen wurde, das sich in Unternehmenssoftware seit zwei -Jahrzehnten bewährt hat: Identität → Rollen → Berechtigungssätze → -Datensatzzugriff → Feldsicherheit. Jede Schicht beantwortet eine -andere Frage, und Sie können diejenigen ignorieren, die Sie nicht -benötigen. - -## Das Modell in einem Diagramm - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Roles Where do they sit in the hierarchy? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -Jede Schicht wird vom Security-Plugin durchgesetzt. Für einfache Apps -können Sie ausschließlich Berechtigungssätze verwenden (keine Rollen, -keine Freigaberegeln) und den Rest hinzufügen, sobald die Anforderung -auftaucht. - -## Schicht 1 — Identität - -Identitätsobjekte befinden sich in Ihrer Projektdatenbank. Die -wichtigsten davon: - -| Objekt | Was es repräsentiert | -|---|---| -| `sys_user` | Eine Person oder ein Dienstkonto, das sich authentifizieren kann | -| `sys_organization` | Mandanten-/Workspace-Grenze (mandantenfähige Apps) | -| `sys_member` | Die Mitgliedschaft eines Benutzers in einer Organisation (Rolle pro Mitgliedschaft zugewiesen) | -| `sys_business_unit`, `sys_team` | Optionale Organisationsstruktur für Freigaberegeln | -| `sys_invitation` | Ausstehende Einladung, die auf Annahme wartet | -| `sys_session` | Aktive authentifizierte Sitzung | -| `sys_api_key` | Langlebige programmatische Anmeldeinformationen, die an einen Benutzer gebunden sind | - -In einer mandantenfähigen Bereitstellung: - -- Benutzer sind auf die Projektdatenbank beschränkt. -- Sitzungen sind auf den Projekt-Hostnamen beschränkt. -- Prüfungen auf Zeilenebene verwenden die Organisation und die Berechtigungen des aktuellen Benutzers. -- Control-Plane-Benutzer sind **nicht** automatisch Geschäftsbenutzer — sie - müssen über Plattform-SSO oder explizite Bereitstellung zugeordnet werden. - -Sie erstellen/verwalten diese zur Laufzeit über die **Console** -(`/_console/`) oder seeden sie in `objectstack.config.ts` für neue -Umgebungen. - -## Schicht 2 — Rollen - -Rollen modellieren das Organigramm (CFO → Finance Manager → Analyst). -Sie existieren in erster Linie, damit Freigaberegeln und Berichte Dinge -ausdrücken können wie "der Vorgesetzte des Datensatzeigentümers". -Verwenden Sie Rollen, wenn Sie hierarchischen Zugriff benötigen; -verzichten Sie auf sie bei flachen Teams. - -Siehe [Roles](/docs/configure/permissions/positions). - -## Schicht 3 — Berechtigungssätze - -Berechtigungssätze sind die primäre Methode, um Fähigkeiten zu -gewähren. Sie werden Benutzern direkt oder über Rollen zugewiesen. - -### Was sie gewähren - -| Typ | Beispiele | -|---|---| -| Anwendungszugriff | CRM öffnen, das Support-Portal öffnen | -| Objektberechtigungen | Datensätze eines Objekts erstellen / lesen / aktualisieren / löschen | -| Feldberechtigungen | Bestimmte Felder lesen oder aktualisieren | -| Systemberechtigungen | Auf Console zugreifen, Berichte ausführen, Daten exportieren, Audit-Log anzeigen | -| Integrationsberechtigungen | API-Schlüssel verwenden, Webhooks konfigurieren, Admin-Aktionen ausführen | - -### Flags für Objektberechtigungen - -Dies sind die exakten Flag-Namen, die das Security-Plugin prüft: - -| Flag | Bedeutung | -|---|---| -| `allowRead` | Datensätze lesen, die der Benutzer über den Datensatzzugriff sehen kann | -| `allowCreate` | Neue Datensätze erstellen | -| `allowEdit` | Datensätze aktualisieren, die der Benutzer sehen kann | -| `allowDelete` | Datensätze löschen, die der Benutzer sehen kann | -| `viewAllRecords` | **Jeden** Datensatz des Objekts lesen, unter Missachtung der Datensatzzugriffsregeln | -| `modifyAllRecords` | **Jeden** Datensatz aktualisieren/löschen; impliziert `viewAllRecords` | - -`viewAllRecords` und `modifyAllRecords` sind mandantenweite -Superuser-Berechtigungen für das jeweilige Objekt. Reservieren Sie sie -für explizite administrative Berechtigungssätze und halten Sie sie aus -jeder benutzerseitigen Rolle heraus. - -Siehe [Permission Sets](/docs/configure/permissions/permission-sets). - -## Schicht 4 — Datensatzzugriff - -Für Benutzer **ohne** `viewAllRecords`: Welche Zeilen können sie sehen? - -Das Modell unterstützt: - -- Implizites Eigentum (Zeilen, die der Benutzer erstellt hat oder besitzt) -- Freigaberegeln (deklarativ — "Team A sieht die Datensätze von Team A") -- Explizite Freigaben (`sys_record_share`-Zeilen — einmalige Freigaben) -- Organisationsbereich (das `organization_id` der Zeile stimmt mit der - Organisation des Benutzers überein) - -Siehe [Record Access](/docs/configure/permissions/record-access). - -## Schicht 5 — Feldsicherheit - -Selbst wenn ein Benutzer einen Datensatz sehen kann, können einzelne -Felder sein: - -- **Ausgeblendet** — das Feld wird aus API- und UI-Antworten entfernt. -- **Schreibgeschützt** — das Feld wird zurückgegeben, aber beim Schreiben abgelehnt. - -Feldsicherheit gilt pro Objekt + pro Berechtigungssatz. Typische -Verwendung: - -- `salary` auf `sys_user` für alle außerhalb der Personalabteilung ausblenden. -- `external_account_id` für Support-Mitarbeiter lesbar, aber nicht bearbeitbar machen. - -Sie wird im selben Evaluator wie die Objektberechtigungen durchgesetzt, -sodass sie einheitlich über REST, ObjectQL und Console hinweg gilt. - -## Wo Sie anfangen sollten - -| Wenn Sie etwas erstellen … | Verwenden Sie | -|---|---| -| Ein internes Tool für ein einzelnes Team | Nur Berechtigungssätze | -| Eine teamübergreifende App, in der Manager Berichte sehen | Rollen + Berechtigungssätze | -| Eine mandantenfähige SaaS-artige App | Organisationsbereich + Berechtigungssätze | -| Eine regulierte App mit PII | Feldsicherheit obendrauf hinzufügen | -| Eine komplexe App im CRM-Stil | Der vollständige Stack | - -## Diagnose & Audit - -- `/_console/` zeigt die effektiven Berechtigungen eines beliebigen - Benutzers, so wie sie ausgewertet werden. -- Das Audit-Log (`sys_audit_log`) erfasst berechtigungsrelevante - Änderungen — Gewährungen, Rollenzuweisungen, Bearbeitungen von - Berechtigungssätzen. -- Abgelehnte Anfragen protokollieren die fehlgeschlagene Regel - (Objektberechtigung vs. Datensatzzugriff vs. Feldsicherheit), sodass - der Support schnell die Frage "Warum kann ich das nicht sehen?" - beantworten kann. diff --git a/content/docs/configure/permissions/index.es.mdx b/content/docs/configure/permissions/index.es.mdx deleted file mode 100644 index 6a8717c..0000000 --- a/content/docs/configure/permissions/index.es.mdx +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: Permisos -description: Identidad, roles, conjuntos de permisos, acceso a registros y seguridad de campos — todo el modelo de acceso en una sola página. -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS tiene un modelo de acceso en capas tomado del manual que ha -funcionado en el software empresarial durante dos décadas: identidad → roles → -conjuntos de permisos → acceso a registros → seguridad de campos. Cada capa responde a -una pregunta diferente, y puedes ignorar las que no necesites. - -## El modelo en un solo diagrama - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Roles Where do they sit in the hierarchy? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -Cada capa es aplicada por el plugin de seguridad. Puedes usar solo -conjuntos de permisos (sin roles, sin reglas de uso compartido) para aplicaciones simples y añadir -el resto a medida que aparezca el requisito. - -## Capa 1 — Identidad - -Los objetos de identidad residen en la base de datos de tu proyecto. Los más importantes: - -| Objeto | Qué representa | -|---|---| -| `sys_user` | Una persona o cuenta de servicio que puede autenticarse | -| `sys_organization` | Límite de inquilino / espacio de trabajo (aplicaciones multiinquilino) | -| `sys_member` | La pertenencia de un usuario a una organización (rol asignado por pertenencia) | -| `sys_business_unit`, `sys_team` | Estructura organizativa opcional para las reglas de uso compartido | -| `sys_invitation` | Invitación pendiente a la espera de ser aceptada | -| `sys_session` | Sesión autenticada activa | -| `sys_api_key` | Credencial programática de larga duración vinculada a un usuario | - -En un despliegue multiinquilino: - -- Los usuarios están delimitados a la base de datos del proyecto. -- Las sesiones están delimitadas al nombre de host del proyecto. -- Las comprobaciones a nivel de fila usan la organización y los permisos del usuario actual. -- Los usuarios del plano de control **no** son automáticamente usuarios de negocio — - deben mapearse mediante SSO de la plataforma o aprovisionamiento explícito. - -Creas/gestionas estos desde la **Console** (`/_console/`) en tiempo de ejecución, o -los precargas en `objectstack.config.ts` para entornos nuevos. - -## Capa 2 — Roles - -Los roles modelan el organigrama (CFO → Gerente de Finanzas → Analista). Existen -principalmente para que las reglas de uso compartido y los informes puedan decir cosas como "el -gerente del propietario del registro". Usa roles cuando necesites acceso -jerárquico; omítelos para equipos planos. - -Consulta [Roles](/docs/configure/permissions/positions). - -## Capa 3 — Conjuntos de permisos - -Los conjuntos de permisos son la forma principal de otorgar capacidades. Se adjuntan -a los usuarios directamente o a través de roles. - -### Qué otorgan - -| Tipo | Ejemplos | -|---|---| -| Acceso a aplicaciones | Abrir CRM, abrir el portal de soporte | -| Permisos de objeto | Crear / leer / actualizar / eliminar registros de un objeto | -| Permisos de campo | Leer o actualizar campos específicos | -| Permisos de sistema | Acceder a Console, ejecutar informes, exportar datos, ver el registro de auditoría | -| Permisos de integración | Usar claves de API, configurar webhooks, ejecutar acciones de administrador | - -### Indicadores de permisos de objeto - -Estos son los nombres exactos de los indicadores que comprueba el plugin de seguridad: - -| Indicador | Significado | -|---|---| -| `allowRead` | Leer registros que el usuario puede ver mediante el acceso a registros | -| `allowCreate` | Crear nuevos registros | -| `allowEdit` | Actualizar registros que el usuario puede ver | -| `allowDelete` | Eliminar registros que el usuario puede ver | -| `viewAllRecords` | Leer **todos** los registros del objeto, ignorando las reglas de acceso a registros | -| `modifyAllRecords` | Actualizar/eliminar **todos** los registros; implica `viewAllRecords` | - -`viewAllRecords` y `modifyAllRecords` son concesiones de superusuario a nivel de -inquilino para ese objeto. Resérvalas para conjuntos de permisos administrativos -explícitos y mantenlas fuera de cualquier rol orientado al usuario. - -Consulta [Permission Sets](/docs/configure/permissions/permission-sets). - -## Capa 4 — Acceso a registros - -Para los usuarios **sin** `viewAllRecords`, ¿qué filas pueden ver? - -El modelo admite: - -- Propiedad implícita (filas que el usuario creó o posee) -- Reglas de uso compartido (declarativas — "el equipo A ve los registros del equipo A") -- Compartidos explícitos (filas `sys_record_share` — compartidos puntuales) -- Delimitación por organización (el `organization_id` de la fila coincide con la - organización del usuario) - -Consulta [Record Access](/docs/configure/permissions/record-access). - -## Capa 5 — Seguridad de campos - -Incluso cuando un usuario puede ver un registro, los campos individuales pueden ser: - -- **Ocultos** — el campo se elimina de las respuestas de la API y la UI. -- **De solo lectura** — el campo se devuelve pero se rechaza al escribir. - -La seguridad de campos es por objeto + por conjunto de permisos. Uso típico: - -- Ocultar `salary` en `sys_user` a cualquiera fuera de RR. HH. -- Hacer que `external_account_id` sea legible pero no editable para los representantes de soporte. - -Se aplica en el mismo evaluador que los permisos de objeto, por lo que -se aplica de manera uniforme en REST, ObjectQL y Console. - -## Por dónde empezar - -| Si estás construyendo … | Usa | -|---|---| -| Una herramienta interna de un solo equipo | Solo conjuntos de permisos | -| Una aplicación multiequipo con gerentes que ven informes | Roles + conjuntos de permisos | -| Una aplicación con forma de SaaS multiinquilino | Delimitación por organización + conjuntos de permisos | -| Una aplicación regulada con PII | Añade seguridad de campos por encima | -| Una aplicación compleja estilo CRM | La pila completa | - -## Diagnosticar y auditar - -- `/_console/` muestra los permisos efectivos de cualquier usuario tal como se - evalúan. -- El registro de auditoría (`sys_audit_log`) registra los cambios sensibles a permisos — - concesiones, asignaciones de roles, ediciones de conjuntos de permisos. -- Las solicitudes denegadas registran la regla que falló (permiso de objeto vs acceso a - registros vs seguridad de campos) para que el soporte pueda responder rápidamente "¿por qué no puedo ver - esto?". diff --git a/content/docs/configure/permissions/index.fr.mdx b/content/docs/configure/permissions/index.fr.mdx deleted file mode 100644 index c206dec..0000000 --- a/content/docs/configure/permissions/index.fr.mdx +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: Permissions -description: Identité, rôles, ensembles d'autorisations, accès aux enregistrements et sécurité des champs — l'intégralité du modèle d'accès sur une seule page. -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS dispose d'un modèle d'accès en couches inspiré des principes qui -ont fait leurs preuves dans les logiciels d'entreprise depuis deux -décennies : identité → rôles → ensembles d'autorisations → accès aux -enregistrements → sécurité des champs. Chaque couche répond à une -question différente, et vous pouvez ignorer celles dont vous n'avez pas -besoin. - -## Le modèle en un seul diagramme - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Roles Where do they sit in the hierarchy? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -Chaque couche est appliquée par le plugin de sécurité. Vous pouvez -utiliser uniquement les ensembles d'autorisations (sans rôles, sans -règles de partage) pour des applications simples et ajouter le reste à -mesure que le besoin apparaît. - -## Couche 1 — Identité - -Les objets d'identité résident dans la base de données de votre projet. -Les plus importants : - -| Objet | Ce qu'il représente | -|---|---| -| `sys_user` | Une personne ou un compte de service pouvant s'authentifier | -| `sys_organization` | Limite de locataire / espace de travail (applications multi-locataires) | -| `sys_member` | L'appartenance d'un utilisateur à une organisation (rôle attribué par appartenance) | -| `sys_business_unit`, `sys_team` | Structure organisationnelle facultative pour les règles de partage | -| `sys_invitation` | Invitation en attente d'acceptation | -| `sys_session` | Session authentifiée active | -| `sys_api_key` | Identifiant programmatique de longue durée lié à un utilisateur | - -Dans un déploiement multi-locataire : - -- Les utilisateurs sont délimités à la base de données du projet. -- Les sessions sont délimitées au nom d'hôte du projet. -- Les vérifications au niveau des lignes utilisent l'organisation et les - autorisations de l'utilisateur courant. -- Les utilisateurs du plan de contrôle ne sont **pas** automatiquement - des utilisateurs métier — ils doivent être mappés via le SSO de la - plateforme ou un provisionnement explicite. - -Vous créez/gérez ces éléments depuis la **Console** (`/_console/`) à -l'exécution, ou vous les initialisez dans `objectstack.config.ts` pour -les nouveaux environnements. - -## Couche 2 — Rôles - -Les rôles modélisent l'organigramme (CFO → Responsable financier → -Analyste). Ils existent principalement pour que les règles de partage et -les rapports puissent exprimer des choses comme « le responsable du -propriétaire de l'enregistrement ». Utilisez les rôles lorsque vous avez -besoin d'un accès hiérarchique ; ignorez-les pour les équipes à -structure plate. - -Voir [Rôles](/docs/configure/permissions/positions). - -## Couche 3 — Ensembles d'autorisations - -Les ensembles d'autorisations constituent le principal moyen d'accorder -des capacités. Ils s'attachent aux utilisateurs directement ou via les -rôles. - -### Ce qu'ils accordent - -| Type | Exemples | -|---|---| -| Accès aux applications | Ouvrir le CRM, ouvrir le portail de support | -| Permissions sur les objets | Créer / lire / mettre à jour / supprimer les enregistrements d'un objet | -| Permissions sur les champs | Lire ou mettre à jour des champs spécifiques | -| Permissions système | Accéder à la Console, exécuter des rapports, exporter des données, consulter le journal d'audit | -| Permissions d'intégration | Utiliser des clés API, configurer des webhooks, exécuter des actions d'administration | - -### Indicateurs de permission sur les objets - -Voici les noms exacts des indicateurs vérifiés par le plugin de -sécurité : - -| Indicateur | Signification | -|---|---| -| `allowRead` | Lire les enregistrements que l'utilisateur peut voir via l'accès aux enregistrements | -| `allowCreate` | Créer de nouveaux enregistrements | -| `allowEdit` | Mettre à jour les enregistrements que l'utilisateur peut voir | -| `allowDelete` | Supprimer les enregistrements que l'utilisateur peut voir | -| `viewAllRecords` | Lire **chaque** enregistrement de l'objet, en ignorant les règles d'accès aux enregistrements | -| `modifyAllRecords` | Mettre à jour/supprimer **chaque** enregistrement ; implique `viewAllRecords` | - -`viewAllRecords` et `modifyAllRecords` sont des privilèges de -super-utilisateur à l'échelle du locataire pour cet objet. Réservez-les à -des ensembles d'autorisations administratifs explicites et tenez-les à -l'écart de tout rôle destiné aux utilisateurs. - -Voir [Ensembles d'autorisations](/docs/configure/permissions/permission-sets). - -## Couche 4 — Accès aux enregistrements - -Pour les utilisateurs **sans** `viewAllRecords`, quelles lignes -peuvent-ils voir ? - -Le modèle prend en charge : - -- La propriété implicite (les lignes que l'utilisateur a créées ou - possède) -- Les règles de partage (déclaratives — « l'équipe A voit les - enregistrements de l'équipe A ») -- Les partages explicites (lignes `sys_record_share` — partages - ponctuels) -- La délimitation par organisation (l'`organization_id` de la ligne - correspond à l'organisation de l'utilisateur) - -Voir [Accès aux enregistrements](/docs/configure/permissions/record-access). - -## Couche 5 — Sécurité des champs - -Même lorsqu'un utilisateur peut voir un enregistrement, des champs -individuels peuvent être : - -- **Masqués** — le champ est retiré des réponses de l'API et de - l'interface. -- **En lecture seule** — le champ est renvoyé mais rejeté en écriture. - -La sécurité des champs s'applique par objet + par ensemble -d'autorisations. Usage typique : - -- Masquer `salary` sur `sys_user` pour toute personne en dehors des RH. -- Rendre `external_account_id` lisible mais non modifiable pour les - commerciaux du support. - -Elle est appliquée par le même évaluateur que les permissions sur les -objets, de sorte qu'elle s'applique uniformément à REST, ObjectQL et la -Console. - -## Par où commencer - -| Si vous construisez … | Utilisez | -|---|---| -| Un outil interne pour une seule équipe | Uniquement des ensembles d'autorisations | -| Une application multi-équipes où les responsables consultent des rapports | Rôles + ensembles d'autorisations | -| Une application de type SaaS multi-locataire | Délimitation par organisation + ensembles d'autorisations | -| Une application réglementée avec des données personnelles (PII) | Ajouter la sécurité des champs par-dessus | -| Une application complexe de type CRM | L'ensemble complet de la pile | - -## Diagnostiquer et auditer - -- `/_console/` affiche les permissions effectives de tout utilisateur - telles qu'elles sont évaluées. -- Le journal d'audit (`sys_audit_log`) enregistre les modifications - sensibles aux permissions — octrois, attributions de rôles, modifications - d'ensembles d'autorisations. -- Les requêtes refusées consignent la règle qui a échoué (permission sur - l'objet, accès à l'enregistrement ou sécurité des champs), afin que le - support puisse répondre rapidement à la question « pourquoi ne puis-je - pas voir ceci ? ». diff --git a/content/docs/configure/permissions/index.ja.mdx b/content/docs/configure/permissions/index.ja.mdx deleted file mode 100644 index 935a56c..0000000 --- a/content/docs/configure/permissions/index.ja.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: 権限 -description: アイデンティティ、ロール、権限セット、レコードアクセス、フィールドセキュリティ — アクセスモデル全体を1ページにまとめて解説します。 -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS は、エンタープライズソフトウェアで20年間にわたり実績を重ねてきた手法を取り入れた、階層型のアクセスモデルを備えています。アイデンティティ → ロール → 権限セット → レコードアクセス → フィールドセキュリティという構成です。各レイヤーはそれぞれ異なる問いに答えるものであり、必要のないレイヤーは無視して構いません。 - -## モデルを1つの図で - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Roles Where do they sit in the hierarchy? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -各レイヤーは security プラグインによって適用されます。シンプルなアプリでは権限セットだけ(ロールやシェアルールなし)を使い、必要が生じた時点で残りを追加できます。 - -## レイヤー 1 — アイデンティティ - -アイデンティティオブジェクトは、プロジェクトのデータベースに存在します。最も重要なものは次のとおりです。 - -| オブジェクト | 表すもの | -|---|---| -| `sys_user` | 認証可能な個人またはサービスアカウント | -| `sys_organization` | テナント / ワークスペースの境界(マルチテナントアプリ向け) | -| `sys_member` | 組織におけるユーザーのメンバーシップ(ロールはメンバーシップごとに割り当てられる) | -| `sys_business_unit`、`sys_team` | シェアルール向けの任意の組織構造 | -| `sys_invitation` | 承諾待ちの保留中の招待 | -| `sys_session` | アクティブな認証済みセッション | -| `sys_api_key` | ユーザーに紐づく長期間有効なプログラム用の認証情報 | - -マルチテナントのデプロイメントでは次のようになります。 - -- ユーザーはプロジェクトのデータベースにスコープされます。 -- セッションはプロジェクトのホスト名にスコープされます。 -- 行レベルのチェックには、現在のユーザーの組織と権限が使用されます。 -- コントロールプレーンのユーザーは自動的にビジネスユーザーには**なりません**。プラットフォームの SSO 経由でマッピングするか、明示的にプロビジョニングする必要があります。 - -これらは実行時に **Console**(`/_console/`)から作成・管理するか、新しい環境向けに `objectstack.config.ts` でシードします。 - -## レイヤー 2 — ロール - -ロールは組織図(CFO → 財務マネージャー → アナリスト)をモデル化します。これらが存在する主な目的は、シェアルールやレポートで「レコード所有者のマネージャー」といった表現を可能にすることです。階層的なアクセスが必要な場合はロールを使い、フラットなチームでは省略してください。 - -[ロール](/docs/configure/permissions/positions)を参照してください。 - -## レイヤー 3 — 権限セット - -権限セットは、機能を付与するための主要な手段です。ユーザーに直接、またはロール経由でアタッチされます。 - -### 付与する内容 - -| 種類 | 例 | -|---|---| -| アプリケーションアクセス | CRM を開く、サポートポータルを開く | -| オブジェクト権限 | オブジェクトのレコードの作成 / 読み取り / 更新 / 削除 | -| フィールド権限 | 特定のフィールドの読み取りまたは更新 | -| システム権限 | Console へのアクセス、レポートの実行、データのエクスポート、監査ログの閲覧 | -| 連携権限 | API キーの使用、Webhook の設定、管理アクションの実行 | - -### オブジェクト権限フラグ - -これらは security プラグインがチェックする正確なフラグ名です。 - -| フラグ | 意味 | -|---|---| -| `allowRead` | レコードアクセスを通じてユーザーが閲覧できるレコードを読み取る | -| `allowCreate` | 新しいレコードを作成する | -| `allowEdit` | ユーザーが閲覧できるレコードを更新する | -| `allowDelete` | ユーザーが閲覧できるレコードを削除する | -| `viewAllRecords` | レコードアクセスルールを無視して、そのオブジェクトの**すべて**のレコードを読み取る | -| `modifyAllRecords` | **すべて**のレコードを更新 / 削除する。`viewAllRecords` を含意する | - -`viewAllRecords` と `modifyAllRecords` は、そのオブジェクトに対するテナント全体のスーパーユーザー権限です。明示的な管理用の権限セットに限定し、ユーザー向けのロールには含めないでください。 - -[権限セット](/docs/configure/permissions/permission-sets)を参照してください。 - -## レイヤー 4 — レコードアクセス - -`viewAllRecords` を**持たない**ユーザーが閲覧できる行はどれでしょうか。 - -このモデルは次をサポートします。 - -- 暗黙的な所有権(ユーザーが作成または所有する行) -- シェアルール(宣言的 — 「チーム A はチーム A のレコードを閲覧できる」) -- 明示的な共有(`sys_record_share` の行 — 個別の共有) -- 組織スコープ(行の `organization_id` がユーザーの組織に一致する) - -[レコードアクセス](/docs/configure/permissions/record-access)を参照してください。 - -## レイヤー 5 — フィールドセキュリティ - -ユーザーがレコードを閲覧できる場合でも、個々のフィールドは次のように設定できます。 - -- **非表示** — フィールドは API および UI のレスポンスから除外されます。 -- **読み取り専用** — フィールドは返されますが、書き込みは拒否されます。 - -フィールドセキュリティは、オブジェクトごと + 権限セットごとに設定します。代表的な用途は次のとおりです。 - -- HR 以外のユーザーから `sys_user` の `salary` を非表示にする。 -- サポート担当者に対して `external_account_id` を読み取り可能だが編集不可にする。 - -これはオブジェクト権限と同じエバリュエーターで適用されるため、REST、ObjectQL、Console 全体に一貫して適用されます。 - -## どこから始めるか - -| 構築しているのが … | 使うもの | -|---|---| -| 単一チームの社内ツール | 権限セットのみ | -| マネージャーがレポートを閲覧するマルチチームアプリ | ロール + 権限セット | -| マルチテナントの SaaS 型アプリ | 組織スコープ + 権限セット | -| PII を扱う規制対象アプリ | 上記にフィールドセキュリティを追加 | -| 複雑な CRM 型アプリ | フルスタック | - -## 診断と監査 - -- `/_console/` は、任意のユーザーの実効権限を評価された状態で表示します。 -- 監査ログ(`sys_audit_log`)は、権限に関わる変更 — 付与、ロールの割り当て、権限セットの編集 — を記録します。 -- 拒否されたリクエストは、失敗したルール(オブジェクト権限 / レコードアクセス / フィールドセキュリティ)をログに残すため、サポートは「なぜこれが見えないのか」という問い合わせに迅速に答えられます。 diff --git a/content/docs/configure/permissions/index.ko.mdx b/content/docs/configure/permissions/index.ko.mdx deleted file mode 100644 index f997167..0000000 --- a/content/docs/configure/permissions/index.ko.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: 권한 -description: 신원, 역할, 권한 집합, 레코드 접근, 필드 보안 — 전체 접근 모델을 한 페이지에서. -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS는 엔터프라이즈 소프트웨어에서 20년간 검증된 방식을 차용한 계층형 접근 모델을 갖추고 있습니다: 신원 → 역할 → 권한 집합 → 레코드 접근 → 필드 보안. 각 계층은 서로 다른 질문에 답하며, 필요하지 않은 계층은 무시할 수 있습니다. - -## 하나의 다이어그램으로 보는 모델 - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Roles Where do they sit in the hierarchy? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -각 계층은 보안 플러그인에 의해 적용됩니다. 단순한 앱이라면 권한 집합만 사용하고(역할이나 공유 규칙 없이), 요구 사항이 생길 때 나머지를 추가할 수 있습니다. - -## 계층 1 — 신원 - -신원 객체는 프로젝트 데이터베이스에 존재합니다. 가장 중요한 것들은 다음과 같습니다: - -| 객체 | 의미 | -|---|---| -| `sys_user` | 인증할 수 있는 사람 또는 서비스 계정 | -| `sys_organization` | 테넌트 / 워크스페이스 경계(멀티테넌트 앱) | -| `sys_member` | 조직 내 사용자의 멤버십(역할은 멤버십 단위로 할당됨) | -| `sys_business_unit`, `sys_team` | 공유 규칙을 위한 선택적 조직 구조 | -| `sys_invitation` | 수락을 기다리는 대기 중인 초대 | -| `sys_session` | 활성 인증 세션 | -| `sys_api_key` | 사용자에 바인딩된 장기 프로그래밍 자격 증명 | - -멀티테넌트 배포에서는: - -- 사용자는 프로젝트 데이터베이스 범위로 한정됩니다. -- 세션은 프로젝트 호스트명 범위로 한정됩니다. -- 행 수준 검사는 현재 사용자의 조직과 권한을 사용합니다. -- 컨트롤 플레인 사용자는 자동으로 비즈니스 사용자가 **아닙니다** — 플랫폼 SSO 또는 명시적 프로비저닝을 통해 매핑되어야 합니다. - -이들은 런타임에 **Console**(`/_console/`)에서 생성/관리하거나, 새 환경을 위해 `objectstack.config.ts`에 시드할 수 있습니다. - -## 계층 2 — 역할 - -역할은 조직도(CFO → Finance Manager → Analyst)를 모델링합니다. 역할이 존재하는 주된 이유는 공유 규칙과 보고서가 "레코드 소유자의 관리자"와 같은 표현을 할 수 있게 하기 위함입니다. 계층적 접근이 필요할 때 역할을 사용하고, 평면적인 팀에서는 생략하세요. - -[역할](/docs/configure/permissions/positions)을 참조하세요. - -## 계층 3 — 권한 집합 - -권한 집합은 기능을 부여하는 주요 방법입니다. 사용자에게 직접 연결되거나 역할을 통해 연결됩니다. - -### 무엇을 부여하는가 - -| 유형 | 예시 | -|---|---| -| 애플리케이션 접근 | CRM 열기, 지원 포털 열기 | -| 객체 권한 | 객체의 레코드 생성 / 읽기 / 수정 / 삭제 | -| 필드 권한 | 특정 필드 읽기 또는 수정 | -| 시스템 권한 | Console 접근, 보고서 실행, 데이터 내보내기, 감사 로그 보기 | -| 통합 권한 | API 키 사용, 웹훅 구성, 관리 작업 실행 | - -### 객체 권한 플래그 - -다음은 보안 플러그인이 검사하는 정확한 플래그 이름입니다: - -| 플래그 | 의미 | -|---|---| -| `allowRead` | 레코드 접근을 통해 사용자가 볼 수 있는 레코드 읽기 | -| `allowCreate` | 새 레코드 생성 | -| `allowEdit` | 사용자가 볼 수 있는 레코드 수정 | -| `allowDelete` | 사용자가 볼 수 있는 레코드 삭제 | -| `viewAllRecords` | 레코드 접근 규칙을 무시하고 해당 객체의 **모든** 레코드 읽기 | -| `modifyAllRecords` | **모든** 레코드 수정/삭제; `viewAllRecords`를 함의함 | - -`viewAllRecords`와 `modifyAllRecords`는 해당 객체에 대한 테넌트 전역 슈퍼유저 권한입니다. 명시적인 관리용 권한 집합에만 한정하고, 사용자 대상 역할에서는 제외하세요. - -[권한 집합](/docs/configure/permissions/permission-sets)을 참조하세요. - -## 계층 4 — 레코드 접근 - -`viewAllRecords`가 **없는** 사용자의 경우, 어떤 행을 볼 수 있을까요? - -이 모델은 다음을 지원합니다: - -- 암묵적 소유권(사용자가 생성했거나 소유한 행) -- 공유 규칙(선언적 — "팀 A는 팀 A의 레코드를 본다") -- 명시적 공유(`sys_record_share` 행 — 일회성 공유) -- 조직 범위 지정(행의 `organization_id`가 사용자의 조직과 일치) - -[레코드 접근](/docs/configure/permissions/record-access)을 참조하세요. - -## 계층 5 — 필드 보안 - -사용자가 레코드를 볼 수 있는 경우에도, 개별 필드는 다음과 같이 설정될 수 있습니다: - -- **숨김** — 필드가 API 및 UI 응답에서 제거됩니다. -- **읽기 전용** — 필드는 반환되지만 쓰기 시 거부됩니다. - -필드 보안은 객체별 + 권한 집합별로 적용됩니다. 일반적인 사용 예: - -- HR 외부의 누구에게나 `sys_user`의 `salary`를 숨김. -- 지원 담당자에게 `external_account_id`를 읽을 수는 있지만 수정할 수는 없게 설정. - -이는 객체 권한과 동일한 평가기에서 적용되므로 REST, ObjectQL, Console 전반에 걸쳐 일관되게 작동합니다. - -## 어디서 시작할까 - -| 무엇을 만들고 있다면 … | 사용 | -|---|---| -| 단일 팀 내부 도구 | 권한 집합만 | -| 관리자가 보고서를 보는 멀티팀 앱 | 역할 + 권한 집합 | -| 멀티테넌트 SaaS 형태의 앱 | 조직 범위 지정 + 권한 집합 | -| PII가 있는 규제 대상 앱 | 그 위에 필드 보안 추가 | -| 복잡한 CRM 스타일 앱 | 전체 스택 | - -## 진단 및 감사 - -- `/_console/`는 평가되는 대로 모든 사용자의 유효 권한을 보여줍니다. -- 감사 로그(`sys_audit_log`)는 권한에 민감한 변경 사항(권한 부여, 역할 할당, 권한 집합 편집)을 기록합니다. -- 거부된 요청은 실패한 규칙(객체 권한, 레코드 접근, 필드 보안 중 무엇인지)을 기록하므로, 지원 담당자가 "왜 이걸 볼 수 없나요?"라는 질문에 빠르게 답할 수 있습니다. diff --git a/content/docs/configure/permissions/index.mdx b/content/docs/configure/permissions/index.mdx index 583fb80..fdd9869 100644 --- a/content/docs/configure/permissions/index.mdx +++ b/content/docs/configure/permissions/index.mdx @@ -61,11 +61,12 @@ seed them in `objectstack.config.ts` for fresh environments. Positions model job functions ("Sales Manager", "Support Agent"). They are flat — hierarchy lives on the business-unit tree, so sharing rules and reports say things like "the record owner's unit and subordinate -units." Two seeded audience anchors, `everyone` (all authenticated -users) and `guest` (anonymous callers), let you bind baseline -permission sets without custom fallback logic. Use positions to -distribute permission sets by function; skip custom positions for flat -teams. +units." The seeded audience anchor `everyone` (all authenticated +users) lets you bind baseline permission sets without custom fallback +logic. Its counterpart `guest` (anonymous callers) grants nothing: +anonymous visitors reach data only through a surface that declares it, +such as a public form or a share link. Use positions to distribute +permission sets by function; skip custom positions for flat teams. See [Positions](/docs/configure/permissions/positions). @@ -138,14 +139,21 @@ Even when a user can see a record, individual fields can be: - **Hidden** — field is stripped from API and UI responses. - **Read-only** — field is returned but rejected on write. +- **Masked** — field is returned with most of its value replaced + (`138****5678`), unless the caller holds the capabilities the field + requires (ObjectStack 17.1). -Field security is per object + per permission set. Typical use: +Hidden and read-only are set per object + per permission set; masking +is declared on the field itself. Typical use: - Hide `salary` on `sys_user` from anyone outside HR. - Make `external_account_id` readable but not editable to support reps. +- Show a customer's phone number as `138****5678` to everyone except + the team that calls customers. It's enforced in the same evaluator as object permissions, so it -applies uniformly across REST, ObjectQL, and the UI. +applies uniformly across REST, ObjectQL, and the UI. See +[Field-Level Security](/docs/configure/permissions/field-level-security). ## Where to start diff --git a/content/docs/configure/permissions/index.zh-Hans.mdx b/content/docs/configure/permissions/index.zh-Hans.mdx deleted file mode 100644 index 33b2b02..0000000 --- a/content/docs/configure/permissions/index.zh-Hans.mdx +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: 权限 -description: 身份、岗位、权限集、记录访问与字段安全 —— 一页讲完整套访问模型。 -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS 借鉴企业软件二十年来行之有效的分层访问模型:身份 → 岗位 → 权限集 → 记录访问 → 字段安全。每一层回答一个不同的问题,你可以忽略用不到的层。(ObjectStack 13 将旧的角色与简档概念合并为**岗位**——参见[岗位](/docs/configure/permissions/positions)。) - -## 一张图说明模型 - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Positions Which job functions do they hold? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -每一层都由 security 插件强制执行。简单应用可以只使用权限集(不用岗位、不用共享规则),等需求出现时再增补其余层。 - -## 第 1 层 —— 身份 - -身份对象存在你的项目数据库中。最重要的几个: - -| 对象 | 表示什么 | -|---|---| -| `sys_user` | 一个能认证的人或服务账号 | -| `sys_org` | 租户/工作空间边界(多租户应用) | -| `sys_member` | 用户在某组织内的成员资格 | -| `sys_business_unit`、`sys_team` | 可选的组织结构,用于共享规则 | -| `sys_invitation` | 待接受的邀请 | -| `sys_session` | 已认证的活动会话 | -| `sys_api_key` | 绑定到用户的长期编程凭据 | - -在多租户部署中: - -- 用户作用域限定到项目数据库。 -- 会话作用域限定到项目主机名。 -- 行级检查使用当前用户所在组织和权限。 -- 控制面用户**不会**自动成为业务用户——必须通过平台 SSO 或显式预置进行映射。 - -你可以在运行时通过 **Console**(`/_console/`)创建/管理这些对象,也可以在 `objectstack.config.ts` 中为全新环境种入。 - -## 第 2 层 —— 岗位 - -岗位对职能建模("销售经理"、"支持坐席")。岗位是扁平的——层级结构位于业务单元树上,因此共享规则和报表表达的是"记录所有者所在单元及下级单元"之类的关系。两个预置的受众锚点 `everyone`(所有已认证用户)和 `guest`(匿名调用者)让你无需自定义回退逻辑即可绑定基线权限集。用岗位按职能分发权限集;扁平团队可以不建自定义岗位。 - -参见[岗位](/docs/configure/permissions/positions)。 - -## 第 3 层 —— 权限集 - -权限集是授予能力的主要方式。它们直接附加到用户,或通过岗位附加。 - -### 它们授予什么 - -| 类型 | 示例 | -|---|---| -| 应用访问 | 打开 CRM、打开支持门户 | -| 对象权限 | 对某对象的记录进行 增/查/改/删 | -| 字段权限 | 读取或更新特定字段 | -| 系统权限 | 访问 Console、运行报表、导出数据、查看审计日志 | -| 集成权限 | 使用 API Key、配置 Webhook、执行管理操作 | - -### 对象权限标志 - -这些是 security 插件实际检查的标志名称: - -| 标志 | 含义 | -|---|---| -| `allowRead` | 读取通过记录访问可见的记录 | -| `allowCreate` | 创建新记录 | -| `allowEdit` | 更新用户可见的记录 | -| `allowDelete` | 删除用户可见的记录 | -| `viewAllRecords` | 读取该对象**每一条**记录,忽略记录访问规则 | -| `modifyAllRecords` | 更新/删除**每一条**记录;隐含 `viewAllRecords` | - -`viewAllRecords` 与 `modifyAllRecords` 是对该对象的租户级超级用户授权。仅在显式的管理权限集中使用,不要放进任何面向普通用户的岗位。 - -参见 [Permission Sets](/docs/configure/permissions/permission-sets)。 - -## 第 4 层 —— 记录访问 - -对于**没有** `viewAllRecords` 的用户,他们能看到哪些行? - -模型支持: - -- 隐式所有权(用户创建或拥有的行) -- 共享规则(声明式 —— "团队 A 能看到团队 A 的记录") -- 显式共享(`sys_record_share` 行——一次性共享,可授予用户、岗位或"单元及下级单元") -- 组织作用域(行的 `org_id` 与用户所在组织匹配) - -自 ObjectStack 13 起,带有所有者字段的自定义对象默认使用**私有**共享模型——需要开放时请显式声明 `sharingModel`。 - -参见 [Record Access](/docs/configure/permissions/record-access)。 - -## 第 5 层 —— 字段安全 - -即使用户能看到记录,单独的字段也可以是: - -- **隐藏** —— 字段被从 API 和 UI 响应中剥离。 -- **只读** —— 字段返回,但写入会被拒绝。 - -字段安全是按对象 + 按权限集设定的。典型用途: - -- 把 `sys_user` 上的 `salary` 对 HR 之外的所有人隐藏。 -- 把 `external_account_id` 对支持代表设为可读但不可编辑。 - -它在与对象权限相同的求值器中强制执行,因此在 REST、ObjectQL 和 Console 上统一生效。 - -## 从哪里入手 - -| 如果你在构建 …… | 使用 | -|---|---| -| 单团队的内部工具 | 仅权限集 | -| 多团队、经理需要看报表的应用 | 业务单元 + 岗位 + 权限集 | -| 多租户 SaaS 形态的应用 | 组织作用域 + 权限集 | -| 带 PII 的合规应用 | 在上面叠加字段安全 | -| 复杂的 CRM 类应用 | 完整栈 | - -## 诊断与审计 - -- **解释引擎**(`explain(principal, object, operation)`)按顺序报告每一层的判定结果——所需权限、对象 CRUD、字段安全、OWD 基线、共享、行级安全——并给出逐层归因。Console 将其呈现为"该用户为何能访问?"面板。解释其他用户需要 `manage_users` 能力。 -- `/_console/` 显示任一用户当前评估出的有效权限。 -- 审计日志(`sys_audit_log`)记录权限敏感变更——授权、岗位分配、权限集编辑。 -- 被拒请求记录失败的具体规则(对象权限 vs 记录访问 vs 字段安全),便于支持人员快速回答"为什么我看不到这个?"。 diff --git a/content/docs/configure/permissions/index.zh-Hant.mdx b/content/docs/configure/permissions/index.zh-Hant.mdx deleted file mode 100644 index 2b6e493..0000000 --- a/content/docs/configure/permissions/index.zh-Hant.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant -title: 許可權 -description: 身份、崗位、許可權集、記錄訪問與欄位安全 —— 一頁講完整套訪問模型。 -translation: - source_sha: a3f6767f973862267ab70d0ce8f90587d2af0df0edddc43babcf58bcce8e23c3 - guide_rev: 1 - mode: auto ---- - -ObjectOS 借鑑企業軟體二十年來行之有效的分層訪問模型:身份 → 崗位 → 許可權集 → 記錄訪問 → 欄位安全。每一層回答一個不同的問題,你可以忽略用不到的層。(ObjectStack 13 將舊的角色與簡檔概念合併為**崗位**——參見[崗位](/docs/configure/permissions/positions)。) - -## 一張圖說明模型 - -```text -Authentication Who is the caller? - ↓ -Identity Which user/org/membership is active? - ↓ -Positions Which job functions do they hold? - ↓ -Permission sets What CAN they do — apps, objects, fields, system? - ↓ -Record access WHICH records can they touch? - ↓ -Field security For those records, which FIELDS are readable / writable? -``` - -每一層都由 security 外掛強制執行。簡單應用可以只使用許可權集(不用崗位、不用共享規則),等需求出現時再增補其餘層。 - -## 第 1 層 —— 身份 - -身份物件存在你的專案資料庫中。最重要的幾個: - -| 物件 | 表示什麼 | -|---|---| -| `sys_user` | 一個能認證的人或服務賬號 | -| `sys_org` | 租戶/工作空間邊界(多租戶應用) | -| `sys_member` | 使用者在某組織內的成員資格 | -| `sys_business_unit`、`sys_team` | 可選的組織結構,用於共享規則 | -| `sys_invitation` | 待接受的邀請 | -| `sys_session` | 已認證的活動會話 | -| `sys_api_key` | 繫結到使用者的長期程式設計憑據 | - -在多租戶部署中: - -- 使用者作用域限定到專案資料庫。 -- 會話作用域限定到專案主機名。 -- 行級檢查使用當前使用者所在組織和許可權。 -- 控制面使用者**不會**自動成為業務使用者——必須通過平臺 SSO 或顯式預置進行對映。 - -你可以在執行時通過 **Console**(`/_console/`)建立/管理這些物件,也可以在 `objectstack.config.ts` 中為全新環境種入。 - -## 第 2 層 —— 崗位 - -崗位對職能建模("銷售經理"、"支援坐席")。崗位是扁平的——層級結構位於業務單元樹上,因此共享規則和報表表達的是"記錄所有者所在單元及下級單元"之類的關係。兩個預置的受眾錨點 `everyone`(所有已認證使用者)和 `guest`(匿名呼叫者)讓你無需自定義回退邏輯即可繫結基線許可權集。用崗位按職能分發許可權集;扁平團隊可以不建自定義崗位。 - -參見[崗位](/docs/configure/permissions/positions)。 - -## 第 3 層 —— 許可權集 - -許可權集是授予能力的主要方式。它們直接附加到使用者,或通過崗位附加。 - -### 它們授予什麼 - -| 型別 | 示例 | -|---|---| -| 應用訪問 | 開啟 CRM、開啟支援門戶 | -| 物件許可權 | 對某物件的記錄進行 增/查/改/刪 | -| 欄位許可權 | 讀取或更新特定欄位 | -| 系統許可權 | 訪問 Console、執行報表、匯出資料、檢視審計日誌 | -| 整合許可權 | 使用 API Key、配置 Webhook、執行管理操作 | - -### 物件許可權標誌 - -這些是 security 外掛實際檢查的標誌名稱: - -| 標誌 | 含義 | -|---|---| -| `allowRead` | 讀取通過記錄訪問可見的記錄 | -| `allowCreate` | 建立新記錄 | -| `allowEdit` | 更新使用者可見的記錄 | -| `allowDelete` | 刪除使用者可見的記錄 | -| `viewAllRecords` | 讀取該物件**每一條**記錄,忽略記錄訪問規則 | -| `modifyAllRecords` | 更新/刪除**每一條**記錄;隱含 `viewAllRecords` | - -`viewAllRecords` 與 `modifyAllRecords` 是對該物件的租戶級超級使用者授權。僅在顯式的管理許可權集中使用,不要放進任何面向普通使用者的崗位。 - -參見 [Permission Sets](/docs/configure/permissions/permission-sets)。 - -## 第 4 層 —— 記錄訪問 - -對於**沒有** `viewAllRecords` 的使用者,他們能看到哪些行? - -模型支援: - -- 隱式所有權(使用者建立或擁有的行) -- 共享規則(宣告式 —— "團隊 A 能看到團隊 A 的記錄") -- 顯式共享(`sys_record_share` 行——一次性共享,可授予使用者、崗位或"單元及下級單元") -- 組織作用域(行的 `org_id` 與使用者所在組織匹配) - -自 ObjectStack 13 起,帶有所有者欄位的自定義物件預設使用**私有**共享模型——需要開放時請顯式宣告 `sharingModel`。 - -參見 [Record Access](/docs/configure/permissions/record-access)。 - -## 第 5 層 —— 欄位安全 - -即使使用者能看到記錄,單獨的欄位也可以是: - -- **隱藏** —— 欄位被從 API 和 UI 響應中剝離。 -- **只讀** —— 欄位返回,但寫入會被拒絕。 - -欄位安全是按物件 + 按許可權集設定的。典型用途: - -- 把 `sys_user` 上的 `salary` 對 HR 之外的所有人隱藏。 -- 把 `external_account_id` 對支援代表設為可讀但不可編輯。 - -它在與物件許可權相同的求值器中強制執行,因此在 REST、ObjectQL 和 Console 上統一生效。 - -## 從哪裡入手 - -| 如果你在構建 …… | 使用 | -|---|---| -| 單團隊的內部工具 | 僅許可權集 | -| 多團隊、經理需要看報表的應用 | 業務單元 + 崗位 + 許可權集 | -| 多租戶 SaaS 形態的應用 | 組織作用域 + 許可權集 | -| 帶 PII 的合規應用 | 在上面疊加欄位安全 | -| 複雜的 CRM 類應用 | 完整棧 | - -## 診斷與審計 - -- **解釋引擎**(`explain(principal, object, operation)`)按順序報告每一層的判定結果——所需許可權、物件 CRUD、欄位安全、OWD 基線、共享、行級安全——並給出逐層歸因。Console 將其呈現為"該使用者為何能訪問?"面板。解釋其他使用者需要 `manage_users` 能力。 -- `/_console/` 顯示任一使用者當前評估出的有效許可權。 -- 審計日誌(`sys_audit_log`)記錄許可權敏感變更——授權、崗位分配、許可權集編輯。 -- 被拒請求記錄失敗的具體規則(物件許可權 vs 記錄訪問 vs 欄位安全),便於支援人員快速回答"為什麼我看不到這個?"。 diff --git a/content/docs/configure/permissions/permission-sets.mdx b/content/docs/configure/permissions/permission-sets.mdx index 034d295..b6a350a 100644 --- a/content/docs/configure/permissions/permission-sets.mdx +++ b/content/docs/configure/permissions/permission-sets.mdx @@ -127,6 +127,26 @@ Then add domain-specific sets for the customer's application. Marking a set `isDefault` suggests it for assignment when the owning package is installed (this replaces the pre-13 `isProfile` flag). +## Deactivating a permission set + +A permission set's **Deactivate** action stops it granting, immediately +(ObjectStack 17.1). A deactivated set contributes none of its object, +field, system or tab permissions — and none of the administrator +standing it would otherwise confer — whether it reaches the user directly +or through a position. A set whose `active` value is empty is +unaffected; only an explicit deactivation counts. + +Two consequences: + +- **You cannot lock everyone out with it.** Deactivating the set that + makes your administrators administrators is refused by the same + last-administrator guard that refuses deleting it. +- **Upgrading past 17.1 is a revocation.** Before 17.1 the switch was + inert, and a deactivated set kept granting. Before you upgrade, list + the deactivated sets and positions and re-activate any that are still + meant to grant — see + [Deactivating a position](/docs/configure/permissions/positions#deactivating-a-position). + ## Delegated administration A permission set can carry an `adminScope` that turns its holders into @@ -156,6 +176,11 @@ read a record, individual fields can be hidden or made read-only. | **Hidden** | Field is stripped from API responses and generated views entirely | | **Read-only** | Field is returned but writes are rejected | +A third state, **masked** (`138****5678`), is not a permission-set mode: +it is declared on the field, and a permission set only decides who holds +the capabilities that unmask it. See +[Field-Level Security](/docs/configure/permissions/field-level-security#masked-fields). + ### Where it's enforced The same evaluator that checks object permissions applies field rules diff --git a/content/docs/configure/permissions/positions.de.mdx b/content/docs/configure/permissions/positions.de.mdx deleted file mode 100644 index cfa43f0..0000000 --- a/content/docs/configure/permissions/positions.de.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Rollen -description: Modellhierarchie und Verantwortung im Management mit Rollen. -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -Rollen beschreiben die Position eines Benutzers in der Organisation. Sie sind -nützlich für Hierarchie und Verantwortung im Management, sollten aber nicht -zur einzigen Möglichkeit werden, Berechtigungen zu vergeben. - -## Rollenverantwortlichkeiten - -Verwenden Sie Rollen, um Folgendes zu modellieren: - -- Beziehungen zwischen Vorgesetzten und Untergebenen; -- Abteilungs- oder Teamhierarchie; -- Datensatzsichtbarkeit basierend auf der Eigentümerhierarchie; -- Genehmigungsverantwortung; -- Berichtsstruktur. - -Verwenden Sie [Berechtigungssätze](/docs/configure/permissions/permission-sets), -um konkrete Objekt-, Feld- und Systemfunktionen zu vergeben. - -## Systemobjekte - -| Objekt | Zweck | -|---|---| -| `sys_role` | Rollendefinition und Hierarchie | -| `sys_role_permission_set` | Über eine Rolle zugewiesene Berechtigungssätze | -| `sys_member` | Organisationszugehörigkeit und Rollenkontext des Benutzers | - -## Empfohlenes Muster - -Beginnen Sie mit einer kleinen Rollenhierarchie: - -```text -System Administrator -Sales Director -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -Hängen Sie dann Berechtigungssätze für Funktionen an: - -```text -Sales Manager role - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -Dadurch bleibt der Rollenbaum stabil, während sich die Berechtigungen -weiterentwickeln können. - -## Vermeiden - -- eine Rolle pro einzelnem Benutzer; -- das Duplizieren jeder Berechtigung in jeder Rolle; -- die Verwendung von Rollennamen als Prüfungen in der Geschäftslogik; -- das Gewähren von weitreichendem Zugriff über Manager-Rollen, wenn - [Datensatzfreigabe](/docs/configure/permissions/record-access) präziser - wäre. diff --git a/content/docs/configure/permissions/positions.es.mdx b/content/docs/configure/permissions/positions.es.mdx deleted file mode 100644 index 21cbae9..0000000 --- a/content/docs/configure/permissions/positions.es.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Roles -description: Jerarquía del modelo y responsabilidad de gestión con roles. -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -Los roles describen la posición de un usuario en la organización. Resultan -útiles para la jerarquía y la responsabilidad de gestión, pero no deberían -convertirse en la única forma de otorgar permisos. - -## Responsabilidades de los roles - -Usa los roles para modelar: - -- relaciones entre responsable y subordinado; -- jerarquía de departamentos o equipos; -- visibilidad de registros según la jerarquía de propiedad; -- responsabilidad de aprobación; -- estructura de informes. - -Usa los [conjuntos de permisos](/docs/configure/permissions/permission-sets) -para otorgar capacidades concretas de objetos, campos y sistema. - -## Objetos del sistema - -| Objeto | Propósito | -|---|---| -| `sys_role` | Definición y jerarquía de roles | -| `sys_role_permission_set` | Conjuntos de permisos asignados a través de un rol | -| `sys_member` | Pertenencia del usuario a la organización y contexto de rol | - -## Patrón recomendado - -Comienza con una pequeña jerarquía de roles: - -```text -System Administrator -Sales Director -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -Luego adjunta conjuntos de permisos para las capacidades: - -```text -Sales Manager role - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -Esto mantiene estable el árbol de roles mientras permite que los permisos -evolucionen. - -## Evita - -- un rol por cada usuario individual; -- duplicar cada permiso dentro de cada rol; -- usar los nombres de los roles como comprobaciones de lógica de negocio; -- otorgar acceso amplio a través de roles de responsable cuando el - [uso compartido de registros](/docs/configure/permissions/record-access) - sería más preciso. diff --git a/content/docs/configure/permissions/positions.fr.mdx b/content/docs/configure/permissions/positions.fr.mdx deleted file mode 100644 index 5b3662b..0000000 --- a/content/docs/configure/permissions/positions.fr.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Rôles -description: Hiérarchie du modèle et responsabilité de gestion grâce aux rôles. -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -Les rôles décrivent la position d'un utilisateur dans l'organisation. Ils sont -utiles pour la hiérarchie et la responsabilité de gestion, mais ils ne doivent -pas devenir le seul moyen d'accorder des permissions. - -## Responsabilités des rôles - -Utilisez les rôles pour modéliser : - -- les relations responsable/subordonné ; -- la hiérarchie des départements ou des équipes ; -- la visibilité des enregistrements selon la hiérarchie de propriété ; -- la responsabilité d'approbation ; -- la structure hiérarchique de reporting. - -Utilisez les [ensembles de permissions](/docs/configure/permissions/permission-sets) -pour accorder des capacités concrètes sur les objets, les champs et le système. - -## Objets système - -| Objet | Finalité | -|---|---| -| `sys_role` | Définition et hiérarchie des rôles | -| `sys_role_permission_set` | Ensembles de permissions attribués via un rôle | -| `sys_member` | Appartenance à l'organisation et contexte de rôle de l'utilisateur | - -## Modèle recommandé - -Commencez par une petite hiérarchie de rôles : - -```text -System Administrator -Sales Director -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -Attachez ensuite des ensembles de permissions pour les capacités : - -```text -Sales Manager role - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -Cela maintient la stabilité de l'arborescence des rôles tout en permettant aux -permissions d'évoluer. - -## À éviter - -- un rôle par utilisateur individuel ; -- la duplication de chaque permission à l'intérieur de chaque rôle ; -- l'utilisation des noms de rôles comme contrôles de logique métier ; -- l'octroi d'un accès étendu via les rôles de responsable alors que le - [partage d'enregistrements](/docs/configure/permissions/record-access) serait - plus précis. diff --git a/content/docs/configure/permissions/positions.ja.mdx b/content/docs/configure/permissions/positions.ja.mdx deleted file mode 100644 index 6a745cd..0000000 --- a/content/docs/configure/permissions/positions.ja.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: ロール -description: ロールによる階層構造と管理責任のモデリング。 -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -ロールは、組織におけるユーザーの位置づけを表します。階層構造や管理責任を -モデリングするのに役立ちますが、権限を付与する唯一の手段にすべきでは -ありません。 - -## ロールの責務 - -ロールは次のようなモデリングに使用します。 - -- 上司/部下の関係。 -- 部門やチームの階層構造。 -- 所有権の階層に基づくレコードの可視性。 -- 承認責任。 -- 報告体系。 - -具体的なオブジェクト、フィールド、システム機能の権限を付与するには、 -[権限セット](/docs/configure/permissions/permission-sets)を使用してください。 - -## システムオブジェクト - -| オブジェクト | 目的 | -|---|---| -| `sys_role` | ロールの定義と階層 | -| `sys_role_permission_set` | ロールを通じて割り当てられる権限セット | -| `sys_member` | ユーザーの組織メンバーシップとロールのコンテキスト | - -## 推奨パターン - -まずは小さなロール階層から始めます。 - -```text -System Administrator -Sales Director -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -次に、機能を付与するための権限セットを割り当てます。 - -```text -Sales Manager role - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -これにより、権限を進化させながらロールツリーを安定して保つことができます。 - -## 避けるべきこと - -- ユーザー個人ごとに1つのロールを作成すること。 -- すべての権限を各ロール内で重複して定義すること。 -- ロール名をビジネスロジックの判定に使用すること。 -- [レコード共有](/docs/configure/permissions/record-access)の方がより - 精密に制御できる場面で、マネージャーロールを通じて広範なアクセスを - 付与すること。 diff --git a/content/docs/configure/permissions/positions.ko.mdx b/content/docs/configure/permissions/positions.ko.mdx deleted file mode 100644 index f43ec19..0000000 --- a/content/docs/configure/permissions/positions.ko.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: 역할 -description: 역할을 통한 모델 계층 구조와 관리 책임. -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -역할은 조직 내에서 사용자의 위치를 나타냅니다. 계층 구조와 관리 책임을 -표현하는 데 유용하지만, 권한을 부여하는 유일한 수단이 되어서는 안 됩니다. - -## 역할의 책임 - -다음을 모델링하는 데 역할을 사용하세요. - -- 관리자/하위자 관계; -- 부서 또는 팀 계층 구조; -- 소유권 계층 구조에 기반한 레코드 가시성; -- 승인 책임; -- 보고 체계. - -구체적인 객체, 필드, 시스템 기능을 부여하려면 -[권한 집합](/docs/configure/permissions/permission-sets)을 사용하세요. - -## 시스템 객체 - -| 객체 | 용도 | -|---|---| -| `sys_role` | 역할 정의 및 계층 구조 | -| `sys_role_permission_set` | 역할을 통해 할당된 권한 집합 | -| `sys_member` | 사용자의 조직 멤버십 및 역할 컨텍스트 | - -## 권장 패턴 - -작은 역할 계층 구조로 시작하세요. - -```text -System Administrator -Sales Director -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -그런 다음 기능을 위한 권한 집합을 연결하세요. - -```text -Sales Manager role - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -이렇게 하면 권한이 발전하는 동안에도 역할 트리를 안정적으로 유지할 수 있습니다. - -## 피해야 할 사항 - -- 개별 사용자마다 하나의 역할을 만드는 것; -- 모든 역할 안에 동일한 권한을 중복으로 넣는 것; -- 역할 이름을 비즈니스 로직 검사에 사용하는 것; -- [레코드 공유](/docs/configure/permissions/record-access)가 더 정밀할 수 있는 상황에서 - 관리자 역할을 통해 광범위한 접근 권한을 부여하는 것. diff --git a/content/docs/configure/permissions/positions.mdx b/content/docs/configure/permissions/positions.mdx index b3202f6..ffbe20b 100644 --- a/content/docs/configure/permissions/positions.mdx +++ b/content/docs/configure/permissions/positions.mdx @@ -56,10 +56,17 @@ Two system-managed positions are seeded in every deployment: | `guest` | Sessionless (anonymous) HTTP principals only | Bind a permission set to `everyone` to grant a baseline to all signed-in -users; bind to `guest` to open something to anonymous visitors. Bindings -are additive, and the platform refuses to bind high-privilege sets -(View All / Modify All, delete/purge/transfer, system permissions, -wildcards) to these anchors. +users. Bindings are additive, and the platform refuses to bind +high-privilege sets (View All / Modify All, delete/purge/transfer, +system permissions, wildcards) to these anchors. + +**`guest` grants nothing.** Anonymous access to object data is denied +on every HTTP surface (ObjectStack 17.0), and no binding on the `guest` +anchor gives an anonymous caller a permission set (ObjectStack 17.6). +Open something to anonymous visitors by declaring the +surface instead — a +[public form](/docs/build/interface/views#public-forms) or a share +link — each of which authorizes only what it declares. The configured baseline permission set (`fallbackPermissionSet`, default `member_default`) applies through the same `everyone` binding path. Note @@ -67,6 +74,36 @@ that since ObjectStack 14.2 the member baseline no longer includes **delete** — record deletion must be granted explicitly per object through position-distributed permission sets. +**A caller with no permission set gets the deny baseline** (ObjectStack +17.6). A request that resolves no permission set at all — an anonymous +request, or one naming only sets that do not exist — is refused every +object with `403 PERMISSION_DENIED`. It is not served a field gated by +`requiredPermissions` (or is served it masked, if the field declares a +`maskingRule`), and cannot filter, sort, group or write on one. Signed-in +users are unaffected as long as a baseline set is configured — the +default, `member_default`, always resolves for them. + +## Deactivating a position + +A position's **Deactivate** action takes away everything it confers, +immediately (ObjectStack 17.1): + +- it distributes none of its permission sets, and its name leaves the + holders' `current_user.positions`; +- a sharing rule whose recipient is the position shares with nobody, + and the record shares it had already granted are revoked on the next + reconcile. + +Deactivation stops access, not addressing: an approval step with an +approver of type `position` still routes to the holders of a +deactivated position. A position whose `active` value is empty is +unaffected — only an explicit deactivation counts. + +> Before ObjectStack 17.1 the switch was inert: a deactivated position +> kept granting. Upgrading past it revokes that access on live data, so +> re-activate any deactivated position that is still meant to grant +> before you upgrade. + ## Effective-dated assignments Position and permission-set assignments carry optional `valid_from` / diff --git a/content/docs/configure/permissions/positions.zh-Hans.mdx b/content/docs/configure/permissions/positions.zh-Hans.mdx deleted file mode 100644 index 6ad2541..0000000 --- a/content/docs/configure/permissions/positions.zh-Hans.mdx +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: 岗位 -description: 使用岗位对职能和受众锚点进行建模。 -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -岗位描述用户所承担的职能——"销售经理"、"支持坐席"、"审计员"。 -自 ObjectStack 13(权限模型 v2,ADR-0090)起,岗位是**唯一**的人员分组概念: -旧的角色(Role)和简档(Profile)框架已合并为岗位,并从协议中移除。 - -岗位刻意保持**扁平**。岗位没有 `parent` 字段,也没有岗位层级—— -汇报结构和基于子树的可见性由[业务单元树](/docs/configure/permissions/record-access)承载。 - -## 岗位职责 - -使用岗位来建模: - -- 职能("销售经理"、"招聘专员"、"审计员"); -- 应用、选项卡和知识库(Book)的受众定向; -- 审批职责(类型为 `position` 的审批人会自动展开为当前岗位持有者); -- 向持有相同职能的所有用户分发[权限集](/docs/configure/permissions/permission-sets)。 - -使用**业务单元**来建模组织架构(部门、区域、上下级结构),使用**权限集**来授予具体的对象、字段和系统能力。 - -## 系统对象 - -| 对象 | 用途 | -|---|---| -| `sys_position` | 岗位定义(扁平——无层级) | -| `sys_user_position` | 用户的岗位分配 | -| `sys_position_permission_set` | 通过岗位分发的权限集 | -| `sys_business_unit` | 用于层级和子树共享的组织架构树 | -| `sys_business_unit_member` | 用户在业务单元中的成员身份(`function_in_business_unit`) | - -对 RBAC 关联表(`sys_user_position`、`sys_position_permission_set`、 -`sys_user_permission_set`、`sys_permission_set`)的写入需要租户级管理员权限或 -[委托管理范围](/docs/configure/permissions/permission-sets#委托管理delegated-administration)—— -仅对这些表授予普通 CRUD 权限是不够的。 - -## 受众锚点:`everyone` 与 `guest` - -每个部署都会预置两个系统管理的岗位: - -| 锚点 | 持有者 | -|---|---| -| `everyone` | 所有已认证的主体(隐式持有) | -| `guest` | 仅无会话(匿名)HTTP 主体 | - -将权限集绑定到 `everyone` 可为所有已登录用户授予基线权限;绑定到 `guest` -可向匿名访问者开放内容。绑定是叠加式的,并且平台会拒绝将高权限集 -(View All / Modify All、删除/清除/转移、系统权限、通配符)绑定到这些锚点。 - -配置的基线权限集(`fallbackPermissionSet`,默认 `member_default`)通过同一条 -`everyone` 绑定路径生效。注意:自 ObjectStack 14.2 起,成员基线不再包含**删除**权限—— -记录删除必须按对象通过岗位分发的权限集显式授予。 - -## 带生效期的分配 - -岗位与权限集分配支持可选的 `valid_from` / `valid_until` 时间窗口 -(半开区间,UTC;null 表示无界)。过期的授权会立即失效——适用于临时代班、 -外包人员和与认证绑定的访问。每条授权可以记录 `reason`,委托授权还会记录 -`delegated_from`。 - -标记为 `delegatable: true` 的岗位允许其当前持有者在有限时间窗口内将岗位自助 -委托给其他用户(必须设置未来的 `valid_until`,上限 30 天,且必须填写原因)。 -分发了管理范围(adminScope)权限集的岗位永远不能被委托。 - -## 推荐模式 - -保持一组精简、稳定、以职能为单位的岗位: - -```text -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -用业务单元建模组织架构: - -```text -Sales - ├─ EMEA - └─ AMER -Support -``` - -然后为岗位附加权限集: - -```text -Sales Manager 岗位 - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -这样可以保持岗位稳定,同时允许权限独立演进。 - -## 应避免 - -- 为每个用户单独创建一个岗位; -- 在每个岗位中重复定义所有权限; -- 将岗位名称用作业务逻辑判断条件; -- 在岗位上重建层级结构——子树可见性属于业务单元和[记录共享](/docs/configure/permissions/record-access); -- 在记录共享能更精确实现需求时,却通过管理岗位授予宽泛的访问权限。 - -## 从角色迁移(13 之前) - -如果你要升级针对 ObjectStack 12 或更早版本编写的元数据: - -| 旧版 | 现行 | -|---|---| -| `sys_role` / `sys_user_role` / `sys_role_permission_set` | `sys_position` / `sys_user_position` / `sys_position_permission_set` | -| `defineRole` / `RoleSchema`(含 `parent`) | `definePosition` / `PositionSchema`(扁平) | -| 元数据类型 `role` 或 `profile` | `position` | -| 共享接收者 `role` / `role_and_subordinates` | `position` / `unit_and_subordinates` | -| `PermissionSetSchema.isProfile` | 已移除——`isDefault` 用于标记安装时的建议分配范围 | - -角色层级必须重新建模为业务单元树。`os lint` 会通过 `security-role-word` -规则标记遗留的角色词汇。 diff --git a/content/docs/configure/permissions/positions.zh-Hant.mdx b/content/docs/configure/permissions/positions.zh-Hant.mdx deleted file mode 100644 index 8d51025..0000000 --- a/content/docs/configure/permissions/positions.zh-Hant.mdx +++ /dev/null @@ -1,124 +0,0 @@ ---- -# @generated zh-Hant from zh-Hans -- do not edit. Edit the English source, then regenerate: pnpm --filter @objectos/docs gen:zh-hant -title: 崗位 -description: 使用崗位對職能和受眾錨點進行建模。 -translation: - source_sha: 9849d4ab328562e9ec4fb1afcdb480e94cded9dff888bcf1cfadf9b2b8233e4b - guide_rev: 1 - mode: auto ---- - -崗位描述使用者所承擔的職能——"銷售經理"、"支援坐席"、"審計員"。 -自 ObjectStack 13(許可權模型 v2,ADR-0090)起,崗位是**唯一**的人員分組概念: -舊的角色(Role)和簡檔(Profile)框架已合併為崗位,並從協議中移除。 - -崗位刻意保持**扁平**。崗位沒有 `parent` 欄位,也沒有崗位層級—— -彙報結構和基於子樹的可見性由[業務單元樹](/docs/configure/permissions/record-access)承載。 - -## 崗位職責 - -使用崗位來建模: - -- 職能("銷售經理"、"招聘專員"、"審計員"); -- 應用、選項卡和知識庫(Book)的受眾定向; -- 審批職責(型別為 `position` 的審批人會自動展開為當前崗位持有者); -- 向持有相同職能的所有使用者分發[許可權集](/docs/configure/permissions/permission-sets)。 - -使用**業務單元**來建模組織架構(部門、區域、上下級結構),使用**許可權集**來授予具體的物件、欄位和系統能力。 - -## 系統物件 - -| 物件 | 用途 | -|---|---| -| `sys_position` | 崗位定義(扁平——無層級) | -| `sys_user_position` | 使用者的崗位分配 | -| `sys_position_permission_set` | 通過崗位分發的許可權集 | -| `sys_business_unit` | 用於層級和子樹共享的組織架構樹 | -| `sys_business_unit_member` | 使用者在業務單元中的成員身份(`function_in_business_unit`) | - -對 RBAC 關聯表(`sys_user_position`、`sys_position_permission_set`、 -`sys_user_permission_set`、`sys_permission_set`)的寫入需要租戶級管理員許可權或 -[委託管理範圍](/docs/configure/permissions/permission-sets#委託管理delegated-administration)—— -僅對這些表授予普通 CRUD 許可權是不夠的。 - -## 受眾錨點:`everyone` 與 `guest` - -每個部署都會預置兩個系統管理的崗位: - -| 錨點 | 持有者 | -|---|---| -| `everyone` | 所有已認證的主體(隱式持有) | -| `guest` | 僅無會話(匿名)HTTP 主體 | - -將許可權集繫結到 `everyone` 可為所有已登入使用者授予基線許可權;繫結到 `guest` -可向匿名訪問者開放內容。繫結是疊加式的,並且平臺會拒絕將高許可權集 -(View All / Modify All、刪除/清除/轉移、系統許可權、萬用字元)繫結到這些錨點。 - -配置的基線許可權集(`fallbackPermissionSet`,預設 `member_default`)通過同一條 -`everyone` 繫結路徑生效。注意:自 ObjectStack 14.2 起,成員基線不再包含**刪除**許可權—— -記錄刪除必須按物件通過崗位分發的許可權集顯式授予。 - -## 帶生效期的分配 - -崗位與許可權集分配支援可選的 `valid_from` / `valid_until` 時間視窗 -(半開區間,UTC;null 表示無界)。過期的授權會立即失效——適用於臨時代班、 -外包人員和與認證繫結的訪問。每條授權可以記錄 `reason`,委託授權還會記錄 -`delegated_from`。 - -標記為 `delegatable: true` 的崗位允許其當前持有者在有限時間視窗內將崗位自助 -委託給其他使用者(必須設定未來的 `valid_until`,上限 30 天,且必須填寫原因)。 -分發了管理範圍(adminScope)許可權集的崗位永遠不能被委託。 - -## 推薦模式 - -保持一組精簡、穩定、以職能為單位的崗位: - -```text -Sales Manager -Sales Representative -Support Manager -Support Agent -``` - -用業務單元建模組織架構: - -```text -Sales - ├─ EMEA - └─ AMER -Support -``` - -然後為崗位附加許可權集: - -```text -Sales Manager 岗位 - -> CRM User - -> Sales Manager Access - -> Report Viewer -``` - -這樣可以保持崗位穩定,同時允許許可權獨立演進。 - -## 應避免 - -- 為每個使用者單獨建立一個崗位; -- 在每個崗位中重複定義所有許可權; -- 將崗位名稱用作業務邏輯判斷條件; -- 在崗位上重建層級結構——子樹可見性屬於業務單元和[記錄共享](/docs/configure/permissions/record-access); -- 在記錄共享能更精確實現需求時,卻通過管理崗位授予寬泛的訪問許可權。 - -## 從角色遷移(13 之前) - -如果你要升級針對 ObjectStack 12 或更早版本編寫的後設資料: - -| 舊版 | 現行 | -|---|---| -| `sys_role` / `sys_user_role` / `sys_role_permission_set` | `sys_position` / `sys_user_position` / `sys_position_permission_set` | -| `defineRole` / `RoleSchema`(含 `parent`) | `definePosition` / `PositionSchema`(扁平) | -| 後設資料型別 `role` 或 `profile` | `position` | -| 共享接收者 `role` / `role_and_subordinates` | `position` / `unit_and_subordinates` | -| `PermissionSetSchema.isProfile` | 已移除——`isDefault` 用於標記安裝時的建議分配範圍 | - -角色層級必須重新建模為業務單元樹。`os lint` 會通過 `security-role-word` -規則標記遺留的角色詞彙。 diff --git a/content/docs/configure/permissions/record-access.mdx b/content/docs/configure/permissions/record-access.mdx index 4fa1e55..11536c0 100644 --- a/content/docs/configure/permissions/record-access.mdx +++ b/content/docs/configure/permissions/record-access.mdx @@ -92,6 +92,34 @@ grants nothing" or "this policy is off", it is worth re-running the [explain engine](/docs/configure/permissions#diagnose--audit) — the answer may have been wider than the metadata said. +## Row-level security refuses what it cannot enforce + +Since ObjectStack 17.5, an RLS policy narrows exactly what it says, or +denies: + +- **A policy with no `check` gates writes with its `using`.** `check` + was always documented as defaulting to `using`, but only policies that + declared `check` were applied to writes, so a user could insert or + update a row into a place they could not read back. A single-row + insert or by-id update whose result falls outside the `using` of every + write policy that applies now answers `403 PERMISSION_DENIED`. A + policy that meant to let writes land outside its read scope has to + declare a `check` that admits them. +- **A predicate it cannot enforce denies.** Comparing a field with a + list (`record.status != ['closed', 'archived']`), with the bare + `current_user` instead of `current_user.id`, or naming a field the + object does not declare could admit the very rows and writes it was + written to refuse. Such a policy now fails closed: its reads return + no rows and its writes answer `403`. +- **Writes are judged on the stored row.** `check` and the + organization wall see the row as the engine stores it, after + `beforeInsert` / `beforeUpdate` hooks have run. + +`os validate` reports these shapes before they ship +(`rls-predicate-unenforceable`, `rls-predicate-unknown-field`), and the +metadata save door refuses a permission set that carries one +(`422 INVALID_METADATA`). + ## Record shares Use record shares for exceptions: diff --git a/content/docs/configure/users.mdx b/content/docs/configure/users.mdx index 94d5d46..228b779 100644 --- a/content/docs/configure/users.mdx +++ b/content/docs/configure/users.mdx @@ -65,6 +65,12 @@ first-class: Pending invitations are listed under **Setup → People & Organization → Invitations**. +People cannot create their own accounts unless you open self-registration: +since ObjectStack 17.3 the sign-up audience defaults to **invitation only**, +and these three paths are how people arrive. They work whatever the +audience is set to. To let people sign themselves up, see +[Authentication → Who may sign up](/docs/configure/authentication#who-may-sign-up-objectstack-173). + The same flows exist over REST (ObjectStack 14.3+) for scripted onboarding: diff --git a/content/docs/operate/audit-logs.mdx b/content/docs/operate/audit-logs.mdx index 18f8fff..eb05fc2 100644 --- a/content/docs/operate/audit-logs.mdx +++ b/content/docs/operate/audit-logs.mdx @@ -27,15 +27,43 @@ At **Setup → Diagnostics → Audit Logs** (`sys_audit_log`). The object is filter, group, and inspect rows, but nothing can edit or delete them from Setup. +### What each reader is served + +Every row stays stored, but since ObjectStack 17.6 a reader is served a row +about a record only if they can read that record themselves — the same object +permissions, sharing and row-level security that decide whether they can open +it. That excludes: + +- every `delete` row, and every other row about a record that has since been + deleted; +- sign-out rows, and sign-in rows whose session has since been removed; +- rows about records the reader cannot open. + +Rows about no record — configuration changes, user-import runs, auth events +that carry no session — are served under the ledger's own grant, as before. + +The **`view_all_audit_log`** capability lifts this narrowing (ObjectStack +17.7): its holder is served the deletion and sign-out trail and the rows about +records they cannot open. Platform administrators hold it by default; an +organization administrator does not, so grant it explicitly to anyone else who +must read the whole trail. + +Field-level security still applies inside every row. `old_value` and +`new_value` serve a field only to a reader who can read it unmasked, and +filtering, sorting or grouping on them is refused (`403`) unless the filter +names one object by equality (`object_name`) and you can read every field of +it. + ### Preset views -The list opens with tabs that filter by action category: +The list opens with tabs that filter by action category. Each serves only the +rows above: | View | Shows | |---|---| | `Recent` | All events, newest first | -| `Writes` | Create / update / delete actions | -| `Auth` | Sign-in, sign-out, and authentication events | +| `Writes` | Create / update / delete actions — `delete` rows only with `view_all_audit_log` | +| `Auth` | Sign-in and sign-out events — sign-outs, and sign-ins whose session has since been removed, only with `view_all_audit_log` | | `Config` | Settings and configuration changes | ### Columns and fields @@ -67,8 +95,9 @@ Each row carries the full field set: ### Reading a change For write actions, the interesting detail is the before/after. Open a row's -`⋮` menu to expand `old_value` and `new_value` and see exactly what changed on -that record. The `Object` and `Record ID` columns tell you *what* was touched; +`⋮` menu to expand `old_value` and `new_value` and see what changed on that +record — every field you can read in full, and nothing else. The `Object` and +`Record ID` columns tell you *what* was touched; `old_value`/`new_value` tell you *how*; `actor`, `ip_address`, and `user_agent` tell you *who* and *from where*. diff --git a/content/docs/operate/observability.mdx b/content/docs/operate/observability.mdx index cd77596..9f6ea74 100644 --- a/content/docs/operate/observability.mdx +++ b/content/docs/operate/observability.mdx @@ -80,7 +80,10 @@ endpoints do not feed that counter, a rejected API key is indistinguishable from a request that carried no credential at all, and both statuses are dominated by ordinary permission denials against users who authenticated perfectly well. Review sign-in activity in Setup's `Auth` audit view -instead — see [Audit Logs](/docs/operate/audit-logs). +instead, as a holder of `view_all_audit_log` — platform administrators hold +it by default. Without it, sign-outs and sign-ins whose session has since +been removed are not served; see +[Audit Logs](/docs/operate/audit-logs#what-each-reader-is-served). For OpenTelemetry, set `OS_OBS_EXPORTER=otlp` **and** `OS_OTLP_ENDPOINT` (e.g. `https:///otlp`) and ObjectOS will emit traces and metrics diff --git a/content/docs/reference/security.mdx b/content/docs/reference/security.mdx index b6ec843..5334749 100644 --- a/content/docs/reference/security.mdx +++ b/content/docs/reference/security.mdx @@ -81,11 +81,18 @@ Permission Model v2 (ObjectStack 13, ADR-0090): 1. **Object permissions** — CRUD per object per permission set, distributed to users directly or through flat **positions** 2. **Org-wide defaults** — custom objects with an owner default to a - `private` sharing model; anonymous data access is denied by default + `private` sharing model; anonymous access to object data is denied + unconditionally, with no switch to open it (ObjectStack 17.0). + Public access is declared per surface — a public form or a share + link — and the `guest` anchor grants nothing 3. **Row-level security** — declarative policy expressions injected into - queries; not optional -4. **Field-level security** — fields stripped from responses / - rejected on write (keys are object-qualified, lint-enforced) + queries; not optional, and a policy the runtime cannot enforce + denies rather than widens (ObjectStack 17.5) +4. **Field-level security** — fields stripped from responses, + partially masked (`maskingRule`, ObjectStack 17.1), or rejected on + write (keys are object-qualified, lint-enforced). A hidden or masked + field cannot be filtered, sorted, grouped or aggregated on — `403` at + every query door since ObjectStack 17.6 5. **Organization scoping** — multi-tenant isolation; bypass requires explicit `viewAllRecords` diff --git a/content/docs/use/approvals.mdx b/content/docs/use/approvals.mdx index b56f554..541568e 100644 --- a/content/docs/use/approvals.mdx +++ b/content/docs/use/approvals.mdx @@ -28,12 +28,20 @@ ways: | **My Pending** | Requests waiting on *you* to decide. This is your to-do list. | | **I Submitted** | Requests you sent for approval — check here to see where your own submissions stand. | | **Completed** | Requests that have been decided, approved or rejected. | -| **All** | Every approval request you're allowed to see. | +| **All** | Every approval request you take part in — see below. | When there's nothing waiting on you, **My Pending** shows the empty state *"No pending approvals — You're all caught up."* That's the screen you want to see at the end of the day. +**You see the requests you take part in.** A request is visible to the +person who submitted it, to whoever it is currently waiting on (directly or +through a position they hold), and to anyone who has already decided or +commented on it. Administrators see every request. Being able to +open the record is not enough — a colleague who can read the record but has +no part in the approval doesn't see its request, its comments or its +attachments. + > **Tip:** Bookmark the Approvals inbox, or just glance at the **Needs your > attention** list on the home page — pending approvals appear there too, > with how long they've been waiting. From 6067fb5854b48c5dea766acba541ba1243fc71d2 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 13:04:33 +0000 Subject: [PATCH 2/3] docs(access): tighten the query-door, RLS and approvals-inbox wording Claude-Session: https://claude.ai/code/session_01CXCwzqwMhkphKoBC11oPSz Co-authored-by: Claude --- content/docs/configure/permissions/field-level-security.mdx | 6 ++++-- content/docs/configure/permissions/record-access.mdx | 4 ++-- content/docs/operate/audit-logs.mdx | 4 ++-- content/docs/use/approvals.mdx | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/content/docs/configure/permissions/field-level-security.mdx b/content/docs/configure/permissions/field-level-security.mdx index 0f4ab3a..c95047f 100644 --- a/content/docs/configure/permissions/field-level-security.mdx +++ b/content/docs/configure/permissions/field-level-security.mdx @@ -138,8 +138,10 @@ API's filter and sort: - a field named as the right-hand side of a comparison, in a filter or an aggregation; - analytics queries; -- filters and sorts over the value columns of the activity stream, the - [audit log](/docs/operate/audit-logs) and approval snapshots. +- filters and sorts over the copied values in the activity stream, the + [audit log](/docs/operate/audit-logs) and approval snapshots — refused + unless the filter names one object by equality and the caller can read + every field of it. **On write** — `insert` / `update` requests are checked **before** the operation reaches the driver. If the payload contains any field the diff --git a/content/docs/configure/permissions/record-access.mdx b/content/docs/configure/permissions/record-access.mdx index 11536c0..ee41a18 100644 --- a/content/docs/configure/permissions/record-access.mdx +++ b/content/docs/configure/permissions/record-access.mdx @@ -99,8 +99,8 @@ denies: - **A policy with no `check` gates writes with its `using`.** `check` was always documented as defaulting to `using`, but only policies that - declared `check` were applied to writes, so a user could insert or - update a row into a place they could not read back. A single-row + declared `check` were applied to writes, so a user could write a row + they could not read back. A single-row insert or by-id update whose result falls outside the `using` of every write policy that applies now answers `403 PERMISSION_DENIED`. A policy that meant to let writes land outside its read scope has to diff --git a/content/docs/operate/audit-logs.mdx b/content/docs/operate/audit-logs.mdx index eb05fc2..a677abb 100644 --- a/content/docs/operate/audit-logs.mdx +++ b/content/docs/operate/audit-logs.mdx @@ -56,8 +56,8 @@ it. ### Preset views -The list opens with tabs that filter by action category. Each serves only the -rows above: +The list opens with tabs that filter by action category. Every tab applies the +rule above: | View | Shows | |---|---| diff --git a/content/docs/use/approvals.mdx b/content/docs/use/approvals.mdx index 541568e..d66b699 100644 --- a/content/docs/use/approvals.mdx +++ b/content/docs/use/approvals.mdx @@ -28,7 +28,7 @@ ways: | **My Pending** | Requests waiting on *you* to decide. This is your to-do list. | | **I Submitted** | Requests you sent for approval — check here to see where your own submissions stand. | | **Completed** | Requests that have been decided, approved or rejected. | -| **All** | Every approval request you take part in — see below. | +| **All** | Every approval request you can see — which ones is explained below. | When there's nothing waiting on you, **My Pending** shows the empty state *"No pending approvals — You're all caught up."* That's the screen you want From dc12fdb3e5e6d9bb4580c973b74279026d1242a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 04:39:01 +0000 Subject: [PATCH 3/3] docs(security): an action is an AI tool only when its author exposes it Claude-Session: https://claude.ai/code/session_01CXCwzqwMhkphKoBC11oPSz Co-authored-by: Claude --- content/docs/reference/security.mdx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/content/docs/reference/security.mdx b/content/docs/reference/security.mdx index 5334749..729f14d 100644 --- a/content/docs/reference/security.mdx +++ b/content/docs/reference/security.mdx @@ -210,8 +210,12 @@ user prompt There are 11 first-party metadata tools ([see Build → AI Builder](/docs/build/ai-builder)) plus one -`action_` tool per declared action. Every tool — first-party or -custom — has the same lifecycle. +`action_` tool per action its author +[exposed to AI](/docs/build/interface/actions#from-an-ai-agent) — +`ai: { exposed: true }` with an `ai.description` of at least 40 +characters, on a type that runs without a UI (`script`, `flow` or +`api`); an unexposed action is invisible to agents and refused if +called. Every tool — first-party or custom — has the same lifecycle. ### Permission keys