Skip to content

Django/DRF: close deferred permission-detection gaps (settings defaults, @action overrides, @method_decorator, multi-line imports) #107

Description

@bjcorder

Problem

The Django/DRF adapter misses several very common permission-declaration patterns, causing routes that are actually guarded to be classified as unauthenticated or unknown_or_dynamic. Two of these (settings-level defaults and per-@action overrides) are standard practice in most DRF deployments, so classification accuracy on real-world Django projects is materially understated. All four core items are already documented as deferred in docs/PARSERS_AND_ADAPTERS.md ("Django / DRF — Not yet").

Current behavior

  • Evidence extraction covers class-level permission_classes/authentication_classes, CBV mixins, and FBV decorators (crates/authmap-analysis/src/lib.rsclassify_drf_permission_classes and the Django class-attribute extraction around it).
  • ViewSet actions are modeled (ViewSetAction struct in crates/authmap-adapters/src/django.rs), but a permission_classes=[...] argument on the @action(...) decorator itself is not propagated as route evidence for that action.
  • settings.py is never scanned, so REST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"] is invisible; DRF views without explicit permission_classes fall through to no-evidence classification even though the project default guards them.
  • @method_decorator(login_required, name="dispatch") on CBVs is not recognized.
  • Multi-line parenthesized from x import (a, b, c) imports are not resolved by the URLconf/handler symbol resolution, producing django_unresolved_handler diagnostics for perfectly ordinary files.
  • Mixin resolution handles direct bases; aliased/nested chains (class ProjectMixin(LoginRequiredMixin): ... then class MyView(ProjectMixin, View)) resolve only partially (resolve_viewset_classes in django.rs targets viewset action resolution, not guard mixin chains).

Proposed implementation

  1. Settings-level DEFAULT_PERMISSION_CLASSES (highest impact)
    • During adapter discovery, locate settings.py (and settings/*.py packages) among parsed files; extract the REST_FRAMEWORK dict literal and its DEFAULT_PERMISSION_CLASSES / DEFAULT_AUTHENTICATION_CLASSES entries via Tree-sitter.
    • Emit this as app-scoped default evidence, analogous to how FastAPI include_router(dependencies=...) propagates to child routes. At classification time, apply it to DRF views that have no explicit permission_classes (explicit class attributes override the default — match DRF semantics).
    • If the settings value is built dynamically (env-driven, concatenation), emit a diagnostic (django_dynamic_settings_default) and lower-confidence evidence instead of asserting a guard.
  2. Per-@action permission_classes overrides
    • Extend the @action decorator parsing feeding ViewSetAction to capture permission_classes= / authentication_classes= keyword arguments and attach them as evidence on the specific generated action route, overriding class-level evidence for that route only.
  3. @method_decorator on CBVs
    • Recognize @method_decorator(<known FBV guard>, name="dispatch"|"get"|...) on class definitions and @method_decorator(<guard>) directly on CBV methods; reuse the existing FBV decorator classification (@login_required, @permission_required, @user_passes_test, @staff_member_required).
  4. Multi-line parenthesized imports
    • Fix the import-resolution walk to handle import_from_statement nodes whose name list spans multiple lines/parentheses (this is a Tree-sitter node-shape issue, not a heuristic issue).
  5. Deeper mixin chains
    • Reuse the existing class-index recursion (resolve_viewset_classes, depth-limited) to resolve guard mixins through local intermediate classes, emitting evidence with the chain recorded in the rationale.

Acceptance criteria

  • DRF project fixture with DEFAULT_PERMISSION_CLASSES set and views without explicit permissions classifies those routes as guarded (with explicit class attributes still winning).
  • @action(detail=..., permission_classes=[...]) produces per-action evidence overriding the class default.
  • @method_decorator(login_required, name="dispatch") produces authn_only evidence on all the CBV's routes.
  • Multi-line parenthesized handler imports no longer emit django_unresolved_handler for resolvable symbols.
  • Aliased mixin chain fixture classifies as guarded.
  • Unit tests per pattern + golden fixture updates (AUTHMAP_UPDATE_GOLDENS path); full suite green.
  • docs/PARSERS_AND_ADAPTERS.md Django Not yet list updated; docs/DIAGNOSTICS.md updated if new diagnostic codes added; CHANGELOG entry.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:adapterFramework adapter workdetectionAnalyzer detection behavior or pattern coverageenhancementNew feature or requestframework:djangoDjango and Django REST Framework supportrustRust implementation work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions