trustgraph/docs/tech-specs/capabilities.md
2026-04-23 11:29:09 +01:00

6.2 KiB
Raw Blame History

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.

References