From 20ec48e5b4489b092adaf943a777ebdb9fd832e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 01:18:12 +0000 Subject: [PATCH 1/2] docs: guest has no bind door until ADR-0138 D3 item 5's door is built ADR-0090 D9 gains an amended status line pointing at ADR-0138 D3 item 5 (ruling C on #23267): packages suggest `everyone` bindings only, and no door binds a set to `guest` until that door is built. The two docblocks in validate-security-posture.ts and position.zod.ts stop stating an operator or package guest bind path. Comment and ADR text only; no behaviour moves. Claude-Session: https://claude.ai/code/session_01MQfWVZgL81y5JLRXAwYyXF Co-authored-by: Claude --- ...permission-model-v2-concept-convergence.md | 1 + .../lint/src/validate-security-posture.ts | 24 +++++++++---------- packages/spec/src/identity/position.zod.ts | 4 +++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/adr/0090-permission-model-v2-concept-convergence.md b/docs/adr/0090-permission-model-v2-concept-convergence.md index ef469d2753b..9f483123bf9 100644 --- a/docs/adr/0090-permission-model-v2-concept-convergence.md +++ b/docs/adr/0090-permission-model-v2-concept-convergence.md @@ -5,6 +5,7 @@ · **Amended** (2026-10-14, [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D3/D13) — two of the row objects D3 renames into, `sys_position` and `sys_position_permission_set`, and the `sys_capability` D5 names, are retired by #15204 stage 8 (`66949b7729`, 2026-10-13): a position is a metadata-registry definition that names its sets in `PositionSchema.permissionSets`; `sys_user_position` stays. See the notes under D3, D5 and D8. · **Amended** (2026-10-14, ruling of record 6159300530 on #23268, letter A) — D11's external org-wide default is retired: external visibility is the [ADR-0095](./0095-authz-kernel-tenant-layer-and-posture-ladder.md) `EXTERNAL` rung, explicitly shared rows only. See the note under D11. · **Amended** (2026-10-15, ruling of record 6181988435 on #23488, letter A) — D12's position↔set binding right and its environment-set authoring right are retired (`AdminScope.manageBindings` and `AdminScope.authorEnvironmentSets`, ADR-0049 enforce-or-remove): a position's sets and a permission set's body are environment definitions, and the definition write is `manage_metadata`'s per [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D3, never a delegate scope's. D12's *what* is user↔position assignments (and direct set grants) inside the subtree; read its bindings and authoring clauses as superseded by this line. +· **Amended** (2026-10-14, [ADR-0138](./0138-guest-model-anonymous-principal-doors-grants-and-organization.md) D3 item 5, ruling C of record 6159279205 on #23267) — D9's last bullet holds for `everyone` alone: a package suggests `everyone` bindings and the admin confirms each, while no door binds a set to `guest` (no package suggestion, no confirmation, no operator bind) until ADR-0138 D3 item 5's bind door is built, an act of the environment's administrator, never of a package. Read that bullet's `guest` half as superseded by this line. **Deciders**: ObjectStack Protocol Architects **Builds on**: [ADR-0049](./0049-no-unenforced-security-properties.md) (enforce-or-remove), [ADR-0056](./0056-permission-model-landing-verification.md) (permission-model landing verification), diff --git a/packages/lint/src/validate-security-posture.ts b/packages/lint/src/validate-security-posture.ts index c25d7b17c29..c5a3dc770d8 100644 --- a/packages/lint/src/validate-security-posture.ts +++ b/packages/lint/src/validate-security-posture.ts @@ -11,7 +11,7 @@ * | security-owd-unset (error) | objectui#2348 leave_request 事故 | * | security-owd-alias (error) | ADR-0090 D4 canonical enum — UNPARSED intakes only, see § Intake | * | security-wildcard-vama (error) | ADR-0066 superuser wildcard | - * | security-anchor-high-privilege(error) | ADR-0090 D5/D9 anchors — declared `everyone` suggestions (`isDefault: true`) only; a `guest`-bound set is outside a package-time linter's sight and is the bind-time gate's alone (#16110) | + * | security-anchor-high-privilege(error) | ADR-0090 D5/D9 anchors — declared `everyone` suggestions (`isDefault: true`) only; no door binds a set to `guest` until ADR-0138 D3 item 5's bind door is built (#16110) | * | security-role-word (error) | ADR-0090 D3 vocabulary freeze — own function/registry entry since #8310; CLI + runtime publish gate since commit a227afa41 | * | security-book-audience-unknown-set(warn)| ADR-0046 §6.7 { permissionSet } | * | security-private-no-readscope (info) | admin-intent mismatch class | @@ -28,13 +28,13 @@ * — the lint moves the failure from runtime-deny to author-time fix-it. * `security-anchor-high-privilege` mirrors that gate for the one suggestion a * package can actually declare (`isDefault: true` → the `everyone` anchor, - * `suggested-audience-bindings.ts`'s "the only declarable suggestion"); a set - * an operator binds to `guest` at install time is a decision ADR-0090 D9 - * ("a package may suggest bindings … the admin confirms each individually") - * puts past authoring, so this rule is not — and cannot be — coverage for an - * app-authored anchor set bound to `guest` (#16110). No runtime door binds a - * set to `guest` today; ADR-0138 D3 item 5's bind door runs - * `describeAnchorForbiddenBits(set, 'guest')` when it is built. + * `suggested-audience-bindings.ts`'s "the only declarable suggestion"). A + * package never suggests a `guest` binding, and no door binds a set to + * `guest` until ADR-0138 D3 item 5's bind door is built (it amends ADR-0090 + * D9's "a package may suggest bindings to `everyone` or `guest`"), so this + * rule is not — and cannot be — coverage for a set bound to `guest` (#16110). + * That door, when built, is an act of the environment's administrator, never + * of a package, and runs `describeAnchorForbiddenBits(set, 'guest')` itself. * * `security-cbp-ambiguous-relation` used to be the one exception: the runtime * did not refuse two candidate masters, it silently PICKED one by field @@ -932,10 +932,10 @@ export function validateSecurityPosture(stack: AnyRec, opts?: { nowMs?: number } // D5: an isDefault set is a SUGGESTED binding to the `everyone` anchor — // hold it to the anchor tier at author time (the runtime gate enforces the // same predicate at bind time; this moves the failure to the author). - // Scope: `isDefault: true` is the only declarable suggestion today — a set - // an operator binds to `guest` at install carries no author-time flag for - // this rule to key off, so that binding is outside what a package-time - // linter can see and is judged by the bind-time gate alone (#16110). + // Scope: `isDefault: true` is the only declarable suggestion, and it names + // `everyone` alone. No door binds a set to `guest` until ADR-0138 D3 item + // 5's bind door is built (an administrator's act, never a package's), so + // no `guest` binding exists for a package-time linter to see (#16110). if (ps.isDefault === true) { const offending = describeAnchorForbiddenBits(ps, 'everyone', anchorContext); if (offending) { diff --git a/packages/spec/src/identity/position.zod.ts b/packages/spec/src/identity/position.zod.ts index 97b27155cef..5ca91b5a32d 100644 --- a/packages/spec/src/identity/position.zod.ts +++ b/packages/spec/src/identity/position.zod.ts @@ -162,7 +162,9 @@ export const PositionSchema = lazySchema(() => strictObject( * tenant's default grants (resolved per-request; additive, no fallback * cliff). `guest` is held implicitly (and exclusively) by unauthenticated * principals; its bindings face the strictest lint tier. Packages SUGGEST - * bindings to these anchors at install time — never auto-bind. + * bindings to `everyone` at install time and the admin confirms each — never + * auto-bind. No door binds a set to `guest` until ADR-0138 D3 item 5's bind + * door is built, an act of the environment's administrator, never a package's. */ export const EVERYONE_POSITION = 'everyone'; export const GUEST_POSITION = 'guest'; From 781bb576e245139e9abaf8dd6cdf8ecd9c4e88f2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 01:52:01 +0000 Subject: [PATCH 2/2] docs(adr-0086): amended line, the guest half of the anchor row waits for ADR-0138 D3 item 5 The Re-evaluation table's everyone/guest row says packages suggest bindings and admins confirm. That holds for everyone alone: no door binds a set to guest until ADR-0138 D3 item 5's bind door is built (ruling C on #23267). One status line; the row itself is not rewritten. Claude-Session: https://claude.ai/code/session_01MQfWVZgL81y5JLRXAwYyXF Co-authored-by: Claude --- ...hz-metadata-config-boundary-and-cross-package-composition.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md b/docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md index 2e5a8859eac..93588862bc6 100644 --- a/docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md +++ b/docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md @@ -1,6 +1,6 @@ # ADR-0086: Authorization metadata↔config boundary + cross-package composition — DEFINITION travels, ASSIGNMENT stays, packages ship their own sets -**Status**: Accepted (2026-07-04) — **substantially implemented**; parts refined/superseded by [ADR-0090](./0090-permission-model-v2-concept-convergence.md) and [ADR-0094](./0094-sys-permission-set-pure-projection.md). See the **Re-evaluation (2026-07-16)** addendum for the current, code-grounded status of every decision. · **Amended** (2026-10-14, [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D2/D3/D13): the ADR-0094 projection the Re-evaluation describes, and the `sys_permission_set` and `sys_position_permission_set` row objects, are retired by #15204 stage 8 (`66949b7729`, 2026-10-13); the DEFINITION↔ASSIGNMENT thesis stands, and ADR-0131 completes it. See the notes in the Re-evaluation. +**Status**: Accepted (2026-07-04) — **substantially implemented**; parts refined/superseded by [ADR-0090](./0090-permission-model-v2-concept-convergence.md) and [ADR-0094](./0094-sys-permission-set-pure-projection.md). See the **Re-evaluation (2026-07-16)** addendum for the current, code-grounded status of every decision. · **Amended** (2026-10-14, [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D2/D3/D13): the ADR-0094 projection the Re-evaluation describes, and the `sys_permission_set` and `sys_position_permission_set` row objects, are retired by #15204 stage 8 (`66949b7729`, 2026-10-13); the DEFINITION↔ASSIGNMENT thesis stands, and ADR-0131 completes it. See the notes in the Re-evaluation. · **Amended** (2026-10-14, [ADR-0138](./0138-guest-model-anonymous-principal-doors-grants-and-organization.md) D3 item 5, ruling C of record 6159279205 on #23267): the Re-evaluation table's `everyone` / `guest` row ("Packages *suggest* bindings; admins confirm") holds for `everyone` alone; no door binds a set to `guest` (no package suggestion, no confirmation) until ADR-0138 D3 item 5's bind door is built, an act of the environment's administrator, never of a package. Read the row's `guest` half as superseded by this line. **Deciders**: ObjectStack Protocol Architects **Builds on**: [ADR-0066](./0066-unified-authorization-model.md) (three-way separation: Capability / Assignment / Requirement — this ADR operationalizes its **D5** for the packaging axis), [ADR-0056](./0056-permission-model-landing-verification.md) (whole-model enforce/prove; **D7** app-declared default profile), [ADR-0057](./0057-erp-authorization-core-business-units-and-scope-depth.md) (`readScope`/`writeScope` depth), [ADR-0005](./0005-metadata-customization-overlay.md) (per-org overlay = the subtract/adjust layer), [ADR-0028](./0028-metadata-naming-and-namespace-isolation.md) / [ADR-0048](./0048-cross-package-metadata-collision.md) (namespaced api names = collision-proof keys), [ADR-0078](./0078-no-silently-inert-metadata.md) (no declarable-but-never-seeded metadata), [ADR-0016](./0016-studio-package-authoring-and-publish.md) / [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (draft/publish), [ADR-0084](./0084-application-builder-information-architecture.md) (Access pillar = matrix; defers composition), [ADR-0025](./0025-plugin-package-distribution.md) (manifest `permissions` = install-consent scopes, **not** RBAC grants), [ADR-0003](./0003-package-as-first-class-citizen.md) / [ADR-0070](./0070-package-first-authoring.md) (package-first), [ADR-0006](./0006-project-environment-split.v4.md) (environment split) **Consumers**: `@objectstack/spec` (`security/permission.zod.ts`, `stack.zod.ts`, `system/metadata-persistence.zod.ts`), `@objectstack/plugin-security` (`bootstrap-declared-*`, `permission-evaluator`), `@objectstack/core` (`resolve-authz-context`), `@objectstack/metadata` (overlay), `../objectui` (`AccessPillar`, `PermissionMatrixEditor`, `metadata-admin`)