Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
4.4 KiB
Permissions & Groups
Armature uses group-based RBAC. Permissions are granted to groups, and users inherit the union of permissions from all groups they belong to. There are no per-user permission grants — all access flows through group membership.
Groups
System groups
| Group | ID | Purpose |
|---|---|---|
| Everyone | 00000000-...0001 |
Implicit membership for every authenticated user. Default permissions: extension.use, workflow.submit. |
| Admins | 00000000-...0002 |
Full platform access. Members receive all seven permission slugs. Replaces the legacy role = admin check. |
Every new user is automatically added to Everyone on registration. Admin status is granted by adding a user to the Admins group in Admin > People > Groups.
Custom groups
Administrators can create additional groups under Admin > People > Groups. Each custom group has:
- Name — display label
- Description — purpose (shown in admin UI)
- Scope — always
global(team-scoped groups reserved for future use) - Permissions — zero or more permission slugs from the table below
Permission slugs
Seven platform permissions control access to kernel features:
| Slug | Description |
|---|---|
surface.admin.access |
Full admin panel access (tabs, settings, package management) |
admin.view |
Read-only admin panel access (monitoring, health, audit log) |
extension.use |
Use installed extension surfaces and libraries |
extension.install |
Install, update, enable, and disable packages |
workflow.create |
Create and edit workflow definitions |
workflow.submit |
Submit instances to public-link workflows |
token.unlimited |
Bypass per-user token budgets (API rate limiting) |
Permissions follow a domain.action naming convention.
Permission resolution
When a request arrives, the kernel resolves the effective permission set:
- Fetch all groups the user belongs to (including Everyone).
- Union all permission arrays across those groups.
- Cache the result for the duration of the request.
A user has a permission if any of their groups grants it.
Frontend code checks permissions via sw.can('slug') — see the
Frontend JS Guide for details.
Extension permissions
Separate from user permissions, each package can request sandbox capabilities. These are granted per-package in Admin > Packages:
| Permission | Grants |
|---|---|
db.read |
Query ext_data tables (read-only) |
db.write |
Insert, update, and delete rows in ext_data tables |
api.http |
Make outbound HTTP requests from Starlark |
notifications.send |
Send in-app notifications to users |
secrets.read |
Read admin-configured extension secrets |
realtime.publish |
Publish WebSocket events to subscribed clients |
connections.read |
Read external connection configs (decrypted) |
workflow.access |
Read workflow definitions and instances |
See the Starlark Reference for how these map to sandbox modules.
Settings cascade
Package settings use a three-tier resolution model:
user override → team override → global default
At each tier:
- Global — set by admins in Admin > Packages > Settings
- Team — set by team admins in Team Admin > Settings
- User — set by users in Settings > Extensions
The user_overridable flag
Each setting key in a package manifest can declare user_overridable:
{
"settings": [
{ "key": "theme", "user_overridable": true },
{ "key": "api_endpoint", "user_overridable": false }
]
}
true(default) — team and user scopes can override the global value.false— only the global (admin) value is used. Team and user values are silently ignored during resolution.
This gives administrators a lock mechanism: set user_overridable: false
on security-sensitive keys to prevent lower scopes from changing them,
while allowing cosmetic preferences to flow freely.
Resolution algorithm
- Start with the global value for each key.
- For each key where
user_overridableis true (or undeclared):- If a team-scoped value exists, it overrides global.
- If a user-scoped value exists, it overrides team.
- For keys where
user_overridableis false:- Team and user values are discarded.
- Unknown keys (not in schema) default to overridable.