Defines the hierarchy grant vocabulary (viewer|member|owner, totally ordered), evaluation semantics (deny-by-default, down-the-chain, max rule, live fail-closed evaluation), grant management (owner-managed, no self-escalation, explicit bootstrap of authority), transfer authority (both-sides owner, completing contract 1 §4.2), and revocation propagation with the same 30s/next-message bound as identity §7.1. Embedded decision for ratification: platform admin confers no implicit tenant access (§1.1). Sources: PRD Part I §4, native-kanban SOT Amendment A1 §8.1.3/§8.3, hierarchy-schema contract (PR #1435), identity-lifecycle contract §1.4 (PR #1433).
9.4 KiB
RBAC Grant Model Contract
Status: DRAFT — awaiting ratification (webui-audit S2, contract 2 of 9).
Authority: PRD Part I §4 ("Granular RBAC: admins restrict access per company,
estate, and project; grants are evaluated down the chain") and the
native-kanban SOT Amendment A1 (§8.1.3 RBAC evaluation, §8.3 acceptance 2).
This document defines the grant vocabulary, evaluation semantics, and
revocation propagation that the hierarchy schema contract
(docs/requirements/hierarchy-schema.md, contract 1) attaches to. Contract 1
pins the hierarchy_grants table shape and defers the role vocabulary and
the meaning of "authority" here; the identity contract
(docs/requirements/identity-lifecycle.md §1.4) pins that account creation
grants nothing.
Scope: the roles that can appear in hierarchy_grants.role, what a grant at
each hierarchy level confers, how grants evaluate down the chain, how
revocation propagates, and who may manage grants. Out of scope: the hierarchy
tables themselves (contract 1), workspace-internal membership and its
role/capability vocabulary (native-kanban SOT REQ-ID-001 and its implementing
schema), roll-up projection semantics (contract 8), wizard seeding
(contract 3).
1. Three authority layers, none substitutable
- Platform role (
users.role, better-auth:member|admin) governs instance administration — user management, system settings, provider configuration. It is not tenancy authority: holding platformadminconfers no implicit hierarchy grant and no workspace authorization. An operator who should see tenant content holds an explicit, audited grant like anyone else. (This is the deny-by-default consequence of A1 §8.1.3's "never a bypass" rule; today'sAdminGuardchecksrole === 'admin'for admin endpoints and that stays its only meaning.) - Hierarchy grants (
hierarchy_grants, contract 1 §3) declare tenancy authority at company, estate, or platform-project scope and evaluate down the chain to workspace-scoped authorization (§3 below). - Workspace membership (SOT REQ-ID-001) remains its own mechanism. A chain grant confers command authorization over descendant workspaces; it does not create membership rows, and row-level principal positions (task owner, proposer, decision actor) still require ACTIVE workspace membership exactly as REQ-TEN-001/REQ-ID-001 acceptance states.
2. Role vocabulary
One vocabulary at every hierarchy level, totally ordered — a higher role includes everything below it:
viewer— read: sees the node, its subtree structure, and the roll-up aggregates over descendant workspaces (within contract 8's carve-out bounds); read access to descendant workspace content per the SOT's read command families. No mutation of anything.member— work: everythingviewerhas, plus write authorization for business/orchestration command families in descendant workspaces (the concrete command-family mapping is implementation work under SOT REQ-ID-001; this contract pins thatmembermaps to the workspace write families and nothing structural).owner— structure: everythingmemberhas, plus hierarchy mutations on the subtree (create/rename/delete child nodes, transfers per §5), and grant management on the node and its subtree (§4).
No other value is valid in hierarchy_grants.role; the column is
constraint-checked against exactly these three. Extending the vocabulary is a
contract amendment, not an implementation decision.
3. Evaluation semantics
- Deny by default. No grant on any ancestor → no authority. There are no implicit grants: not from platform role (§1.1), not from creating a node (§4.3), not from workspace membership (membership without a chain grant confers exactly what the SOT's own membership rules confer inside that workspace, nothing up the chain).
- Down-the-chain only. A grant on a node applies to that node and its entire descendant subtree. Nothing evaluates upward or sideways: a grant on an estate says nothing about the parent company or sibling estates.
- Effective role = maximum. A subject's effective role at any node is the highest role among: grants held directly by the subject's user on that node or any ancestor, and grants held by any team the user is a member of on that node or any ancestor. Roles never subtract — there is no negative/deny grant in this model; revocation is deletion (§6).
- Team grants follow live membership. A team grant confers its role on the team's current members, evaluated at decision time. Leaving the team is loss of the grant with §6's propagation bound.
- Live evaluation, fail closed. Authorization decisions derive from the live grant and team-membership rows (or from a cache that is invalidated in the same transaction as any grant/membership/hierarchy mutation). A decision path that cannot read grant state denies. No materialized ACL is ever authoritative.
- Tenant context stays derived from authenticated authority (REQ-TEN-001). The chain adds where grants can be declared; a workspace request is still authorized against that workspace, with the chain contributing the effective role — never a bypass of workspace-scoped checks.
4. Grant management
- Creating, changing, or revoking a grant on a node requires effective
owneron that node (directly or via any ancestor). - No self-escalation. A grant manager cannot create a grant with a role
higher than their own effective role on the target node. (With the §2
vocabulary this only bites managers acting through team-conferred
owner: the rule is stated so it survives vocabulary amendments.) - Creating a hierarchy node confers no automatic grant. Bootstrap of
authority is explicit: the creating command names the initial
ownergrant in the same audited operation, and the wizard (contract 3) seeds the first company's initialownerthe same way. - Every grant mutation is a semantic audit event per contract 1 §5.2 (actor, verb, subject, target, role).
5. Transfer authority (completes contract 1 §4.2)
"Authority over BOTH the source and the destination parent" means: effective
owner on the current parent node (or an ancestor) AND effective owner on
the destination parent node (or an ancestor), evaluated at transfer time in
the transfer's own transaction. One subject must hold both; two cooperating
half-authorized subjects are not a transfer protocol this contract defines.
6. Revocation propagation
- Revoking a grant (deleting the row), removing a user from a team that carries a grant, or deleting an ancestor node's grant during node deletion (contract 1 §3.3) all propagate identically: the authority derived from that grant is gone for every descendant workspace.
- Bound: the next authorization decision on any affected transport decides against the revoked grant. Concretely: no new HTTP/MCP command authorized by the revoked grant after the revoking transaction commits; an open Socket.IO connection whose subscriptions depend on the revoked grant is re-evaluated within 30 seconds or at its next inbound message, whichever comes first (same bound as the identity contract's §7.1 deactivation rule; same mechanism may serve both).
- Revocation is subtractive only in effect, not in representation: the evaluator never needs tombstones; deletion of the row is the revocation.
7. Verification requirements
Binding on the implementing PRs (extends A1 §8.3 acceptance 2–3 and contract 1 §6.4):
- Vocabulary: the role CHECK constraint rejects any value outside
viewer|member|owner(real-PostgreSQL witness,ci-postgresservice in thetestCI step). - Per-level conferral: for each of the three levels × three roles, a grant yields exactly the implied workspace authorization in a descendant workspace and nothing in a non-descendant workspace (the A1 §8.3 "exactly the permissions the chain implies" matrix, enumerated).
- Ordering:
owner⊇member⊇viewerbehaviorally — each higher role passes every lower role's positive cases. - Deny-by-default: platform
adminwith no grant reaches no tenant content; workspace member with no chain grant gains nothing outside SOT membership semantics; fresh account reaches nothing (identity contract §1.4 cross-check). - Max-rule and teams: user-direct and team-conferred grants combine to the maximum; team-leave drops authority within the §6.2 bound; decision-time evaluation witnessed (grant added → next decision allows; no restart or re-login required).
- Revocation: each revocation path in §6.1 denies the next command on every transport; the socket bound is measured; a cached-authorization implementation proves transactional invalidation (grant revoked and decision made on two distinct physical connections).
- Grant management: non-
ownercannot mutate grants; self-escalation attempt refused; node creation without the explicit initial grant refused; every mutation produces its audit event. - Transfer: both-sides
owneraccepted, each single-side case refused (completing contract 1 §6.2).
Ruling request
Ratify sections 1–7 as written, with one decision embedded: platform admin
confers no implicit tenant access — operators see tenant content only
through explicit, audited grants (§1.1) — say "agreed" or name the implicit
access you want platform admins to have.