Skip to content

Refactor permissions to Django auth Permission and Group model #355

@pskillen

Description

@pskillen

Context

Follow-on from #346 (site-wide guest / user / feeder / admin model). Implementation in #354 introduces:

  • Meshflow/common/access.pyAccessLevel 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:

  1. 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.
  2. 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.
  3. DRF viewsets use DjangoModelPermissions, DjangoObjectPermissions, or thin wrappers that check user.has_perm(...) instead of ad-hoc user_is_feeder() scattered across views.
  4. 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”.
  5. 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)

  1. Inventory — derive permission codenames from docs/permissions/README.md matrix and current DRF permission_classes.
  2. Define permissions — migration to create Permission rows; assign defaults to feeder and staff groups.
  3. 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.
  4. DRF — standardize on permission classes backed by Django perms; document guest exceptions.
  5. Tests — permission-matrix tests assert has_perm + HTTP status, not only AccessLevel.
  6. Docs — update docs/permissions/README.md with codename ↔ endpoint mapping.

Acceptance criteria

  • Custom permissions defined and listed in permissions docs
  • feeder (and admin) groups hold permissions via migrations/data migration, not only hard-coded group name checks
  • Representative viewsets use Django permission checks; no regression vs Guest access and system-wide permission model (remove constellation ACL) #346 matrix
  • Guest redaction behaviour unchanged (tests)
  • Management note for deploy (migrate + optional run_deploy_tasks if used)

Priority

Future / after #346 ships. Safe to schedule once #354 is merged and permissions docs are stable.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions