feat: add RBAC (Viewer/Member/Admin) to Django admin#1398
feat: add RBAC (Viewer/Member/Admin) to Django admin#1398thomasrockhu-codecov wants to merge 4 commits into
Conversation
Introduce three staff access levels gated on `is_staff`, enforced centrally via a `CodecovAdminSite` that wraps every registered `ModelAdmin` with an `RBACAdminMixin`: - Viewer: read-only, no actions, Redis/Celery queue models hidden, and custom action views (reprocess/notify) denied. - Member: matches today's staff access. - Admin: driven solely by `is_superuser`; setting it False demotes to Viewer. Adds a `User.staff_role` field (synced with `is_superuser` on save) plus a data migration mapping existing staff to Member and superusers to Admin, and surfaces the role controls in `UserAdmin` (superuser-only edits).
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1398 +/- ##
==========================================
- Coverage 91.89% 91.86% -0.04%
==========================================
Files 1324 1327 +3
Lines 50851 51011 +160
Branches 1626 1634 +8
==========================================
+ Hits 46730 46861 +131
- Misses 3815 3840 +25
- Partials 306 310 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (81.63%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. 📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
b2e125e to
8c5dd55
Compare
Non-staff users now have an explicit `none` staff role instead of defaulting to Viewer: - `User.save()` sets `staff_role` to `none` whenever `is_staff` is False, and `effective_staff_role` returns `NONE` for non-staff users. - Migration 0077 adds the `none` choice/default and backfills existing non-staff, non-superuser rows. Also adds a "role" filter to the Users admin changelist via `StaffRoleListFilter`, which mirrors the effective-role logic (superuser => Admin, non-staff => None), and surfaces `None` as the read-only derived role for non-staff targets in `UserAdmin`.
Remove the unused is_admin_staff/is_member_staff/is_viewer_staff/is_none_staff User properties and condense redundant comments/docstrings across the admin RBAC code for readability.
Simplify StaffRoleListFilter to query the synced staff_role column directly, and combine the two staff_role migrations into one.
fixes https://harness.atlassian.net/browse/COV-8
Summary
Adds a three-tier RBAC model to the Codecov Django admin, gated on
is_staff, enforced centrally so every registeredModelAdminis covered without per-app edits.redis_admin) hidden, and custom action views (commit reprocess/notify, redis chart fragment) return 403.is_superuser; toggling it toTrueforces theadminrole, and demoting (True -> False) drops the user toViewer.How it works
User.staff_rolefield (viewer/member/admin) on the sharedcodecov_authmodel, kept in sync withis_superuserinUser.save().effective_staff_rolederives Admin fromis_superuser.0076_user_staff_roleadds the column and backfills: existing staff -> Member, superusers -> Admin, everyone else -> Viewer (the default).RBACAdminMixin+CodecovAdminSite(wired viaCodecovAdminConfig.default_site, replacingdjango.contrib.admininINSTALLED_APPS) auto-wrap every registeredModelAdmin.deny_viewers()guards GET-triggered custom admin views incoreandredis_admin.UserAdminsurfacesis_staff/is_superuser/staff_role, editable only by superusers, with the Admin level managed automatically.UserFactorydefaults staff test users to Member so the existing admin suite keeps its historical access; Viewer tests opt in explicitly.Test plan
make test(Docker + Postgres/Timescale) — new suitecodecov_auth/tests/test_admin_rbac.pycovers role sync, superuser demotion to Viewer, Viewer read-only/no-actions, Redis models hidden, custom-view 403 vs Member access, and UserAdmin field/choice gating.makemigrations --checkis clean and0076applies.staff_role=viewer) and confirm read-only admin with Redis hidden; as a Member confirm unchanged access; toggleis_superuserand confirm Admin/Viewer transitions.Made with Cursor