Skip to content

[Feature] Permissions and roles hardening — missing permissions, custom roles, audit log #92

Description

@carlosatta

What problem does this solve?

Routerly has a permission system (project:read/write, model:read/write, user:read/write, report:read) and three built-in roles (admin, operator, viewer). The RoleConfig type supports custom roles, but roles.json ships empty and there is no dashboard UI to manage them. Several important actions have no dedicated permission at all, meaning access control is binary (admin vs. non-admin) for settings, notification config, token management, and audit data.

Proposed solution

1. Fill the permission gaps

Add missing permissions to Permission type and enforce them on the relevant API endpoints:

New permission Covers
settings:read View global settings
settings:write Modify global settings (ports, storage, channels)
notification:write Add/edit/delete notification channels and rules
token:read List project tokens (currently: anyone with project:read)
token:write Create/delete/edit project tokens
role:write Create/edit/delete custom roles
audit:read Access audit log

2. Complete custom roles

  • Dashboard UI: Roles page (already exists as RolesPage.tsx) should allow creating, editing, and deleting custom roles
  • On user creation/edit, allow assigning any role from roles.json, not just the three built-ins
  • Validate that built-in roles (admin, operator, viewer) cannot be deleted

3. Project-level role enforcement

ProjectMember already has viewer | editor | admin role, but it is unclear if this is enforced server-side for per-project API calls. Verify and enforce: a project viewer cannot call project:write endpoints for their project; a project admin cannot affect other projects.

4. Audit log

Record all write operations to a tamper-evident append-only log:

  • Who (userId, email), what (endpoint + action), when (timestamp), result (success/forbidden)
  • Exposed via /api/audit with audit:read permission
  • Dashboard: Audit Logs page with filter by user, action type, date range
  • Retention: configurable (default 90 days)

5. Credential hygiene

  • Tokens in projects.json are stored in plaintext — consider storing SHA-256 hashes (show once on creation, like GitHub PATs)
  • Add token expiry support: optional expiresAt field on ProjectToken
  • Add token last-used timestamp so stale tokens can be identified and rotated

Alternatives you've considered

Keeping the current three-role model and documenting its limits. Acceptable for single-user deployments, not for teams.

Who would benefit from this?

Any team deployment where multiple people share a Routerly instance. Required for SOC 2 / ISO 27001 compliance (access control + audit trail are explicit requirements).

Additional context

The resolvePermissions() function in routes/api.ts already supports arbitrary permission arrays — the infrastructure is in place. This issue is primarily about filling the gaps, wiring the UI, and adding the audit trail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions