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.rs — classify_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
- 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.
- 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.
@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).
- 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).
- 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
References
Problem
The Django/DRF adapter misses several very common permission-declaration patterns, causing routes that are actually guarded to be classified as
unauthenticatedorunknown_or_dynamic. Two of these (settings-level defaults and per-@actionoverrides) 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 indocs/PARSERS_AND_ADAPTERS.md("Django / DRF — Not yet").Current behavior
permission_classes/authentication_classes, CBV mixins, and FBV decorators (crates/authmap-analysis/src/lib.rs—classify_drf_permission_classesand the Django class-attribute extraction around it).ViewSetActionstruct incrates/authmap-adapters/src/django.rs), but apermission_classes=[...]argument on the@action(...)decorator itself is not propagated as route evidence for that action.settings.pyis never scanned, soREST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"]is invisible; DRF views without explicitpermission_classesfall through to no-evidence classification even though the project default guards them.@method_decorator(login_required, name="dispatch")on CBVs is not recognized.from x import (a, b, c)imports are not resolved by the URLconf/handler symbol resolution, producingdjango_unresolved_handlerdiagnostics for perfectly ordinary files.class ProjectMixin(LoginRequiredMixin): ...thenclass MyView(ProjectMixin, View)) resolve only partially (resolve_viewset_classesindjango.rstargets viewset action resolution, not guard mixin chains).Proposed implementation
DEFAULT_PERMISSION_CLASSES(highest impact)settings.py(andsettings/*.pypackages) among parsed files; extract theREST_FRAMEWORKdict literal and itsDEFAULT_PERMISSION_CLASSES/DEFAULT_AUTHENTICATION_CLASSESentries via Tree-sitter.include_router(dependencies=...)propagates to child routes. At classification time, apply it to DRF views that have no explicitpermission_classes(explicit class attributes override the default — match DRF semantics).django_dynamic_settings_default) and lower-confidence evidence instead of asserting a guard.@actionpermission_classesoverrides@actiondecorator parsing feedingViewSetActionto capturepermission_classes=/authentication_classes=keyword arguments and attach them as evidence on the specific generated action route, overriding class-level evidence for that route only.@method_decoratoron CBVs@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).import_from_statementnodes whose name list spans multiple lines/parentheses (this is a Tree-sitter node-shape issue, not a heuristic issue).resolve_viewset_classes, depth-limited) to resolve guard mixins through local intermediate classes, emitting evidence with the chain recorded in the rationale.Acceptance criteria
DEFAULT_PERMISSION_CLASSESset 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")producesauthn_onlyevidence on all the CBV's routes.django_unresolved_handlerfor resolvable symbols.AUTHMAP_UPDATE_GOLDENSpath); full suite green.docs/PARSERS_AND_ADAPTERS.mdDjango Not yet list updated;docs/DIAGNOSTICS.mdupdated if new diagnostic codes added; CHANGELOG entry.References
docs/PARSERS_AND_ADAPTERS.md"Django / DRF" limitations paragraphcrates/authmap-adapters/src/django.rs(ViewSetAction,resolve_viewset_classes)crates/authmap-analysis/src/lib.rs(classify_drf_permission_classes)