Features

RBAC

Users, groups, roles, and the permission model that gates every dashboard action.

telark models access control as a role-based system on top of custom resources. Users, groups, and roles are first-class CRDs owned by the exporter service; the auth service resolves the permission set for the current session on every request.

The four resources

ResourceNotes
UserIdentity. Holds id, username, full name, email, identity provider.
UserPasskeyOne per registered authenticator on a user.
GroupA named collection of users.
RoleA bundle of scope → permission level rules with optional protection and validity.
CategoryTagging primitive used to scope roles within a domain.

Every one of these is persisted as a Kubernetes CRD via the exporter service. The dashboard talks to the same HTTP API the auth service uses internally — no kubectl detour required.

Built-in roles

Four roles ship out of the box and cover the majority of teams:

RoleWhat it grants
AdminFull read/write on every telark scope, including configuration, RBAC mutation, and global config.
ContributorCreate and edit protection plans, trigger rollbacks, manage applications. Cannot touch RBAC or global config.
ReadOnlyRead everything. Cannot mutate anything.
OwnerBootstrap admin assigned by the configured email on first login. Same surface as Admin.

The bootstrap admin is set by the auth-service config; every additional admin is created by assigning the Admin role via Settings → Access & permissions.

Custom roles

Custom roles are first-class. The shape:

{
  id: string;
  name: string;
  description: string;
  version: string;
  type: RoleType;
  priority: number;
  categoryID: string;
  scopesAndPermissions: [{ scope: string; level: PermissionLevel; ... }];
  protection?: Protection;       // optional system-role guards
  status: RoleStatus;             // active | deprecated | deleted
  validity?: Validity;            // optional time-bound role
  creationDate: string;
  // … audit fields
}

A role's scopesAndPermissions is the substantive part — every entry pairs a telark scope (applications, protection-plans, global-config, rbac, etc.) with a PermissionLevel. priority is used to resolve conflicts when a user inherits multiple roles.

A role's protection block prevents accidental deletion of system-critical roles. A role's validity block lets a role expire on a date or after a window — useful for time-bound elevation.

Groups

Groups bundle users. Every user can be a member of multiple groups. A role can be assigned to:

  • A specific user (via assignedTo.userIDs).
  • A specific group (via assignedTo.groupIDs).

Permission resolution: take the set of roles assigned directly to the user, union with the roles assigned to every group the user is a member of, then sort by priority and resolve conflicts in priority order. The result is a flat map of scope → PermissionLevel.

Permission levels

A role's scopesAndPermissions uses PermissionLevel to encode the level of access. The auth-service permissions endpoint collapses this to a { scope, level, deny? } triple the UI uses to gate elements.

The dashboard's permission hook (features/access-and-permissions/hooks/permissions) consumes the endpoint output and exposes usePermission(scope, level, deny?). Every button gated by RBAC reads from this hook.

The UI surface

dashboard-ui/src/features/access-and-permissions/ covers:

  • Users — list, manage, assign roles directly, scope filters.
  • Groups — list, create, edit, attach members, attach roles, bulk operations. (The Create group button is the canonical one — its style is the dashboard's reference for primary buttons.)
  • Roles — list, view scopes and permissions, manage category mapping. Custom roles are created from this surface.
  • Categories — tags used to filter roles in the role picker.

Every page renders an empty state, a loading state, an error state, and the main list — with permission gating on the create and edit actions.

Endpoints (resource API)

All persistence calls go to the exporter service:

MethodPathPurpose
POST/resources/usersCreate a user.
GET/resources/users/{id} / ?username= / ?email=Resolve a user.
PATCH/resources/users/{id}Patch.
DELETE/resources/users/{id}Delete.
POST/resources/groupsCreate a group.
GET/resources/groups/{id}Read.
PATCH/resources/groups/{id}Patch.
DELETE/resources/groups/{id}Delete.
POST/resources/rolesCreate a role.
GET/resources/roles/{id}Read.
PATCH/resources/roles/{id}Patch.
DELETE/resources/roles/{id}Delete.

Every write dispatches an in-app notification so the affected user sees a Role assigned or Group membership changed toast next time they load the dashboard.