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_superuseras 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:
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)
- Open Access Control → Security configuration.
- Select the role that should receive the task, or create the role first.
- Choose New privilege.
- Enter:
- Name:
HR - View Employees- Code:task.humanresource.employee.view- Application:Human Resource- Description: the task and the business reason. - Leave Grant to this role selected if the privilege is being created for this role.
- 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.
- 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.
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.
- In the security workspace choose New role.
- Use an uppercase code:
HR_OFFICER,PAYROLL_CLERK,RECRUITER. - Name it with the business job title.
- Describe what the role is allowed to do.
- Link only the task privileges required for that job.
- Do not link
function.unclassified.admin,system.administrator, or a*.adminbundle to a normal staff role.
A role can contain several tasks. For example:
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
- Open Access Control → Users.
- Find the user and open their roles.
- Add the role.
- Do not assign privileges directly to a user; assign the role.
Step 8: Verify
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_USERdoes 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.adminto a role; - assign
SYSTEM_ADMINISTRATORto normal staff; - set
is_superuser=Truefor convenience; - give
NORMAL_USERan admin privilege; - add all of an app's targets to one privilege;
- use
app_labelsto expose a whole user-facing app; - grant
delete,correctorinvokewithout a named task and approval.
Rollback
- Remove the role from the user.
- Remove the task privilege from the role if it is no longer needed.
- Deactivate the privilege if no role uses it; do not delete a privilege that has role links.
- Run
rbac_synconly if the catalogue changed. A normal sync does not restore a manual removal;resetdoes, so avoid reset unless the removal was a mistake.