6.2 KiB
| layout | title | parent |
|---|---|---|
| default | Capability Vocabulary Technical Specification | Tech Specs |
Capability Vocabulary Technical Specification
Overview
Authorisation in TrustGraph is capability-based. Every gateway endpoint maps to exactly one capability; a user's roles each grant a set of capabilities; an authenticated request is permitted when the required capability is a member of the union of the caller's role capability sets.
This document defines the capability vocabulary — the closed list of capability strings that the gateway recognises — and the open-source edition's role bundles.
The capability mechanism is shared between open-source and
enterprise editions. The open-source edition ships a fixed
three-role bundle (reader, writer, admin). Enterprise editions
define additional roles by composing their own capability bundles
from the same vocabulary; no protocol, gateway, or backend-service
change is required.
Motivation
The original IAM spec used hierarchical "minimum role" checks
(admin implies writer implies reader). That shape is simple
but paints the role model into a corner: any enterprise need to
grant a subset of admin abilities (helpdesk that can reset
passwords but not edit flows; analyst who can query but not ingest)
requires a protocol-level change.
A capability vocabulary decouples "what a request needs" from "what roles a user has" and makes the role table pure data. The open-source bundles can stay coarse while the enterprise role table expands without any code movement.
Design
Capability string format
<subsystem>:<verb> or <subsystem> (for capabilities with no
natural read/write split). All lowercase, kebab-case for
multi-word subsystems.
Capability list
Data plane
| Capability | Covers |
|---|---|
query |
Read queries: agent, text-completion, prompt, graph-rag, document-rag, embeddings, triples, rows, NLP query, SPARQL, structured-query, mcp-tool |
library:read |
List / fetch documents |
library:write |
Add / replace / delete documents |
collections:read |
List / describe collections |
collections:write |
Create / delete collections |
knowledge:read |
List / get knowledge cores |
knowledge:write |
Create / delete knowledge cores |
ingest |
text-load, document-load |
export |
Streaming exports (triples, graph-embeddings, document-embeddings, entity-contexts, core-export) |
import |
Streaming imports (triples, graph-embeddings, document-embeddings, entity-contexts, rows, core-import) |
Control plane
| Capability | Covers |
|---|---|
config:read |
Read workspace config |
config:write |
Write workspace config |
flows:read |
List / describe flows, blueprints, flow classes |
flows:write |
Start / stop / update flows |
users:read |
List / get users within the workspace |
users:write |
Create / update / disable users within the workspace |
users:admin |
Assign / remove roles on users within the workspace |
keys:self |
Create / revoke / list own API keys |
keys:admin |
Create / revoke / list any user's API keys within the workspace |
workspaces:admin |
Create / delete / disable workspaces (system-level) |
iam:admin |
JWT signing-key rotation, IAM-level operations |
metrics:read |
Prometheus metrics proxy |
Open-source role bundles
The open-source edition ships three roles:
| Role | Capabilities |
|---|---|
reader |
query, library:read, collections:read, knowledge:read, flows:read, config:read, keys:self |
writer |
everything in reader + library:write, collections:write, knowledge:write, ingest, export, import |
admin |
everything in writer + config:write, flows:write, users:read, users:write, users:admin, keys:admin, workspaces:admin, iam:admin, metrics:read |
Open-source bundles are deliberately coarse. workspaces:admin and
iam:admin live inside admin without a separate role; a single
admin user holds the keys to the whole deployment.
Authorisation evaluation
For a request bearing a resolved set of roles
R = {r1, r2, ...} against an endpoint that requires capability
c:
allow if c IN union(bundle(r) for r in R)
No hierarchy, no precedence, no role-order sensitivity. A user with a single role is the common case; a user with multiple roles gets the union of their bundles.
Unknown capabilities and unknown roles
- An endpoint declaring an unknown capability is a server-side bug and fails closed (403, logged).
- A user carrying a role name that is not defined in the role table is ignored for authorisation purposes and logged as a warning. Behaviour is deterministic: unknown roles contribute zero capabilities.
Capability scope
Every capability is implicitly scoped to the caller's resolved
workspace. A users:write capability does not permit a user
in workspace acme to create users in workspace beta — the
workspace-resolver has already narrowed the request to one
workspace before the capability check runs. See the IAM
specification for the workspace-resolver contract.
The three exceptions are the system-level capabilities
workspaces:admin and iam:admin, which operate across
workspaces by definition, and metrics:read, which returns
process-level series not scoped to any workspace.
Enterprise extensibility
Enterprise editions extend the role table additively:
data-analyst: {query, library:read, collections:read, knowledge:read}
helpdesk: {users:read, users:write, users:admin, keys:admin}
data-engineer: writer + {flows:read, config:read}
workspace-owner: admin − {workspaces:admin, iam:admin}
None of this requires a protocol change — the wire-protocol
roles field on user records is already a set, the gateway's
capability-check is already capability-based, and the capability
vocabulary is closed. Enterprise introduces roles whose bundles
compose the same capabilities differently.
When enterprise introduces a new capability (e.g. for a feature that does not exist in open source), the capability string is added to the vocabulary and recognised by the gateway build that ships that feature.