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.jsonat open = roles poisoned; [GraphDb::mask_for_role] returnsErrfor 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§
- Prop
Predicate - 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.
- Write
Scope - Write permissions granted to a role.