Creating Roles and Privileges

Use this playbook whenever a user asks an agent to give someone access. Create the smallest task that satisfies the request, put tasks into a role, and assign the role. Never grant an unassigned element, an admin bundle, or is_superuser as a shortcut.

Step 1: Restate the request

Write down:

  • Who needs access: a named user or a job role.
  • What task: the screen or operation they must perform.
  • Where: app, model, menu or report.
  • Which operations: read, create, update, delete, correct, invoke, export.
  • Why: the business reason and who approved it.

If the request is "give them the full HR app" or "make them an administrator", stop and ask for the specific tasks. Offer task-level grants instead.

Step 2: Look for an existing role or task

Reuse before creating:

  • Open Access Control → Security configuration and search the role list.
  • Search the privilege list for an existing task.* privilege.
  • If an existing task covers the request, link it to the role and stop.
  • If an existing role covers the request, assign the role to the user and stop.

Step 3: Choose the task boundary

One privilege = one task. Use these patterns:

Request Task code
View employees task.humanresource.employee.view
Create or update employees task.humanresource.employee.manage
Delete employees task.humanresource.employee.delete
View the organization tree task.humanresource.organization.view
Maintain positions task.humanresource.position.manage
Maintain jobs, skills and qualifications task.humanresource.setup.manage
View HR reports task.humanresource.reports.view

Do not combine read, write and delete into one privilege unless the user explicitly asks for one "maintain" task. Do not create one privilege per model operation unless the operation is genuinely a separate task.

Step 4: Identify the exact elements

Use Access Control → Catalogue, or:

powershell
python manage.py rbac_explain --user <test-user> --target <app>

For the task, collect only:

  • the model targets and the minimum verbs;
  • the display menu target and its parent fasttab;
  • the module menu target if the task must open the module or a dashboard;
  • the action targets for buttons the task uses;
  • the output targets for reports the task reads.

Do not include unrelated targets to "make it work". If an autocomplete or related lookup is needed, grant view on that related model rather than the whole app.

Step 5: Create the privilege

Option A: Security workspace (normal)

  1. Open Access Control → Security configuration.
  2. Select the role that should receive the task, or create the role first.
  3. Choose New privilege.
  4. Enter: - Name: HR - View Employees - Code: task.humanresource.employee.view - Application: Human Resource - Description: the task and the business reason.
  5. Leave Grant to this role selected if the privilege is being created for this role.
  6. Open the privilege page and use Add items: - Models: add the employee models with the required verbs. - Display menus: add the module menu, parent fasttab and item menus. - Actions: add only the actions the task executes. - Outputs: add only the reports the task reads.
  7. Save and review the privilege counts.

Option B: Code catalog (framework apps)

For an app that ships with the framework, add a TaskPrivilegeSpec to enezarbac/task_catalog.py, then run rbac_sync. The seeder creates the privilege as active and unassigned. Do not link it to a role in code.

python
TaskPrivilegeSpec(
    code="task.humanresource.employee.view",
    name="HR - View Employees",
    application="Human Resource",
    model_grants=(
        ("humanresource.employee", ("view",)),
        ("humanresource.employeeposition", ("view",)),
        ("humanresource.employmentperiod", ("view",)),
    ),
    menu_codes=(
        "menu.humanresource.__module__",
        "menu.humanresource.hremployees",
    ),
    menu_codes=(
        "menu.humanresource.__module__",
        "menu.humanresource.hremployees",
    ),
    menu_url_names=(
        "humanresource:employee_list",
    ),
)

Step 6: Create the role

Create a role only when no existing role matches the job.

  1. In the security workspace choose New role.
  2. Use an uppercase code: HR_OFFICER, PAYROLL_CLERK, RECRUITER.
  3. Name it with the business job title.
  4. Describe what the role is allowed to do.
  5. Link only the task privileges required for that job.
  6. Do not link function.unclassified.admin, system.administrator, or a *.admin bundle to a normal staff role.

A role can contain several tasks. For example:

text
HR_OFFICER
  task.humanresource.organization.view
  task.humanresource.employee.view
  task.humanresource.employee.manage
  task.humanresource.position.manage
  task.humanresource.reports.view

Step 7: Assign the role to the user

  1. Open Access Control → Users.
  2. Find the user and open their roles.
  3. Add the role.
  4. Do not assign privileges directly to a user; assign the role.

Step 8: Verify

powershell
python manage.py rbac_explain --user <email> --target humanresource
python manage.py rbac_audit --strict --list

Check:

  • The user's roles and privileges are exactly the intended ones.
  • The effective models show only the intended verbs.
  • NORMAL_USER does not appear with an admin or fallback privilege.
  • The user can open the intended screen.
  • The user cannot open an unassigned HR screen or a delete URL.
  • The Role inspector shows the same effective permissions.

If access still fails, use the Troubleshooting Access decision table before changing the role again. Common causes are a missing menu grant, a missing related-model view, an unpublished dashboard, or a role override.

The agent must not run tests or claim the access works. The user is solely responsible for testing and validation.

Step 9: Record the change

Keep a short record in the ticket or release note:

  • requester and approver;
  • user and role;
  • task privileges and element codes;
  • verbs granted;
  • date;
  • reason.

Rejection rules

Refuse or escalate when asked to:

  • assign function.unclassified.admin to a role;
  • assign SYSTEM_ADMINISTRATOR to normal staff;
  • set is_superuser=True for convenience;
  • give NORMAL_USER an admin privilege;
  • add all of an app's targets to one privilege;
  • use app_labels to expose a whole user-facing app;
  • grant delete, correct or invoke without a named task and approval.

Rollback

  1. Remove the role from the user.
  2. Remove the task privilege from the role if it is no longer needed.
  3. Deactivate the privilege if no role uses it; do not delete a privilege that has role links.
  4. Run rbac_sync only if the catalogue changed. A normal sync does not restore a manual removal; reset does, so avoid reset unless the removal was a mistake.