Feat v0.7.4 docs surface work (#58)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m51s
CI/CD / test-sqlite (push) Successful in 2m51s
CI/CD / build-and-deploy (push) Successful in 39s
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m51s
CI/CD / test-sqlite (push) Successful in 2m51s
CI/CD / build-and-deploy (push) Successful in 39s
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #58.
This commit is contained in:
121
docs/PERMISSIONS-AND-GROUPS.md
Normal file
121
docs/PERMISSIONS-AND-GROUPS.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# 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:
|
||||
|
||||
1. Fetch all groups the user belongs to (including Everyone).
|
||||
2. Union all permission arrays across those groups.
|
||||
3. 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](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](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`:
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
1. Start with the global value for each key.
|
||||
2. For each key where `user_overridable` is true (or undeclared):
|
||||
- If a team-scoped value exists, it overrides global.
|
||||
- If a user-scoped value exists, it overrides team.
|
||||
3. For keys where `user_overridable` is false:
|
||||
- Team and user values are discarded.
|
||||
4. Unknown keys (not in schema) default to overridable.
|
||||
Reference in New Issue
Block a user