Skip to content

Test#2

Closed
Maffooch wants to merge 2 commits into
devfrom
tailwind
Closed

Test#2
Maffooch wants to merge 2 commits into
devfrom
tailwind

Conversation

@Maffooch

@Maffooch Maffooch commented May 9, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Migrate UI from Bootstrap to Tailwind CSS with classic template library and remove group/SSO functionality

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Complete redesign of the UI from Bootstrap/SB Admin 2 to modern Tailwind CSS with Alpine.js and
  htmx
• Migrated base template (base.html) from Bootstrap to Tailwind with sticky topbar, collapsible
  sidebar, and native HTML dialogs
• Created comprehensive classic UI templates in dojo/templates_classic/ directory including base
  layout, engagement view, test view, finding view, metrics dashboard, and product pages
• Added new templates for error pages, template management, and webhook notifications
• Removed jQuery UI, Bootstrap Select, and MetisMenu dependencies; replaced with vanilla JavaScript
  and Alpine.js
• Removed group management functionality and SSO-related code (views, middleware, context
  processors, SAML/OIDC configurations)
• Updated form styling by removing form-horizontal class from profile and user forms
• Implemented extensive JavaScript functionality for keyboard shortcuts, JIRA integration, and
  interactive features across multiple views
Diagram
flowchart LR
  A["Bootstrap/SB Admin 2<br/>jQuery UI"] -->|"Redesign"| B["Tailwind CSS<br/>Alpine.js + htmx"]
  C["Single base.html"] -->|"Separate"| D["Modern base.html<br/>+ Classic templates"]
  E["Group Management<br/>SSO Features"] -->|"Remove"| F["Simplified Auth"]
  B --> G["New UI"]
  D --> G
  F --> G
Loading

Grey Divider

File Changes

1. dojo/templates/base.html ✨ Enhancement +495/-757

Complete redesign from Bootstrap to Tailwind CSS layout

• Replaced Bootstrap/SB Admin 2 layout with modern Tailwind CSS-based sidebar and topbar navigation
• Removed jQuery UI, Bootstrap Select, MetisMenu, and SB Admin 2 dependencies; added htmx and
 Alpine.js
• Converted fixed navbar to sticky topbar with search, alerts dropdown, and user menu using
 Alpine.js
• Restructured sidebar navigation with collapsible menu items using Alpine.js instead of jQuery
• Updated CSS imports to use Tailwind output and custom DataTables styling; removed Bootstrap CSS
• Replaced Bootstrap modals with native HTML <dialog> element for session timeout
• Updated footer styling to use Tailwind utilities
• Converted inline JavaScript from jQuery to vanilla JavaScript for session notifications and form
 handling

dojo/templates/base.html


2. dojo/templates_classic/dojo/view_eng.html ✨ Enhancement +1019/-0

New engagement view template with classic Bootstrap styling

• New file containing engagement view template with Bootstrap panel-based layout
• Displays engagement details, tests, risk acceptances, and additional features (checklists,
 questionnaires, notes, files)
• Includes dropdown menus for engagement actions and test management
• Sidebar panel shows engagement metadata and CI/CD details
• Uses jQuery for keyboard shortcuts and interactive features

dojo/templates_classic/dojo/view_eng.html


3. dojo/templates/dojo/profile.html Formatting +1/-58

Minor form styling update in profile template

• Removed form-horizontal class from form element to update styling approach

dojo/templates/dojo/profile.html


View more (110)
4. dojo/templates_classic/google_sheet_error.html ✨ Enhancement +9/-0

New Google Sheets error page template

• New error page template extending base.html
• Displays error message in heading format

dojo/templates_classic/google_sheet_error.html


5. dojo/templates_classic/dojo/view_test.html ✨ Enhancement +1867/-0

Complete test view template with findings management interface

• Added comprehensive Django template for test view with full HTML structure extending base.html
• Implemented test header section with engagement details, environment, dates, and dropdown menu for
 test actions
• Added findings table with filtering, bulk edit capabilities, severity-based selection, and JIRA
 integration
• Included import history section, finding groups panel, file management, and comments with
 extensive JavaScript functionality

dojo/templates_classic/dojo/view_test.html


6. dojo/templates_classic/dojo/metrics.html ✨ Enhancement +965/-0

Metrics dashboard with charts and detailed findings breakdown

• Created comprehensive metrics dashboard template extending base.html with tabbed interface
• Implemented multiple chart sections for bug trends (monthly/weekly), health gauges for critical
 products, and severity breakdowns
• Added detailed metrics tables for opened, accepted, and closed findings with product-level
 breakdowns
• Included accessibility features with sr-only sections and ARIA labels for charts and gauges

dojo/templates_classic/dojo/metrics.html


7. dojo/templates_classic/dojo/add_template.html ✨ Enhancement +132/-0

Finding template creation and editing interface

• Added template creation/editing form with markdown editor (EasyMDE) integration
• Implemented form validation for required fields and keyboard shortcut (Ctrl+S) for saving
• Included delete template functionality with permission checks
• Added styling for chosen select dropdowns and editor toolbar

dojo/templates_classic/dojo/add_template.html


8. dojo/templates_classic/login/forgot_username_subject.html ✨ Enhancement +3/-0

Email subject template for username recovery

• Created email subject template for username recovery functionality
• Uses Django i18n for internationalization support

dojo/templates_classic/login/forgot_username_subject.html


9. dojo/templates_classic/dojo/view_finding.html ✨ Enhancement +1573/-0

New classic template for finding detail view page

• Added comprehensive finding view template with 1573 lines of HTML/Django template code
• Includes finding details display with severity, status, dates, and metadata in a table format
• Implements dropdown menu with actions like edit, copy, verify, close, and risk acceptance
• Contains sections for description, mitigation, impact, references, and request/response pairs
• Integrates JavaScript for keyboard shortcuts (e, p, n, v, c), JIRA integration, and bulk endpoint
 operations

dojo/templates_classic/dojo/view_finding.html


10. dojo/templates_classic/base.html ✨ Enhancement +1254/-0

New classic base template with navigation structure

• Added 1254-line base template for classic UI layout with navigation and structure
• Includes responsive navbar with search, alerts, and user menu dropdown
• Implements comprehensive sidebar navigation with menu items for dashboard, products, engagements,
 findings, and configuration
• Contains product tab bar with dynamic tabs for overview, components, metrics, engagements,
 findings, endpoints, and settings
• Integrates footer, session timeout modal, and JavaScript for alerts and session management

dojo/templates_classic/base.html


11. dojo/templates/dojo/add_user.html Formatting +1/-5

Remove horizontal form layout from user form

• Removed form-horizontal CSS class from form element
• Changed form styling from Bootstrap horizontal layout to default layout

dojo/templates/dojo/add_user.html


12. dojo/templates_classic/notifications/webhooks/product_type_added.tpl ✨ Enhancement +2/-0

New webhook notification template for product type

• Added new webhook notification template for product type added events
• Includes base template and product type specific template subtemplates

dojo/templates_classic/notifications/webhooks/product_type_added.tpl


13. Dockerfile.nginx-alpine Additional files +2/-0

...

Dockerfile.nginx-alpine


14. components/node_modules/.gitkeep Additional files +0/-0

...

components/node_modules/.gitkeep


15. components/package.json Additional files +17/-1

...

components/package.json


16. components/tailwind.css Additional files +1245/-0

...

components/tailwind.css


17. docs/content/admin/sso/OS__auth0.md Additional files +0/-36

...

docs/content/admin/sso/OS__auth0.md


18. docs/content/admin/sso/OS__azure_ad.md Additional files +0/-72

...

docs/content/admin/sso/OS__azure_ad.md


19. docs/content/admin/sso/OS__github_enterprise.md Additional files +0/-35

...

docs/content/admin/sso/OS__github_enterprise.md


20. docs/content/admin/sso/OS__gitlab.md Additional files +0/-45

...

docs/content/admin/sso/OS__gitlab.md


21. docs/content/admin/sso/OS__google.md Additional files +0/-59

...

docs/content/admin/sso/OS__google.md


22. docs/content/admin/sso/OS__keycloak.md Additional files +0/-74

...

docs/content/admin/sso/OS__keycloak.md


23. docs/content/admin/sso/OS__oidc.md Additional files +0/-40

...

docs/content/admin/sso/OS__oidc.md


24. docs/content/admin/sso/OS__okta.md Additional files +0/-46

...

docs/content/admin/sso/OS__okta.md


25. docs/content/admin/sso/OS__remote_user.md Additional files +0/-37

...

docs/content/admin/sso/OS__remote_user.md


26. docs/content/admin/sso/OS__saml.md Additional files +0/-80

...

docs/content/admin/sso/OS__saml.md


27. docs/content/admin/sso/PRO__auth0.md Additional files +1/-1

...

docs/content/admin/sso/PRO__auth0.md


28. docs/content/admin/sso/PRO__azure_ad.md Additional files +1/-1

...

docs/content/admin/sso/PRO__azure_ad.md


29. docs/content/admin/sso/PRO__github_enterprise.md Additional files +1/-1

...

docs/content/admin/sso/PRO__github_enterprise.md


30. docs/content/admin/sso/PRO__gitlab.md Additional files +1/-1

...

docs/content/admin/sso/PRO__gitlab.md


31. docs/content/admin/sso/PRO__google.md Additional files +1/-1

...

docs/content/admin/sso/PRO__google.md


32. docs/content/admin/sso/PRO__keycloak.md Additional files +1/-1

...

docs/content/admin/sso/PRO__keycloak.md


33. docs/content/admin/sso/PRO__oidc.md Additional files +1/-1

...

docs/content/admin/sso/PRO__oidc.md


34. docs/content/admin/sso/PRO__okta.md Additional files +1/-1

...

docs/content/admin/sso/PRO__okta.md


35. docs/content/admin/sso/PRO__saml.md Additional files +1/-1

...

docs/content/admin/sso/PRO__saml.md


36. docs/content/admin/sso/_index.md Additional files +24/-16

...

docs/content/admin/sso/_index.md


37. docs/content/admin/user_management/OS__authorized_users.md Additional files +60/-0

...

docs/content/admin/user_management/OS__authorized_users.md


38. docs/content/admin/user_management/_index.md Additional files +27/-2

...

docs/content/admin/user_management/_index.md


39. docs/content/admin/user_management/about_perms_and_roles.md Additional files +5/-1

...

docs/content/admin/user_management/about_perms_and_roles.md


40. docs/content/admin/user_management/configure_sso.md Additional files +0/-750

...

docs/content/admin/user_management/configure_sso.md


41. docs/content/admin/user_management/create_user_group.md Additional files +5/-1

...

docs/content/admin/user_management/create_user_group.md


42. docs/content/admin/user_management/set_user_permissions.md Additional files +4/-1

...

docs/content/admin/user_management/set_user_permissions.md


43. docs/content/admin/user_management/user_permission_chart.md Additional files +5/-1

...

docs/content/admin/user_management/user_permission_chart.md


44. docs/content/automation/api/api-v2-docs.md Additional files +1/-1

...

docs/content/automation/api/api-v2-docs.md


45. docs/content/releases/os_upgrading/2.59.md Additional files +49/-1

...

docs/content/releases/os_upgrading/2.59.md


46. docs/content/releases/pro/changelog.md Additional files +7/-0

...

docs/content/releases/pro/changelog.md


47. dojo/announcement/views.py Additional files +0/-4

...

dojo/announcement/views.py


48. dojo/api_v2/permissions.py Additional files +9/-1254

...

dojo/api_v2/permissions.py


49. dojo/api_v2/serializers.py Additional files +10/-395

...

dojo/api_v2/serializers.py


50. dojo/api_v2/views.py Additional files +28/-261

...

dojo/api_v2/views.py


51. dojo/asset/api/filters.py Additional files +0/-18

...

dojo/asset/api/filters.py


52. dojo/asset/api/serializers.py Additional files +1/-92

...

dojo/asset/api/serializers.py


53. dojo/asset/api/urls.py Additional files +2/-4

...

dojo/asset/api/urls.py


54. dojo/asset/api/views.py Additional files +4/-66

...

dojo/asset/api/views.py


55. dojo/asset/urls.py Additional files +6/-54

...

dojo/asset/urls.py


56. dojo/auditlog/filters.py Additional files +2/-3

...

dojo/auditlog/filters.py


57. dojo/auditlog/ui/views.py Additional files +8/-9

...

dojo/auditlog/ui/views.py


58. dojo/authorization/MIGRATION_REHEARSAL.md Additional files +247/-0

...

dojo/authorization/MIGRATION_REHEARSAL.md


59. dojo/authorization/__init__.py Additional files +11/-0

...

dojo/authorization/init.py


60. dojo/authorization/api_permissions.py Additional files +1103/-0

...

dojo/authorization/api_permissions.py


61. dojo/authorization/authorization.py Additional files +126/-328

...

dojo/authorization/authorization.py


62. dojo/authorization/middleware.py Additional files +50/-0

...

dojo/authorization/middleware.py


63. dojo/authorization/models.py Additional files +111/-0

...

dojo/authorization/models.py


64. dojo/authorization/query_filters.py Additional files +9/-0

...

dojo/authorization/query_filters.py


65. dojo/authorization/query_registrations.py Additional files +404/-0

...

dojo/authorization/query_registrations.py


66. dojo/authorization/roles_permissions.py Additional files +154/-278

...

dojo/authorization/roles_permissions.py


67. dojo/authorization/template_filters.py Additional files +47/-0

...

dojo/authorization/template_filters.py


68. dojo/authorization/url_permissions.py Additional files +295/-0

...

dojo/authorization/url_permissions.py


69. dojo/banner/views.py Additional files +0/-4

...

dojo/banner/views.py


70. dojo/benchmark/views.py Additional files +0/-6

...

dojo/benchmark/views.py


71. dojo/components/views.py Additional files +1/-2

...

dojo/components/views.py


72. dojo/context_processors.py Additional files +26/-1

...

dojo/context_processors.py


73. dojo/db_migrations/0265_usercontactinfo_ui_use_tailwind.py Additional files +18/-0

...

dojo/db_migrations/0265_usercontactinfo_ui_use_tailwind.py


74. dojo/db_migrations/0266_reintroduce_authorized_users.py Additional files +23/-0

...

dojo/db_migrations/0266_reintroduce_authorized_users.py


75. dojo/db_migrations/0267_backfill_authorized_users.py Additional files +132/-0

...

dojo/db_migrations/0267_backfill_authorized_users.py


76. dojo/db_migrations/0268_release_rbac_state.py Additional files +88/-0

...

dojo/db_migrations/0268_release_rbac_state.py


77. dojo/development_environment/views.py Additional files +0/-3

...

dojo/development_environment/views.py


78. dojo/endpoint/queries.py Additional files +20/-167

...

dojo/endpoint/queries.py


79. dojo/endpoint/views.py Additional files +7/-19

...

dojo/endpoint/views.py


80. dojo/engagement/queries.py Additional files +9/-41

...

dojo/engagement/queries.py


81. dojo/engagement/views.py Additional files +13/-33

...

dojo/engagement/views.py


82. dojo/filters.py Additional files +35/-45

...

dojo/filters.py


83. dojo/finding/queries.py Additional files +22/-165

...

dojo/finding/queries.py


84. dojo/finding/views.py Additional files +19/-52

...

dojo/finding/views.py


85. dojo/finding_group/queries.py Additional files +13/-84

...

dojo/finding_group/queries.py


86. dojo/finding_group/views.py Additional files +5/-12

...

dojo/finding_group/views.py


87. dojo/fixtures/dojo_testdata.json Additional files +1/-1

...

dojo/fixtures/dojo_testdata.json


88. dojo/forms.py Additional files +74/-310

...

dojo/forms.py


89. dojo/github/templates/dojo/delete_github.html Additional files +1/-1

...

dojo/github/templates/dojo/delete_github.html


90. dojo/github/templates/dojo/new_github.html Additional files +1/-1

...

dojo/github/templates/dojo/new_github.html


91. dojo/github/ui/views.py Additional files +0/-4

...

dojo/github/ui/views.py


92. dojo/group/__init__.py Additional files +0/-0

...

dojo/group/init.py


93. dojo/group/queries.py Additional files +0/-69

...

dojo/group/queries.py


94. dojo/group/urls.py Additional files +0/-17

...

dojo/group/urls.py


95. dojo/group/utils.py Additional files +0/-68

...

dojo/group/utils.py


96. dojo/group/views.py Additional files +0/-592

...

dojo/group/views.py


97. dojo/home/views.py Additional files +2/-3

...

dojo/home/views.py


98. dojo/importers/auto_create_context.py Additional files +7/-23

...

dojo/importers/auto_create_context.py


99. dojo/jira/api/views.py Additional files +3/-4

...

dojo/jira/api/views.py


100. dojo/jira/queries.py Additional files +13/-103

...

dojo/jira/queries.py


101. dojo/location/api/endpoint_compat.py Additional files +6/-7

...

dojo/location/api/endpoint_compat.py


102. dojo/location/api/permissions.py Additional files +0/-46

...

dojo/location/api/permissions.py


103. dojo/location/api/views.py Additional files +7/-8

...

dojo/location/api/views.py


104. dojo/location/queries.py Additional files +17/-127

...

dojo/location/queries.py


105. dojo/management/commands/migrate_staff_users.py Additional files +0/-94

...

dojo/management/commands/migrate_staff_users.py


106. dojo/management/commands/preview_legacy_authorization_migration.py Additional files +220/-0

...

dojo/management/commands/preview_legacy_authorization_migration.py


107. dojo/metrics/utils.py Additional files +4/-5

...

dojo/metrics/utils.py


108. dojo/metrics/views.py Additional files +6/-7

...

dojo/metrics/views.py


109. dojo/models.py Additional files +14/-48

...

dojo/models.py


110. dojo/note_type/views.py Additional files +0/-6

...

dojo/note_type/views.py


111. dojo/notes/views.py Additional files +6/-7

...

dojo/notes/views.py


112. dojo/notifications/helper.py Additional files +2/-3

...

dojo/notifications/helper.py


113. Additional files not shown Additional files +0/-0

...

Additional files not shown


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (3)

Grey Divider


Action required

1. Role.Meta sets app_label 📘 Rule violation ≡ Correctness
Description
Extracted models in dojo/authorization/models.py explicitly set Meta.app_label, which violates
the extraction rule and can cause Django model discovery/migration inconsistencies. This should rely
on the default dojo app inheritance instead of forcing app_label.
Code

dojo/authorization/models.py[R24-27]

+    class Meta:
+        app_label = "dojo"
+        db_table = "dojo_role"
+        managed = False
Evidence
PR Compliance ID 4 forbids explicitly setting Meta.app_label on extracted models. The newly added
Role model (and others in the same file) sets app_label = "dojo" in Meta.

