1+ from collections .abc import Sequence
12from pathlib import Path
23
4+ from django .apps import AppConfig , apps
5+ from django .contrib import admin
6+ from django .contrib .auth .admin import UserAdmin
7+ from django .contrib .auth .models import User
38from django .core .checks import Warning
49
5- from maykin_common .checks import check_missing_init_files
10+ import pytest
11+
12+ from maykin_common .checks import (
13+ check_missing_init_files ,
14+ check_privilege_escalation_prevention_enabled ,
15+ )
616
717
818def test_check_missing_init_files (settings ):
@@ -18,3 +28,91 @@ def test_check_missing_init_files(settings):
1828 id = "maykin.W001" ,
1929 )
2030 ]
31+
32+
33+ @pytest .fixture
34+ def unregister_user_model ():
35+ _original = type (admin .site .get_model_admin (User ))
36+ admin .site .unregister (User )
37+ yield
38+ # pyright complains about invariance here:
39+ # Type parameter "_ModelT@ModelAdmin" is invariant, but "User" is not the same
40+ # as "Model"
41+ admin .site .register (User , _original ) # pyright: ignore[reportArgumentType]
42+
43+
44+ @pytest .fixture
45+ def revert_useradmin_patch (unregister_user_model ):
46+ """
47+ Restore the default, unpatched user admin.
48+ """
49+ admin .site .register (User , UserAdmin )
50+ yield
51+ admin .site .unregister (User )
52+
53+
54+ @pytest .mark .parametrize (
55+ "app_configs" ,
56+ [
57+ None ,
58+ [
59+ apps .get_app_config ("maykin_common" ),
60+ apps .get_app_config ("admin" ),
61+ apps .get_app_config ("testapp" ),
62+ ],
63+ ],
64+ )
65+ def test_privilege_escalation_check_skipped_if_admin_not_installed (
66+ revert_useradmin_patch ,
67+ app_configs : Sequence [AppConfig ] | None ,
68+ settings ,
69+ ):
70+ UPDATED_APPS = [* settings .INSTALLED_APPS ]
71+ UPDATED_APPS .remove ("django.contrib.admin" )
72+ settings .INSTALLED_APPS = UPDATED_APPS
73+ assert not apps .is_installed ("django.contrib.admin" )
74+
75+ errors = check_privilege_escalation_prevention_enabled (app_configs )
76+
77+ assert errors == []
78+
79+
80+ def test_privilege_escalation_check_skipped_if_not_requested (
81+ revert_useradmin_patch ,
82+ ):
83+ errors = check_privilege_escalation_prevention_enabled (
84+ [apps .get_app_config ("testapp" )]
85+ )
86+
87+ assert errors == []
88+
89+
90+ def test_privilege_escalation_check_warns_if_admin_not_patched (
91+ revert_useradmin_patch ,
92+ ):
93+ errors = check_privilege_escalation_prevention_enabled (None )
94+
95+ expected_warning = Warning (
96+ "Your UserAdmin does not use the 'PreventPrivilegeEscalationMixin' "
97+ "protections." ,
98+ hint = (
99+ "Use a custom UserAdmin that includes 'maykin_common.accounts.admin."
100+ "PreventPrivilegeEscalationMixin'."
101+ ),
102+ id = "maykin.W002" ,
103+ )
104+ assert expected_warning in errors
105+
106+
107+ def test_privilege_escalation_check_does_not_warn_if_admin_is_patched ():
108+ errors = check_privilege_escalation_prevention_enabled (None )
109+
110+ assert errors == []
111+
112+
113+ def test_privilege_escalation_check_does_not_warn_for_unregistered_user_model (
114+ unregister_user_model ,
115+ ):
116+ errors = check_privilege_escalation_prevention_enabled (None )
117+
118+ assert errors == []
0 commit comments