Skip to content

feat(spec,security): OrgScopingEntitlement grows platform-global exemption + unbounded-admin suppression, consumed by Layer 0 arming #12699

Description

@os-zhuang

Part of objectstack-ai/cloud#1653 (epic — the ruling and the measured evidence live there; read the ruling comment and cost-analysis comment 5410466814 before designing).

Deliverable — Phase 1: the deployment-entitlement contract Layer 0 consumes

OrgScopingEntitlement (packages/spec/src/security/tenancy-posture.ts) grows two declared-by-the-runtime keys, both consumed by plugin-security when arming the Layer 0 wall:

  1. Platform-global object exemption (name yours, e.g. platformGlobalObjects?: readonly string[]): objects the deployment declares platform-owned — Layer 0 must not wall them on this deployment. Semantics: per-deployment, declared by the mounted org-scoping service, NOT authorable app metadata. Fail closed: key absent ⇒ every object walls exactly as today. Junk shapes refused loudly at the seam (the MembershipPolicy entry-validation precedent).
  2. Unbounded-admin suppression (name yours): the deployment declares that arming a walled posture must NOT auto-grant the organization_admin role's unbounded viewAllRecords/modifyAllRecords superbits (the epic's measured regression: sys_secret 403→200, 17 objects regaining cross-tenant writes, cloud#1257's write gate voided). Fail closed the same way: absent ⇒ today's behaviour.

Why this exists (ruled, not re-adjudicable)

The alternative seams are dead: host self-declaration of the boundary is a paywall bypass (ruled out), and the objectExtensions merge silently drops tenancy (objectstack#12680 — measured). This contract keeps the paywall intact (only a mounted enterprise runtime can declare anything) while letting a deployment that genuinely IS walled carve out its platform tables.

Mechanism assumptions (MUST verify; refuting = good outcome)

  • Find the actual consumer of supportedPostures today and mirror its read pattern — this seat's grep found no consumer inside plugin-security, so locate where the tenancy service reads the entitlement and whether SecurityPlugin should read via the same path or via getService('org-scoping') directly. Argue the placement in the report.
  • Confirm SecurityPlugin's per-object wall predicate (security-plugin.ts ~6345/~6639 reads tenancy.enabled/systemFields.tenant from the live registry) is the single choke point, so the exemption composes there and nowhere else.

Tests

Exempted object not walled / non-exempted still walled / absent-key = byte-identical behaviour to today / junk entitlement refused loudly / superbit suppression on + off / the entitlement shape itself. Ablation on both keys.

Consumer

cloud Phase 2 consumes this verbatim: PR body MUST publish the final key names, shapes, and the exact declaration site pattern.

Clause-②: YES (widens the spec contract surface) — contract-tier dispatch, needs:contract-review chain applies at ACCEPT regardless.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions