security rights #4

Open
opened 2026-03-19 10:31:38 +00:00 by despiegk · 3 comments
Owner

on a group we can give following rights

  • is admin, can do all
  • can create/modify/delete workspace
  • can create/modify/delete channels: select the workspaces, multiple
  • can be admin in workspace(s): select the workspaces, multiple (admins can do everything in 1 workspace)|
  • ... what more do we need

then implement this in the server so its enforced

on a group we can give following rights - is admin, can do all - can create/modify/delete workspace - can create/modify/delete channels: select the workspaces, multiple - can be admin in workspace(s): select the workspaces, multiple (admins can do everything in 1 workspace)| - ... what more do we need then implement this in the server so its enforced
Author
Owner

Implementation Spec for Issue #4: Security Rights

Objective

Add a role-based permission system to hero_collab where groups carry security rights that govern what their members can do. Permissions are assigned at the group level and enforced server-side on every mutating RPC call.

Rights Model

A group can be assigned one or more of:

  • admin — full admin, can do everything across all workspaces
  • workspace_manage — can create, modify, and delete workspaces
  • channel_manage — can create, modify, and delete channels in specified workspace(s)
  • workspace_admin — full admin within specified workspace(s)
  • group_manage — can create, modify, and delete groups and their memberships

Rights scoped to workspaces (channel_manage, workspace_admin) store the list of workspace IDs they apply to.

Database: New group_rights Table

CREATE TABLE IF NOT EXISTS group_rights (
    group_id TEXT NOT NULL,
    right TEXT NOT NULL CHECK(right IN ('admin', 'workspace_manage', 'channel_manage', 'workspace_admin', 'group_manage')),
    workspace_ids TEXT NOT NULL DEFAULT '[]',
    data TEXT NOT NULL,
    PRIMARY KEY (group_id, right)
);

New RPC Methods

  • group.rights.set — set rights for a group (admin only)
  • group.rights.get — get rights for a group
  • user.permissions — resolve effective permissions for a user (union of all group rights, recursively)

Enforcement

  • All mutating RPCs accept optional caller_id parameter
  • If caller_id is omitted → no authorization (backward compat)
  • If caller_id lacks permission → JSON-RPC error -32003
  • Permission resolution walks nested groups (depth cap 10)

Implementation Steps

  1. DB schema + model — Add GroupRight struct and group_rights table migration
  2. Permissions module — New handlers/permissions.rs with check_permission() and resolve_user_rights()
  3. Group rights RPCsrights_set, rights_get handlers + user.permissions + RPC registration
  4. Workspace/Channel enforcement — Add permission checks to workspace and channel handlers
  5. Message/Document/Room/Group enforcement — Add permission checks to remaining handlers
  6. SDK update — Add GroupRight type, rights methods, and caller_id param to all mutating calls
  7. OpenRPC spec update — Document new methods and caller_id parameter

Acceptance Criteria

  • group_rights table created by migration
  • group.rights.set / group.rights.get / user.permissions work correctly
  • Admin can do everything; scoped rights enforced per workspace
  • Nested group permissions resolve correctly
  • caller_id omission = backward compat (no auth check)
  • Missing permission returns error code -32003
  • SDK exposes all new methods
  • OpenRPC spec updated
  • Existing tests pass
## Implementation Spec for Issue #4: Security Rights ### Objective Add a role-based permission system to hero_collab where groups carry security rights that govern what their members can do. Permissions are assigned at the group level and enforced server-side on every mutating RPC call. ### Rights Model A group can be assigned one or more of: - **`admin`** — full admin, can do everything across all workspaces - **`workspace_manage`** — can create, modify, and delete workspaces - **`channel_manage`** — can create, modify, and delete channels in specified workspace(s) - **`workspace_admin`** — full admin within specified workspace(s) - **`group_manage`** — can create, modify, and delete groups and their memberships Rights scoped to workspaces (`channel_manage`, `workspace_admin`) store the list of workspace IDs they apply to. ### Database: New `group_rights` Table ```sql CREATE TABLE IF NOT EXISTS group_rights ( group_id TEXT NOT NULL, right TEXT NOT NULL CHECK(right IN ('admin', 'workspace_manage', 'channel_manage', 'workspace_admin', 'group_manage')), workspace_ids TEXT NOT NULL DEFAULT '[]', data TEXT NOT NULL, PRIMARY KEY (group_id, right) ); ``` ### New RPC Methods - `group.rights.set` — set rights for a group (admin only) - `group.rights.get` — get rights for a group - `user.permissions` — resolve effective permissions for a user (union of all group rights, recursively) ### Enforcement - All mutating RPCs accept optional `caller_id` parameter - If `caller_id` is omitted → no authorization (backward compat) - If `caller_id` lacks permission → JSON-RPC error `-32003` - Permission resolution walks nested groups (depth cap 10) ### Implementation Steps 1. **DB schema + model** — Add `GroupRight` struct and `group_rights` table migration 2. **Permissions module** — New `handlers/permissions.rs` with `check_permission()` and `resolve_user_rights()` 3. **Group rights RPCs** — `rights_set`, `rights_get` handlers + `user.permissions` + RPC registration 4. **Workspace/Channel enforcement** — Add permission checks to workspace and channel handlers 5. **Message/Document/Room/Group enforcement** — Add permission checks to remaining handlers 6. **SDK update** — Add `GroupRight` type, rights methods, and `caller_id` param to all mutating calls 7. **OpenRPC spec update** — Document new methods and `caller_id` parameter ### Acceptance Criteria - [ ] `group_rights` table created by migration - [ ] `group.rights.set` / `group.rights.get` / `user.permissions` work correctly - [ ] Admin can do everything; scoped rights enforced per workspace - [ ] Nested group permissions resolve correctly - [ ] `caller_id` omission = backward compat (no auth check) - [ ] Missing permission returns error code `-32003` - [ ] SDK exposes all new methods - [ ] OpenRPC spec updated - [ ] Existing tests pass
Author
Owner

Implementation Complete

Test Results

  • Total: 4 tests
  • Passed: 4
  • Failed: 0

All integration tests (test_rpc_discover, test_server_health), unit tests, and doc-tests pass.

Changes Made

New files:

  • crates/hero_collab_server/src/handlers/permissions.rs — Core permission resolution and checking module

Modified files:

  • crates/hero_collab_server/src/models.rs — Added GroupRight struct
  • crates/hero_collab_server/src/db.rs — Added group_rights table migration
  • crates/hero_collab_server/src/handlers/mod.rs — Registered permissions module
  • crates/hero_collab_server/src/handlers/group.rs — Added rights_set, rights_get handlers + permission checks on CRUD
  • crates/hero_collab_server/src/handlers/workspace.rs — Added permission checks to create/update/delete
  • crates/hero_collab_server/src/handlers/channel.rs — Added permission checks to create/update/archive/delete
  • crates/hero_collab_server/src/handlers/message.rs — Added permission checks to send/update/delete (authors can edit own messages)
  • crates/hero_collab_server/src/handlers/document.rs — Added permission checks to create/update/delete/share
  • crates/hero_collab_server/src/handlers/room.rs — Added permission checks to create/end
  • crates/hero_collab_server/src/rpc.rs — Registered group.rights.set, group.rights.get, user.permissions
  • crates/hero_collab_sdk/src/lib.rs — Added GroupRight type, group_rights_set, group_rights_get, user_permissions methods
  • crates/hero_collab_server/openrpc.json — Added GroupRight schema and 3 new method definitions

Notes

  • caller_id is optional on all mutating RPCs — omitting it bypasses authorization (backward compat)
  • Permission resolution recursively walks nested groups (depth cap 10)
  • Message authors can always edit/delete their own messages regardless of permissions
## Implementation Complete ### Test Results - Total: 4 tests - Passed: 4 - Failed: 0 All integration tests (`test_rpc_discover`, `test_server_health`), unit tests, and doc-tests pass. ### Changes Made **New files:** - `crates/hero_collab_server/src/handlers/permissions.rs` — Core permission resolution and checking module **Modified files:** - `crates/hero_collab_server/src/models.rs` — Added `GroupRight` struct - `crates/hero_collab_server/src/db.rs` — Added `group_rights` table migration - `crates/hero_collab_server/src/handlers/mod.rs` — Registered permissions module - `crates/hero_collab_server/src/handlers/group.rs` — Added `rights_set`, `rights_get` handlers + permission checks on CRUD - `crates/hero_collab_server/src/handlers/workspace.rs` — Added permission checks to create/update/delete - `crates/hero_collab_server/src/handlers/channel.rs` — Added permission checks to create/update/archive/delete - `crates/hero_collab_server/src/handlers/message.rs` — Added permission checks to send/update/delete (authors can edit own messages) - `crates/hero_collab_server/src/handlers/document.rs` — Added permission checks to create/update/delete/share - `crates/hero_collab_server/src/handlers/room.rs` — Added permission checks to create/end - `crates/hero_collab_server/src/rpc.rs` — Registered `group.rights.set`, `group.rights.get`, `user.permissions` - `crates/hero_collab_sdk/src/lib.rs` — Added `GroupRight` type, `group_rights_set`, `group_rights_get`, `user_permissions` methods - `crates/hero_collab_server/openrpc.json` — Added `GroupRight` schema and 3 new method definitions ### Notes - `caller_id` is optional on all mutating RPCs — omitting it bypasses authorization (backward compat) - Permission resolution recursively walks nested groups (depth cap 10) - Message authors can always edit/delete their own messages regardless of permissions
Author
Owner

Implementation committed: f0167b8

Browse: f0167b8

Implementation committed: `f0167b8` Browse: https://forge.ourworld.tf/lhumina_code/hero_collab/commit/f0167b8
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_collab#4
No description provided.