Skip to main content

Module roles

Module roles 

Source
Expand description

RBAC role definitions and sidecar I/O.

RoleDef is the public unit of role configuration. Roles are declared in Schema::roles and persisted as roles.json in the database directory via [GraphDb::apply_schema].

§Never-widen rule

  • Empty role (no keys, no labels) = empty mask = sees nothing.
  • Unknown role on a request = Err (never silently grant full access).
  • Corrupt roles.json at open = roles poisoned; [GraphDb::mask_for_role] returns Err for any role name until the file is fixed and the DB re-opened.

§Persistence

roles.json format: { "version": 1, "roles": [...] } (no write scopes) or { "version": 2, "roles": [...] } (at least one role has a write scope) or { "version": 3, "roles": [...] } (at least one role has a visible_where predicate) or { "version": 4, "roles": [...] } (at least one role is bound to namespaces). The highest applicable version is written and no higher: version 2 is written only when a write scope is present, version 3 only when a predicate is, version 4 only when a namespace binding is. Version 1 is kept for forward-compat honesty — a v0.2 server can load v1 safely and the write field (absent from v1) is ignored by serde’s #[serde(default)] when a v2 sidecar is loaded by an older binary. Version 3 is deliberately not loadable by an older binary: a binary that does not know visible_where would resolve a narrowed role to its full label set, so an unrecognised version poisons instead, which denies rather than over-grants. Version 4 is the same bargain for namespaces: a binary that does not know the field would resolve a tenant-scoped role across every tenant. Files are written atomically (temp → fsync → rename → dir-sync); a no-change re-apply leaves the file byte-identical.

Structs§

PropPredicate
One property test a role’s visibility may carry, beside labels.
RoleDef
A named RBAC role: resolves to a node-visibility mask at query time.
WriteScope
Write permissions granted to a role.