Skip to content

Latest commit

 

History

History
215 lines (166 loc) · 7.06 KB

File metadata and controls

215 lines (166 loc) · 7.06 KB

Permissions Registry

Authoritative reference for the permission strings recognised by Powernode access control.

Table of Contents

Overview

Powernode uses permission-based access control. The frontend MUST check permissions only, never roles. The backend uses current_user.has_permission?('name') for authorization. Roles exist only as a backend convenience for grouping permissions; they are never inspected by frontend code. The canonical registry is Permission records seeded by server/app/services/permission_seeder.rb.

For the design rationale (why permissions instead of roles, ABAC vs RBAC trade-offs, etc.), see ../concepts/permissions.md.

Forbidden Patterns

Frontend

// FORBIDDEN — role-based access control
const canManage    = currentUser?.roles?.includes('account.manager');
const isSystemAdmin = currentUser?.role === 'system.admin';
if (user.roles.includes('billing.manager')) { return <AdminPanel />; }

// FORBIDDEN — mixed role / permission checks
const hasAccess = user.roles.includes('admin') || user.permissions.includes('read');

// FORBIDDEN — hardcoded role checks
if (currentUser?.roles?.some(r => r.includes('admin'))) { /* ... */ }

Backend

# FORBIDDEN — .include? on permissions collection (returns objects, not strings)
if current_user.permissions.include?('users.manage')

# FORBIDDEN — role-based authorization
if current_user.roles.any? { |r| r.name == 'admin' }

Correct Patterns

Frontend

const canManageUsers   = currentUser?.permissions?.includes('users.manage');
const canViewBilling   = currentUser?.permissions?.includes('billing.read');
const canAccessAdmin   = currentUser?.permissions?.includes('admin.access');

if (!canAccessAdmin) return <AccessDenied />;

<Button disabled={!currentUser?.permissions?.includes('users.create')}>
  Create User
</Button>

{currentUser?.permissions?.includes('analytics.read') && <AnalyticsDashboard />}

Backend

# Correct — has_permission? helper
if current_user.has_permission?('users.manage')
  # allow
end

# Controller before_action
before_action -> { require_permission('users.read') },   only: %i[index show]
before_action -> { require_permission('users.manage') }, only: %i[create update destroy]

# Inline
def sensitive_action
  return render_forbidden("Access denied") unless current_user.has_permission?('admin.access')
  # proceed
end

Permission Categories

Permissions are organised by prefix. The seeder is the source of truth; counts shown below are illustrative — query the runtime registry for current numbers.

Category Description
admin.* Admin panel access — accounts, AI, audit, billing, DevOps, Docker, files, Git, marketplace
ai.* AI features — agents, workflows, memory, knowledge, conversations, providers, autonomy
system.* System-level — admin, monitoring, health, configuration
supply_chain.* Supply chain management
devops.* DevOps — pipelines, providers, repositories, templates
swarm.* Docker Swarm operations
git.* Git — approvals, credentials, pipelines, providers, repositories
docker.* Docker container management
marketing.* Marketing campaigns
integrations.* Third-party integrations
app.* App marketplace
files.* File management
kb.* Knowledge base articles
mcp.* MCP protocol operations
subscription.* Subscription lifecycle (extension-gated)
page.* CMS pages
review.* Code reviews
storage.* Storage backends
listing.* Marketplace listings
team.* Team management
webhook.* Webhook management
api.* API key management
audit.* Audit logs
billing.* Billing operations (extension-gated)
plans.* Plan management (extension-gated)
report.* Reports
user.* User management
invoice.* Invoice management (extension-gated)
marketplace.* Marketplace access
users.* User listing

AI Autonomy Permissions

Permission Description
ai.kill_switch.manage Activate and deactivate the AI emergency kill switch
ai.goals.manage Create, update, and delete AI agent goals
ai.intervention_policies.manage Configure AI intervention policies and notification preferences
ai.proposals.view View AI agent proposals
ai.proposals.review Approve or reject AI agent proposals
ai.escalations.view View AI agent escalations
ai.escalations.resolve Acknowledge and resolve AI agent escalations
ai.feedback.submit Submit feedback on AI agent performance
ai.feedback.view View AI agent feedback history
ai.autonomy.manage Manage AI agent autonomous behaviour and duty cycles

Role assignments: ai.kill_switch.manage is automatically assigned to owner and admin roles.

Common Permission Patterns

# CRUD pattern
resource.create
resource.read
resource.update
resource.delete

# Management shortcut
resource.manage     # implies full CRUD

# Admin-scoped
admin.resource.read
admin.resource.update
admin.resource.delete

Backend Roles

Roles exist only for permission grouping in the backend. Frontend code NEVER checks roles.

Role Description Typical Permissions
system.admin Full system access All permissions
account.manager Account management Account-scoped permissions
account.member Basic access Read-only permissions
billing.manager Billing operations Billing-related permissions (extension-gated)

API Response Format

User objects returned from API MUST include a permissions array:

class UserSerializer
  def permission_names
    object.permissions.pluck(:name)
  end
end
{
  "data": {
    "id": "uuid",
    "email": "user@example.com",
    "permissions": ["users.read", "billing.read", "analytics.read"]
  }
}

Navigation Filtering

const filteredNavItems = navigationItems.filter(item => {
  if (!item.permission) return true;
  return currentUser?.permissions?.includes(item.permission);
});

Related docs

Materials previously at

  • docs/platform/PERMISSION_SYSTEM_REFERENCE.md (registry portions)

Last verified: 2026-05-17