Context
Follow-on from #346 (site-wide guest / user / feeder / admin model). Implementation in #354 introduces:
Meshflow/common/access.py — AccessLevel enum and get_access_level()
Meshflow/common/drf_permissions.py — custom DRF classes (AllowGuestReadOnly, IsFeederOrAdmin, etc.)
- A single Django
feeder group for trusted operators; is_staff for admin
- Per-view permission class wiring and serializer redaction for guest reads
That delivery is intentional and shippable, but authorization logic is still mostly bespoke Python rather than declarative Django permissions.
Related work (not in scope here):
Goal (future)
Refactor toward first-class Django Permission and Group objects so that:
- Capabilities (e.g.
trigger_traceroute, manage_api_keys, ingest_packets, manage_constellations, read_observed_node_positions) are defined as custom permissions on relevant models or a dedicated permissions app.
- Groups map cleanly to roles: at minimum
feeder; consider whether user and admin should also be groups vs continuing to use is_staff / default authenticated user.
- DRF viewsets use
DjangoModelPermissions, DjangoObjectPermissions, or thin wrappers that check user.has_perm(...) instead of ad-hoc user_is_feeder() scattered across views.
- Guest read remains explicit (unauthenticated + serializer redaction) — likely still needs custom permission classes or a documented exception list, since Django auth has no built-in “guest”.
- Admin surface (DX, constellation CRUD) aligns with
is_staff or a dedicated meshflow_admin permission set.
Why
- Auditability: permission matrix in docs maps to real
auth_permission rows.
- Operability: grant/revoke capabilities via Django admin or management commands without code changes.
- Consistency: reduces drift between
access.py, DRF classes, and view-level checks.
- Extensibility: when constellation/regional ACLs return, object-level perms are already idiomatic.
Non-goals (this ticket)
Suggested approach (sketch)
- Inventory — derive permission codenames from
docs/permissions/README.md matrix and current DRF permission_classes.
- Define permissions — migration to create
Permission rows; assign defaults to feeder and staff groups.
- Replace helpers — migrate
user_is_feeder(), user_can_manage_api_keys(), traceroute helpers to has_perm checks where possible; keep get_access_level() for serializer context / guest redaction.
- DRF — standardize on permission classes backed by Django perms; document guest exceptions.
- Tests — permission-matrix tests assert
has_perm + HTTP status, not only AccessLevel.
- Docs — update
docs/permissions/README.md with codename ↔ endpoint mapping.
Acceptance criteria
Priority
Future / after #346 ships. Safe to schedule once #354 is merged and permissions docs are stable.
Context
Follow-on from #346 (site-wide guest / user / feeder / admin model). Implementation in #354 introduces:
Meshflow/common/access.py—AccessLevelenum andget_access_level()Meshflow/common/drf_permissions.py— custom DRF classes (AllowGuestReadOnly,IsFeederOrAdmin, etc.)feedergroup for trusted operators;is_stafffor adminThat delivery is intentional and shippable, but authorization logic is still mostly bespoke Python rather than declarative Django permissions.
Related work (not in scope here):
docs/permissions/outstanding-tasks.mdGoal (future)
Refactor toward first-class Django
PermissionandGroupobjects so that:trigger_traceroute,manage_api_keys,ingest_packets,manage_constellations,read_observed_node_positions) are defined as custom permissions on relevant models or a dedicated permissions app.feeder; consider whetheruserandadminshould also be groups vs continuing to useis_staff/ default authenticated user.DjangoModelPermissions,DjangoObjectPermissions, or thin wrappers that checkuser.has_perm(...)instead of ad-hocuser_is_feeder()scattered across views.is_staffor a dedicatedmeshflow_adminpermission set.Why
auth_permissionrows.access.py, DRF classes, and view-level checks.Non-goals (this ticket)
ConstellationUserMembershipor regional ACLsSuggested approach (sketch)
docs/permissions/README.mdmatrix and current DRFpermission_classes.Permissionrows; assign defaults tofeederand staff groups.user_is_feeder(),user_can_manage_api_keys(), traceroute helpers tohas_permchecks where possible; keepget_access_level()for serializer context / guest redaction.has_perm+ HTTP status, not onlyAccessLevel.docs/permissions/README.mdwith codename ↔ endpoint mapping.Acceptance criteria
feeder(and admin) groups hold permissions via migrations/data migration, not only hard-coded group name checksrun_deploy_tasksif used)Priority
Future / after #346 ships. Safe to schedule once #354 is merged and permissions docs are stable.