Security Readiness Checklist

Every new model, screen, action, report or API endpoint must pass this checklist before it is considered finished. An element that is not catalogued and assigned cannot be granted, and only superusers can reach it.

1. App configuration

  • Declare menu_verbose_name, app_icon, app_entry_menu, menu_position and menus in the app's AppConfig.
  • Declare dashboards in dashboards when the app ships dashboard data sources.
  • Add a module-entry view and protect it:
python
from enezarbac.registry import rbac_protected
from enezarbac.services.menus import module_menu_code

@rbac_protected(module_menu_code("humanresource"), kind="menu")
def humanresource_module_entry(request):
    return redirect("enezadashboard:module_entry", module="humanresource")
  • Every URL referenced by a menu must exist. A dead menu link cannot be granted safely.

2. Models

  • Inherit the correct framework base model and include the entity field when the data is entity-scoped.
  • Do not add the model to RBAC_EXEMPT_MODELS or RBAC_INTERNAL_MODEL_LABELS unless it is genuinely internal.
  • Create and apply the migration.
  • Confirm the model appears in Access Control → Catalogue after rbac_sync.

3. CRUD views

  • Inherit BaseListView, BaseDetailView, BaseCreateView and BaseDeleteView (or the inline/setup/journal equivalents).
  • Do not override dispatch in a way that skips the framework mixins.
  • If a view uses a non-standard view_type, set rbac_operation explicitly. An unmapped model view is denied.

4. Custom views, actions and APIs

  • Use @rbac_action("action.<app>.<task>", name="...") for class-based or function-based actions.
  • For a function view wrapped by @login_required, put @rbac_action above @login_required so the attribute survives.
  • Use @rbac_protected(code, kind="menu" | "output") for bespoke menu or output endpoints.
  • Use @rbac_public only for login, registration, health checks and other genuinely public endpoints. Never mark an entire business app public.
  • WebSocket consumers must call has_action_permission(scope["user"], code) before joining a group or mutating data.

5. Menus and navigation

  • Add menu items in AppConfig.menus; the menu URL becomes a target automatically.
  • Grant the parent fasttab and the item to the task. Parent menus have no URL, so a task spec uses menu_codes for them.
  • Module menus use menu.<app>.__module__. This is also the code used by dashboard access.
  • Never use an unqualified short URL name in a selector; include the namespace (app:url_name).

6. Reports and outputs

  • Decorate the report view with @rbac_output("output.<app>.<slug>.view", "...").
  • Add the output code to the task that should read it.
  • A dashboard is visible only when the module menu is granted and, when set, its access_code is granted.
  • Report data sources must keep their entity and module checks; the output permission is not a substitute for data scoping.

7. Inline and autocomplete views

  • Inherit BaseInlineListView, BaseInlineDetailView, BaseInlineCreateView, BaseInlineDeleteView or BaseAutocompleteView.
  • These classes use the parent model's RBAC verbs. Do not replace them with a plain Django view without an explicit action code.

8. Django admin

Business models registered in Django admin bypass the request middleware because admin is an exempt namespace.

Choose one policy for the app:

  • do not register business models in Django admin, or
  • inherit RbacAdminModelAdminMixin in every ModelAdmin so view/add/change/delete checks call has_model_permission.
python
from django.contrib import admin
from enezarbac.admin import RbacAdminModelAdminMixin

@admin.register(Employee)
class EmployeeAdmin(RbacAdminModelAdminMixin, admin.ModelAdmin):
    ...

9. Create the task privilege

  • Add a TaskPrivilegeSpec in enezarbac/task_catalog.py for a framework app, or create the privilege in Access Control → Security configuration for a project-specific request.
  • Use task.<app>.<object>.<operation>.
  • Grant the minimum verbs: view for read, create/update for data entry, delete only for a separately named delete task, correct/invoke only with a stated reason.
  • Include only the menus, actions and outputs the task needs.
  • Do not link the task to a role automatically.
  • Do not use app_labels on a user-facing specification.
  • Do not rely on a broad function.*.use bundle to grant a task target. The seeder deactivates task targets found in a .use bundle; rbac_audit reports any that remain.

10. Verify before handoff

Run these steps yourself or ask the user to run them:

powershell
python manage.py rbac_sync
python manage.py rbac_audit --strict --list

Then check:

  1. The new targets appear in the Catalogue.
  2. The task privilege appears with the expected elements and verbs.
  3. A role with only NORMAL_USER is denied the new screen.
  4. A test role with the new task is allowed only the requested operations.
  5. python manage.py rbac_explain --user <test-user> shows the expected source.
  6. No new target appears only under function.unclassified.admin.

The user is solely responsible for testing and validation.