CLAUDE.md
dojo/authorization/models.py[24-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Extracted models in `dojo/authorization/models.py` explicitly set `Meta.app_label`, which is disallowed by the extraction compliance rules.

## Issue Context
Django should infer the `dojo` app label automatically for models inside the `dojo` app; forcing `app_label` can introduce discovery/migration issues.

## Fix Focus Areas
- dojo/authorization/models.py[24-27]
- dojo/authorization/models.py[45-48]
- dojo/authorization/models.py[64-67]
- dojo/authorization/models.py[75-78]
- dojo/authorization/models.py[86-89]
- dojo/authorization/models.py[97-100]
- dojo/authorization/models.py[108-111]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. dojo.models registers auth models 📘 Rule violation ⚙ Maintainability
Description
Admin registrations for extracted authorization models are still being maintained from
dojo/models.py, which violates the requirement to keep module admin registrations in
dojo/{module}/admin.py. This increases the risk of double-registration and breaks the intended
module boundaries.
Code

dojo/models.py[R4521-4529]

+from dojo.authorization.models import (  # noqa: E402
+    Dojo_Group_Member,
+    Global_Role,
+    Product_Group,
+    Product_Member,
+    Product_Type_Group,
+    Product_Type_Member,
+    Role,
+)
Evidence
PR Compliance ID 7 requires admin registrations to live in dojo/{module}/admin.py and be removed
from dojo/models.py. The diff adds an import of authorization models into dojo/models.py
immediately before admin.site.register(...), indicating the registrations are still being done
from the monolithic file.

CLAUDE.md
dojo/models.py[4521-4529]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Authorization model admin registrations are still effectively anchored in `dojo/models.py` via a new import block, rather than being located in `dojo/authorization/admin.py`.

## Issue Context
Per the modular extraction rules, each module must own its Django admin registrations to avoid double-registration and to keep a clean module boundary.

## Fix Focus Areas
- dojo/models.py[4521-4533]
- dojo/authorization/__init__.py[1-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. authorization.__init__ lacks admin import 📘 Rule violation ☼ Reliability
Description
dojo/authorization/__init__.py does not import dojo.authorization.admin, breaking the required
import chain used for model discovery in extracted modules. This can prevent Django from
consistently discovering module models/admin registrations.
Code

dojo/authorization/init.py[R1-11]

+# Import query_registrations to trigger RBAC filter registration at startup
+from dojo.authorization import query_registrations  # noqa: F401
+from dojo.authorization.authorization import (  # noqa: F401
+    user_has_configuration_permission,
+    user_has_global_permission,
+    user_has_global_permission_or_403,
+    user_has_permission,
+    user_has_permission_or_403,
+    user_is_superuser_or_global_owner,
+)
+from dojo.authorization.roles_permissions import Permissions, Roles  # noqa: F401
Evidence
PR Compliance ID 8 requires each extracted module’s __init__.py to import its admin.py (as done
in the canonical dojo/url/ module). The new dojo/authorization/__init__.py only imports
query_registrations and authorization symbols and contains no import dojo.authorization.admin
line.

CLAUDE.md
dojo/authorization/init.py[1-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`dojo/authorization/__init__.py` does not import the module’s `admin.py`, which breaks the expected discovery/import chain.

## Issue Context
The canonical pattern (e.g., `dojo/url/__init__.py`) imports `dojo.{module}.admin` to ensure model/admin discovery.

## Fix Focus Areas
- dojo/authorization/__init__.py[1-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
4. Endpoint UI auth bypass 🐞 Bug ⛨ Security
Description
When V3 locations are enabled, endpoint UI URL names (e.g., view_endpoint/delete_endpoint) resolve
with kwargs like location_id/product_id, but URL_PERMISSIONS expects eid/pid and
AuthorizationMiddleware skips the check when the kwarg is missing, leaving these views effectively
without object authorization. This can expose findings via view_endpoint and allow destructive
actions like delete_endpoint for any authenticated user.
Code

dojo/authorization/url_permissions.py[R137-162]

+    "view_endpoint": [("object", Endpoint, "view", "eid")],
+    "view_endpoint_host": [("object", Endpoint, "view", "eid")],
+    "edit_endpoint": [("object", Endpoint, "edit", "eid")],
+    "add_endpoint": [("object", Product, "add", "pid")],
+    "delete_endpoint": [("object", Endpoint, "delete", "eid")],
+    "add_endpoint_meta_data": [("object", Endpoint, "edit", "eid")],
+    "edit_endpoint_meta_data": [("object", Endpoint, "edit", "eid")],
+    "endpoints_status_bulk": [("object", Finding, "edit", "fid")],
+    "import_endpoint_meta": [("object", Product, "edit", "pid")],
+    "endpoint_report": [("object", Endpoint, "view", "eid")],
+    "endpoint_host_report": [("object", Endpoint, "view", "eid")],
+
+    # -----------------------------------------------------------------------
+    # URL / Location UI (dojo/url/ui/views.py  ->  dojo/url/ui/urls.py)
+    #
+    # These URL names overlap with the endpoint module above. Since Django
+    # uses the last-registered pattern for reverse() and the middleware reads
+    # view_kwargs from the matched pattern, the kwarg names from the actually
+    # matched URL are used. The endpoint entries above use "eid"; if the
+    # url/ui pattern matched instead, "location_id" will be present and the
+    # middleware will fall back (skip checks where the kwarg is missing).
+    #
+    # Unique URL names from url/ui:
+    # -----------------------------------------------------------------------
+    "add_endpoint_to_product": [("object", Product, "add", "product_id")],
+    "add_endpoint_to_finding": [("object", Product, "add", "finding_id")],
Evidence
URL_PERMISSIONS defines endpoint checks using the legacy kwarg names (eid/pid) and explicitly
documents that when the url/ui pattern matches, location_id will be present and the middleware will
"fall back" by skipping checks; AuthorizationMiddleware indeed continues when lookup_value is None.
With V3_FEATURE_LOCATIONS enabled, Django includes dojo/url/ui/urls.py routes (which use
location_id/product_id for these same URL names), and dojo/url/ui/views.py no longer has per-view
authorization decorators and performs sensitive operations (e.g., Location lookup + delete) without
calling user_has_permission_or_403 for the target Location/Product/Finding.

dojo/authorization/url_permissions.py[134-163]
dojo/authorization/middleware.py[19-48]
dojo/urls.py[206-210]
dojo/url/ui/urls.py[24-40]
dojo/url/ui/views.py[46-110]
dojo/url/ui/views.py[325-377]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`AuthorizationMiddleware` + `URL_PERMISSIONS` do not correctly authorize endpoint/location UI routes when `V3_FEATURE_LOCATIONS` is enabled. The middleware silently skips object checks when the expected kwarg is absent, and `URL_PERMISSIONS` uses legacy kwarg names (`eid`/`pid`) for URL names that (under V3) resolve with `location_id`/`product_id`, leaving sensitive views (including delete) without object authorization.

### Issue Context
- Under `V3_FEATURE_LOCATIONS`, `dojo/urls.py` includes `dojo/url/ui/urls.py` instead of `dojo/endpoint/urls.py`.
- `dojo/url/ui/urls.py` uses `location_id` and `product_id` for URL names like `view_endpoint`, `delete_endpoint`, `add_endpoint_meta_data`, etc.
- `dojo/url/ui/views.py` does not enforce object authorization itself for many of these operations.

### Fix Focus Areas
- dojo/authorization/middleware.py[19-48]
- dojo/authorization/url_permissions.py[134-163]
- dojo/url/ui/views.py[46-110]
- dojo/url/ui/views.py[325-410]
- dojo/url/ui/urls.py[24-52]
- dojo/urls.py[206-210]

### Expected fix
- Make object checks **fail closed** when a configured check cannot be evaluated (missing kwarg), OR support `arg_name` being a list/tuple and use the first kwarg present.
- Update `URL_PERMISSIONS` endpoint/location entries to correctly authorize V3 routes (e.g., use `Location` + `location_id` for `view_endpoint`/`delete_endpoint`/reports/meta-data, and `Product` + `product_id` for the legacy `add_endpoint` duplicate route).
- Add explicit `user_has_permission_or_403(...)` calls in `dojo/url/ui/views.py` for operations that mutate or disclose data (defense-in-depth), so misconfiguration in `URL_PERMISSIONS` cannot become an authorization bypass.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Wrong model permission lookup 🐞 Bug ≡ Correctness
Description
URL_PERMISSIONS defines add_endpoint_to_finding as a Product lookup by finding_id, so
AuthorizationMiddleware authorizes against the wrong object (or returns 404) and does not reflect
the Finding/Product actually being modified. This can break the route or allow/deny access
incorrectly depending on ID collisions.
Code

dojo/authorization/url_permissions.py[R161-162]

+    "add_endpoint_to_product": [("object", Product, "add", "product_id")],
+    "add_endpoint_to_finding": [("object", Product, "add", "finding_id")],
Evidence
The route is defined with kwarg finding_id (a Finding PK), and the view fetches Finding by that PK;
however URL_PERMISSIONS instructs the middleware to fetch Product(pk=finding_id), which is a
different table and unrelated to the Finding being updated. Middleware uses get_object_or_404(model,
pk=lookup_value) for object checks, so this mismatch is directly actionable and will either 404 or
validate permissions against an arbitrary Product with the same numeric ID.

dojo/authorization/url_permissions.py[161-162]
dojo/authorization/middleware.py[42-48]
dojo/url/ui/urls.py[32-36]
dojo/url/ui/views.py[346-359]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`URL_PERMISSIONS` uses the wrong model for the `add_endpoint_to_finding` URL name: it looks up a `Product` by `finding_id`, but `finding_id` is a `Finding` primary key.

### Issue Context
`AuthorizationMiddleware` performs object checks by doing `get_object_or_404(model, pk=view_kwargs[arg_name])` and then calls `user_has_permission_or_403` on that object. Using the wrong model means the permission check is performed on the wrong object (or becomes a 404).

### Fix Focus Areas
- dojo/authorization/url_permissions.py[159-163]
- dojo/authorization/middleware.py[42-48]
- dojo/url/ui/urls.py[32-36]
- dojo/url/ui/views.py[346-365]

### Expected fix
- Change the `add_endpoint_to_finding` entry to authorize against `Finding` with kwarg `finding_id` (since `user_has_permission` can derive the Product scope from a Finding), or introduce a dedicated check type that can resolve `Finding -> product` and then enforce `add` on the derived Product.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Unknown perms default to view 🐞 Bug ⚙ Maintainability
Description
permission_to_action() returns Action.View for unrecognized permission strings, so typos or
unexpected permission values silently degrade to a weaker authorization check instead of failing
closed. This can under-enforce authorization in any call path that passes a
non-Action/non-Permissions value.
Code

dojo/authorization/roles_permissions.py[R337-373]

+def permission_to_action(permission):
+    """
+    Map a fine-grained Permissions enum member, action string, or legacy
+    enum-name string (e.g. "Product_Edit") to an Action.
+
+    The suffix-based mapping captures every Permissions name (which all
+    follow the ``<Noun>_<Verb>`` convention); the noun is irrelevant
+    because legacy authorization is not noun-aware (the object passed at
+    check time determines the membership scope).
+    """
+    if isinstance(permission, Action):
+        return permission
+
+    if isinstance(permission, str):
+        try:
+            return Action(permission)
+        except ValueError:
+            name = permission
+    else:
+        name = getattr(permission, "name", "") or str(permission)
+
+    if name == "Risk_Acceptance":
+        return Action.Edit
+    if name == "Import_Scan_Result":
+        return Action.Import
+    if name.endswith(("_View", "_View_History")):
+        return Action.View
+    if name.endswith(("_Edit", "_Configure_Notifications")):
+        return Action.Edit
+    if name.endswith("_Delete"):
+        return Action.Delete
+    if name.endswith(("_Add_Product", "_Add")):
+        return Action.Add
+    if "_Manage_" in name or name.endswith("_Add_Owner"):
+        return Action.StaffOnly
+
+    return Action.View
Evidence
permission_to_action attempts to coerce strings into Action, but if coercion and suffix matching
fail it returns Action.View; user_has_permission relies on permission_to_action and, for
Action.View, proceeds to membership/staff-based authorization rather than denying. This creates a
fail-open behavior for invalid permission identifiers.

dojo/authorization/roles_permissions.py[337-373]
dojo/authorization/authorization.py[73-109]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`permission_to_action()` defaults unknown/invalid permission identifiers to `Action.View`, which is fail-open and can silently weaken authorization if a caller passes an unexpected string.

### Issue Context
`user_has_permission()` depends on `permission_to_action()` and will authorize based on the mapped Action. Returning `View` for an invalid permission is risky because it can allow access when the caller intended a stricter permission.

### Fix Focus Areas
- dojo/authorization/roles_permissions.py[337-373]
- dojo/authorization/authorization.py[73-109]

### Expected fix
- Prefer failing closed for unknown permission values (e.g., raise, or map to `Action.SuperuserOnly` / a deny action).
- If backward compatibility is needed, explicitly support common Django verbs like `"change" -> Action.Edit` rather than defaulting to View.
- Consider logging when an unknown permission identifier is encountered to surface misconfigurations early.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +24 to +27
class Meta:
app_label = "dojo"
db_table = "dojo_role"
managed = False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. role.meta sets app_label 📘 Rule violation ≡ Correctness

Extracted models in dojo/authorization/models.py explicitly set Meta.app_label, which violates
the extraction rule and can cause Django model discovery/migration inconsistencies. This should rely
on the default dojo app inheritance instead of forcing app_label.
Agent Prompt
## Issue description
Extracted models in `dojo/authorization/models.py` explicitly set `Meta.app_label`, which is disallowed by the extraction compliance rules.

## Issue Context
Django should infer the `dojo` app label automatically for models inside the `dojo` app; forcing `app_label` can introduce discovery/migration issues.

## Fix Focus Areas
- dojo/authorization/models.py[24-27]
- dojo/authorization/models.py[45-48]
- dojo/authorization/models.py[64-67]
- dojo/authorization/models.py[75-78]
- dojo/authorization/models.py[86-89]
- dojo/authorization/models.py[97-100]
- dojo/authorization/models.py[108-111]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread dojo/models.py
Comment on lines +4521 to +4529
from dojo.authorization.models import ( # noqa: E402
Dojo_Group_Member,
Global_Role,
Product_Group,
Product_Member,
Product_Type_Group,
Product_Type_Member,
Role,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. dojo.models registers auth models 📘 Rule violation ⚙ Maintainability

Admin registrations for extracted authorization models are still being maintained from
dojo/models.py, which violates the requirement to keep module admin registrations in
dojo/{module}/admin.py. This increases the risk of double-registration and breaks the intended
module boundaries.
Agent Prompt
## Issue description
Authorization model admin registrations are still effectively anchored in `dojo/models.py` via a new import block, rather than being located in `dojo/authorization/admin.py`.

## Issue Context
Per the modular extraction rules, each module must own its Django admin registrations to avoid double-registration and to keep a clean module boundary.

## Fix Focus Areas
- dojo/models.py[4521-4533]
- dojo/authorization/__init__.py[1-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread dojo/authorization/__init__.py Outdated
Comment on lines +1 to +11
# Import query_registrations to trigger RBAC filter registration at startup
from dojo.authorization import query_registrations # noqa: F401
from dojo.authorization.authorization import ( # noqa: F401
user_has_configuration_permission,
user_has_global_permission,
user_has_global_permission_or_403,
user_has_permission,
user_has_permission_or_403,
user_is_superuser_or_global_owner,
)
from dojo.authorization.roles_permissions import Permissions, Roles # noqa: F401

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. authorization.init lacks admin import 📘 Rule violation ☼ Reliability

dojo/authorization/__init__.py does not import dojo.authorization.admin, breaking the required
import chain used for model discovery in extracted modules. This can prevent Django from
consistently discovering module models/admin registrations.
Agent Prompt
## Issue description
`dojo/authorization/__init__.py` does not import the module’s `admin.py`, which breaks the expected discovery/import chain.

## Issue Context
The canonical pattern (e.g., `dojo/url/__init__.py`) imports `dojo.{module}.admin` to ensure model/admin discovery.

## Fix Focus Areas
- dojo/authorization/__init__.py[1-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +137 to +162
"view_endpoint": [("object", Endpoint, "view", "eid")],
"view_endpoint_host": [("object", Endpoint, "view", "eid")],
"edit_endpoint": [("object", Endpoint, "edit", "eid")],
"add_endpoint": [("object", Product, "add", "pid")],
"delete_endpoint": [("object", Endpoint, "delete", "eid")],
"add_endpoint_meta_data": [("object", Endpoint, "edit", "eid")],
"edit_endpoint_meta_data": [("object", Endpoint, "edit", "eid")],
"endpoints_status_bulk": [("object", Finding, "edit", "fid")],
"import_endpoint_meta": [("object", Product, "edit", "pid")],
"endpoint_report": [("object", Endpoint, "view", "eid")],
"endpoint_host_report": [("object", Endpoint, "view", "eid")],

# -----------------------------------------------------------------------
# URL / Location UI (dojo/url/ui/views.py -> dojo/url/ui/urls.py)
#
# These URL names overlap with the endpoint module above. Since Django
# uses the last-registered pattern for reverse() and the middleware reads
# view_kwargs from the matched pattern, the kwarg names from the actually
# matched URL are used. The endpoint entries above use "eid"; if the
# url/ui pattern matched instead, "location_id" will be present and the
# middleware will fall back (skip checks where the kwarg is missing).
#
# Unique URL names from url/ui:
# -----------------------------------------------------------------------
"add_endpoint_to_product": [("object", Product, "add", "product_id")],
"add_endpoint_to_finding": [("object", Product, "add", "finding_id")],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Endpoint ui auth bypass 🐞 Bug ⛨ Security

When V3 locations are enabled, endpoint UI URL names (e.g., view_endpoint/delete_endpoint) resolve
with kwargs like location_id/product_id, but URL_PERMISSIONS expects eid/pid and
AuthorizationMiddleware skips the check when the kwarg is missing, leaving these views effectively
without object authorization. This can expose findings via view_endpoint and allow destructive
actions like delete_endpoint for any authenticated user.
Agent Prompt
### Issue description
`AuthorizationMiddleware` + `URL_PERMISSIONS` do not correctly authorize endpoint/location UI routes when `V3_FEATURE_LOCATIONS` is enabled. The middleware silently skips object checks when the expected kwarg is absent, and `URL_PERMISSIONS` uses legacy kwarg names (`eid`/`pid`) for URL names that (under V3) resolve with `location_id`/`product_id`, leaving sensitive views (including delete) without object authorization.

### Issue Context
- Under `V3_FEATURE_LOCATIONS`, `dojo/urls.py` includes `dojo/url/ui/urls.py` instead of `dojo/endpoint/urls.py`.
- `dojo/url/ui/urls.py` uses `location_id` and `product_id` for URL names like `view_endpoint`, `delete_endpoint`, `add_endpoint_meta_data`, etc.
- `dojo/url/ui/views.py` does not enforce object authorization itself for many of these operations.

### Fix Focus Areas
- dojo/authorization/middleware.py[19-48]
- dojo/authorization/url_permissions.py[134-163]
- dojo/url/ui/views.py[46-110]
- dojo/url/ui/views.py[325-410]
- dojo/url/ui/urls.py[24-52]
- dojo/urls.py[206-210]

### Expected fix
- Make object checks **fail closed** when a configured check cannot be evaluated (missing kwarg), OR support `arg_name` being a list/tuple and use the first kwarg present.
- Update `URL_PERMISSIONS` endpoint/location entries to correctly authorize V3 routes (e.g., use `Location` + `location_id` for `view_endpoint`/`delete_endpoint`/reports/meta-data, and `Product` + `product_id` for the legacy `add_endpoint` duplicate route).
- Add explicit `user_has_permission_or_403(...)` calls in `dojo/url/ui/views.py` for operations that mutate or disclose data (defense-in-depth), so misconfiguration in `URL_PERMISSIONS` cannot become an authorization bypass.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +161 to +162
"add_endpoint_to_product": [("object", Product, "add", "product_id")],
"add_endpoint_to_finding": [("object", Product, "add", "finding_id")],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. Wrong model permission lookup 🐞 Bug ≡ Correctness

URL_PERMISSIONS defines add_endpoint_to_finding as a Product lookup by finding_id, so
AuthorizationMiddleware authorizes against the wrong object (or returns 404) and does not reflect
the Finding/Product actually being modified. This can break the route or allow/deny access
incorrectly depending on ID collisions.
Agent Prompt
### Issue description
`URL_PERMISSIONS` uses the wrong model for the `add_endpoint_to_finding` URL name: it looks up a `Product` by `finding_id`, but `finding_id` is a `Finding` primary key.

### Issue Context
`AuthorizationMiddleware` performs object checks by doing `get_object_or_404(model, pk=view_kwargs[arg_name])` and then calls `user_has_permission_or_403` on that object. Using the wrong model means the permission check is performed on the wrong object (or becomes a 404).

### Fix Focus Areas
- dojo/authorization/url_permissions.py[159-163]
- dojo/authorization/middleware.py[42-48]
- dojo/url/ui/urls.py[32-36]
- dojo/url/ui/views.py[346-365]

### Expected fix
- Change the `add_endpoint_to_finding` entry to authorize against `Finding` with kwarg `finding_id` (since `user_has_permission` can derive the Product scope from a Finding), or introduce a dedicated check type that can resolve `Finding -> product` and then enforce `add` on the derived Product.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@Maffooch Maffooch force-pushed the tailwind branch 5 times, most recently from 90cf026 to 43e7754 Compare May 11, 2026 15:16
Hand the authorization layer off to dojo-pro. OS keeps a legacy
``is_superuser`` / ``is_staff`` / ``authorized_users`` model and the
seven RBAC + Dojo_Group classes survive as ``managed=False`` shells in
``dojo/authorization/models.py`` so historical pro migrations
(``pro.0001_plugiun_consolidation`` ``EnhancedDojoGroup.group``,
``pro.0034_pghistory_for_permissions_models`` proxy bases) keep
resolving when Django reloads project state. OS code makes no
runtime references to Pro.

Single ``dojo.0268_release_authorization_to_pro`` migration folds:
- Re-introduces ``authorized_users`` M2M on Product / Product_Type and
  backfills it from the RBAC tables (Member / Group → flat membership;
  Global_Role(Owner|Writer|Maintainer|API_Importer) → ``is_superuser`` /
  ``is_staff``).
- Drops the redundant post-RBAC ``members`` / ``authorization_groups``
  M2M accessors on Product / Product_Type (the through-tables remain).
- Flips the eight authorization shells to ``managed=False`` and pins
  their ``db_table``s.
- ``RemoveField``s ``default_group`` / ``default_group_role`` /
  ``default_group_email_pattern`` from ``dojo_system_settings`` (Pro
  copies the values onto ``EnhancedSystemSettings`` first via
  ``run_before``).

Plus the Tailwind UI rebuild and the OS surface tidying that this
branch was already carrying.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Maffooch Maffooch closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants