Skip to main content

Adding a New Role

This guide explains how to add a new role to Arc's IAM (Identity and Access Management) system. Our role-based access control system uses YAML configuration files to define permissions for each role.

Prerequisites

Before creating a role policy, the role must be defined in the application's role system:

  • Role Definition: The role must exist in app/models/concerns/roles.rb in the Roles::Role module
  • Display Name: The role should have an entry in the DISPLAY_NAMES hash
  • System Role Arrays: Add the role to appropriate system role arrays (e.g., ECM_SYSTEM_ROLES, CHW_SYSTEM_ROLES)

Overview

Adding a new role involves three main steps:

  1. Define the role in the Roles module (prerequisite)
  2. Create a role policy file defining the role's permissions
  3. Add tests to ensure the role has the correct permissions

All permissions must already exist in the inventory (modules/iam/app/permissions/inventory.yml) before they can be assigned to roles.

Step 1: Define the Role in the Roles Module

Before creating a policy file, ensure the role is defined in the application's role system.

Add Role Constant

Add your role to app/models/concerns/roles.rb:

module Roles
module Role
# ... existing roles ...
SUPERVISOR = "supervisor".freeze
# ... more roles ...
end

# Add to appropriate system role array
ECM_SYSTEM_ROLES = [
# ... existing roles ...
Role::SUPERVISOR,
].freeze

# Update SYSTEM_ROLES array automatically includes the role through category arrays

# Add display name
DISPLAY_NAMES = {
# ... existing mappings ...
Role::SUPERVISOR => "Supervisor",
}.freeze

# Add role acronym if needed
ROLE_ACRONYMS = {
# ... existing mappings ...
Role::SUPERVISOR => "SUP",
}.freeze
end

Step 2: Create the Role Policy File

Create a new YAML file in modules/iam/app/permissions/ for your role. The filename should match the role identifier.

File Structure

# modules/iam/app/permissions/new_role_name.yml
# yaml-language-server: $schema=./schemas/role_policy.json
name: Display Name for Role
id: role_identifier_used_in_code
permissions:
resource_name:
action_name: {}
another_action: {}
another_resource:
action_name: {}

Example: Creating a "Supervisor" Role

# modules/iam/app/permissions/supervisor.yml
# yaml-language-server: $schema=./schemas/role_policy.json
name: Supervisor
id: supervisor
permissions:
chart:
read: {}
create: {}
update: {}
care_plan:
update: {}
review: {}
care_pod:
read: {}
create: {}
update: {}
document:
read: {}
create: {}
update: {}
delete: {}
user:
read: {}
update: {}

Key Guidelines

  • Schema Validation: Include the schema comment for IDE validation
  • Descriptive Name: Use a human-readable name for the name field
  • Consistent ID: Use snake_case for the id field that matches the filename
  • Empty Permission Objects: Each permission uses an empty hash {} (this will change in future versions)
  • Available Permissions: Only use permissions that exist in inventory.yml

Step 3: Add Tests

Add comprehensive tests to ensure your role has the correct permissions and no unintended access.

Test Structure

Add a new test block in modules/iam/spec/permissions/policies_spec.rb:

describe 'supervisor' do
include_examples 'Policy with the right permissions', role: :supervisor do
let(:expected_permissions) do
{
chart: [:read, :create, :update],
care_plan: [:update, :review],
care_pod: [:read, :create, :update],
document: [:read, :create, :update, :delete],
user: [:read, :update],
}.as_json
end
end
end

What the Tests Verify

The shared test example 'Policy with the right permissions' verifies:

  1. Policy Exists: The role policy file is properly loaded
  2. No Extra Permissions: The role doesn't have permissions not listed in expected_permissions
  3. No Missing Permissions: All permissions in expected_permissions are granted to the role
  4. Permission Validity: All permissions exist in the inventory

Running Tests

# Run all policy tests
bundle exec rspec modules/iam/spec/permissions/policies_spec.rb

Validation and Debugging

Common Issues

  1. Role Not Found: Check that the id field matches the role identifier in the code
  2. Permission Not Found: Ensure all permissions exist in inventory.yml
  3. Test Failures: Ensure expected_permissions exactly matches the YAML file

Best Practices

1. Principle of Least Privilege

Grant only the minimum permissions necessary for the role's responsibilities:

# Good: Specific permissions for role needs
permissions:
chart:
read: {}
update: {}
document:
read: {}

# Avoid: Granting unnecessary permissions
permissions:
chart:
read: {}
create: {}
update: {}
delete: {} # Probably not needed for most roles

2. Consistent Naming

Use descriptive, consistent names:

# Good
name: Clinical Care Coordinator
id: clinical_coordinator

# Avoid
name: CCC
id: ccc_role