Skip to content

Add UI toggle for classic Bootstrap fallback and align form field widths#1

Closed
Maffooch wants to merge 4 commits into
devGregA:tailwindfrom
Maffooch:tailwind-toggle
Closed

Add UI toggle for classic Bootstrap fallback and align form field widths#1
Maffooch wants to merge 4 commits into
devGregA:tailwindfrom
Maffooch:tailwind-toggle

Conversation

@Maffooch
Copy link
Copy Markdown
Collaborator

@Maffooch Maffooch commented Apr 28, 2026

Summary

Adds a per-user UI toggle that lets people opt into the redesigned Tailwind UI ahead of it becoming the default, with the original Bootstrap UI preserved as a parallel templates_classic/ tree for fallback. Also fixes a long-standing inconsistency where text inputs, markdown editors, and tag selects on form pages rendered at three different widths.

What's in this PR

UI toggle infrastructure

  • New UserContactInfo.ui_use_tailwind boolean preference (migration 0265_usercontactinfo_ui_use_tailwind).
  • New dojo/template_loaders.py that chooses between dojo/templates/ (Tailwind) and dojo/templates_classic/ (Bootstrap) based on the per-request preference.
  • Full dojo/templates_classic/ tree (snapshot of the legacy templates), plus classic-only dojo/static/dojo/css/classic/ and dojo/static/dojo/js/classic/ assets so existing users see no visual change until they opt in.
  • Profile page exposes the toggle.
  • Context-processor banner inviting non-opted-in users to enable the new UI in their profile, with copy: "A redesigned UI is available as a beta opt-in. It will become the default on September 8th in the 2.62.0 release."

Form field width consistency fix

Across New/Edit pages for Product Type, Product, Engagement, Test, Finding, Risk Acceptance, and Finding Group (plus ~30 other forms that share the same partial), every text input, select, textarea, EasyMDE markdown editor, and Tagulous/Select2 tag picker now renders at the same responsive width.

  • Removed the legacy width: 70% !important <style> boilerplate that was duplicated across 38 form templates and one popup (add_related.html).
  • Added a single rule in dojo/static/dojo/css/dojo.css that scopes EasyMDE, CodeMirror, the EasyMDE toolbar/statusbar, .chosen-container and .select2-container to width: 100% of their .form-group column — !important only on .select2-container so it beats Tagulous' inline style="width:70%".
  • Verified with Playwright at 1440 / 768 / 414px viewports: every widget on every target form has a single distinct width per viewport (no more 70% outliers).

Test plan

  • New user (no UserContactInfo) sees the classic Bootstrap UI by default and a banner inviting them to opt in.
  • Toggling ui_use_tailwind on the profile flips a session over to the Tailwind templates without a migration or restart.
  • Banner copy reads "It will become the default on September 8th in the 2.62.0 release." and disappears once the user opts in.
  • On Tailwind UI: open New/Edit Product Type, Product, Engagement, Test, Finding, Risk Acceptance, and Finding Group — all text inputs, selects, markdown editors, and tag pickers visually align to the same right edge.
  • At 1440 / 768 / 414px viewports the form widgets resize together (no fixed pixels anywhere).
  • Classic UI renders unchanged (the 70% legacy width is preserved in templates_classic/).

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Comprehensive UI/UX redesign with finding verification, Celery monitoring, and batch deduplication improvements

✨ Enhancement 🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• **Documentation site redesign**: Complete overhaul of Hugo documentation layouts including new
  base template, homepage with dynamic release fetching, improved header with accessibility features
  and social links, comprehensive footer component, and new image render hook
• **Finding verification feature**: Added "Verify Finding" action with new template, keyboard
  shortcuts (v/c), and bulk edit enhancements with conditional V3_FEATURE_LOCATIONS support
• **Celery status monitoring**: New template and interface for monitoring Redis broker, Celery
  workers, queue inspection, and task management with AJAX-driven real-time updates
• **PDF report formatting improvements**: Replaced <pre> tags with <div class="report-field">
  across all PDF report templates for better text wrapping and rendering
• **Batch deduplication refactoring**: Enhanced deduplication module with match-only preview
  functions, batch processing support, and handling of unsaved findings/locations
• **Model refactoring**: JIRA imports migration from dojo.jira_link.helper to
  dojo.jira.services, added deduplication field constants, improved location/endpoint handling
• **Template security fixes**: Removed unsafe |safe filters from endpoint template, fixed field
  references and display methods
• **Filter corrections**: Changed truncatechars_html to truncatechars across multiple templates
  for proper HTML handling
• **UI enhancements**: Added sorting to endpoints and URLs tables, social provider indicators for
  groups, improved list page card layouts, base template banner system enhancements
• **Security audit tests**: Comprehensive permission test suite covering 11 vulnerability scenarios
  including IDOR, role-based access, and cross-product controls
• **Code cleanup**: Removed unused imports, normalized line endings, minified scripts, cleaned up
  styling approaches
Diagram
flowchart LR
  A["Documentation<br/>Redesign"] --> B["Hugo Layouts<br/>& Templates"]
  C["Finding<br/>Verification"] --> D["New Verify<br/>Template"]
  E["Celery<br/>Monitoring"] --> F["Status & Queue<br/>Management"]
  G["PDF Reports"] --> H["Text Wrapping<br/>Improvements"]
  I["Batch<br/>Deduplication"] --> J["Match-Only<br/>Preview"]
  K["Model<br/>Refactoring"] --> L["JIRA Migration<br/>& Optimization"]
  M["Template<br/>Security"] --> N["Filter & Field<br/>Fixes"]
  B --> O["Enhanced UX"]
  D --> O
  F --> O
  H --> O
  J --> O
  L --> O
  N --> O
Loading

Grey Divider

File Changes

1. docs/layouts/home.html ✨ Enhancement +150/-56

Homepage redesign with feature cards and dynamic release info

• Completely redesigned homepage with dynamic release fetching from GitHub API
• Added hero section with improved layout and call-to-action buttons
• Introduced 8-card quick navigation grid for key features (Import Data, Triage Findings, Asset
 Modeling, Metrics, Issue Tracking, Automation, Tools, Administration)
• Removed old Bootstrap grid layout and replaced with modern card-based design
• Simplified sidebar-footer definition

docs/layouts/home.html


2. docs/layouts/_partials/header/header.html ✨ Enhancement +105/-92

Header restructuring with accessibility and social links

• Added skip-to-content accessibility link at the top
• Refactored header layout with improved logo linking to home
• Moved release notes fetching logic and integrated it with header branding
• Repositioned search functionality to right-aligned section with improved styling
• Replaced social menu with hardcoded social links (GitHub, LinkedIn, YouTube, X) using Tabler icons
• Improved responsive design and spacing

docs/layouts/_partials/header/header.html


3. dojo/templates/dojo/celery_status.html ✨ Enhancement +305/-0

New Celery status monitoring and queue management interface

• New template for Celery status monitoring and management
• Displays Redis broker and Celery worker status with real-time indicators
• Provides queue inspection with task details (name, count, position, expiry)
• Includes purge functionality for entire queue or specific tasks
• Shows Celery configuration settings (time limits, expiry)
• JavaScript-driven interface with AJAX calls for status updates and actions

dojo/templates/dojo/celery_status.html


View more (146)
4. dojo/templates/dojo/view_finding.html ✨ Enhancement +122/-43

Finding verification feature and bulk edit enhancements

• Added "Verify Finding" action button in the findings menu (when finding not verified)
• Moved bulk edit menu section to after import activity section
• Enhanced bulk edit form with conditional V3_FEATURE_LOCATIONS support using radio buttons
• Added keyboard shortcuts for verify (v) and close (c) finding actions
• Added "Remove from finding" button for endpoint management
• Updated ProTip to include new keyboard shortcuts

dojo/templates/dojo/view_finding.html


5. docs/layouts/_partials/footer/footer.html ✨ Enhancement +80/-0

New footer component with navigation and social links

• New comprehensive footer component with brand section
• Organized footer links into Documentation, Community, Company, and Connect sections
• Integrated social media links (GitHub, LinkedIn, YouTube, X) with SVG icons
• Added copyright and attribution information
• Responsive grid layout with proper spacing and styling

docs/layouts/_partials/footer/footer.html


6. docs/layouts/_markup/render-image.html ✨ Enhancement +188/-0

New image render hook for Hugo markdown processing

• New image render hook for Hugo based on Veriphor template
• Handles internal and external image resolution with fallback logic
• Supports responsive images with proper attributes (alt, title, loading, fetchpriority)
• Differentiates between SVG and raster images with appropriate rendering
• Includes error handling with configurable error levels

docs/layouts/_markup/render-image.html


7. docs/layouts/_partials/sidebar/render-section-menu.html Formatting +67/-67

Line ending normalization

• Line ending normalization (CRLF to LF)
• No functional changes to the menu rendering logic

docs/layouts/_partials/sidebar/render-section-menu.html


8. docs/layouts/single.html ✨ Enhancement +64/-0

New single page layout for documentation content

• New single page layout template for documentation
• Implements responsive three-column layout with sidebar, content, and TOC
• Includes breadcrumb navigation and page metadata
• Supports conditional rendering of table of contents
• Integrates headline hashing and edit page functionality

docs/layouts/single.html


9. dojo/templates/dojo/snippets/endpoints.html 🐞 Bug fix +7/-7

Endpoint template security and display fixes

• Removed |safe filter from auditor and mitigated_by fields for security
• Changed endpoint.status to endpoint.get_status_display for proper display
• Fixed missing closing tag in vulnerable endpoints header
• Whitespace and formatting cleanup

dojo/templates/dojo/snippets/endpoints.html


10. dojo/templates/dojo/product_type_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to CVSS v3, Description, Mitigation, Impact, Steps to Reproduce, Severity Justification,
 and References sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/product_type_pdf_report.html


11. dojo/templates/dojo/engagement_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied consistently across all finding detail sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/engagement_pdf_report.html


12. dojo/templates/dojo/endpoint_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to all finding detail sections in endpoint reports
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/endpoint_pdf_report.html


13. dojo/templates/dojo/finding_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to all finding detail sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/finding_pdf_report.html


14. dojo/templates/dojo/product_endpoint_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to all finding detail sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/product_endpoint_pdf_report.html


15. dojo/templates/dojo/product_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to all finding detail sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/product_pdf_report.html


16. dojo/templates/dojo/test_pdf_report.html ✨ Enhancement +7/-7

PDF report formatting improvements with div containers

• Replaced <pre> tags with <div class="report-field"> for better PDF rendering
• Applied to all finding detail sections
• Improves text wrapping and formatting in PDF reports

dojo/templates/dojo/test_pdf_report.html


17. docs/layouts/_partials/footer/script-footer-custom.html Formatting +16/-16

Line ending normalization

• Line ending normalization (CRLF to LF)
• No functional changes to the script footer logic

docs/layouts/_partials/footer/script-footer-custom.html


18. docs/layouts/baseof.html ✨ Enhancement +22/-0

New base layout template for Hugo documentation

• New base layout template for Hugo documentation site
• Implements complete HTML structure with proper semantic markup
• Integrates header, footer, and main content areas
• Supports scroll spy and responsive container breakpoints
• Includes accessibility features with main-content ID

docs/layouts/baseof.html


19. dojo/templates/dojo/endpoints.html 🐞 Bug fix +2/-2

Endpoints table sorting and field name fixes

• Added sorting capability to "Active (Verified) Findings" column header
• Fixed field reference from active_findings_count to active_finding_count

dojo/templates/dojo/endpoints.html


20. docs/layouts/404.html ✨ Enhancement +14/-5

404 error page redesign with better UX

• Redesigned 404 error page with improved layout and styling
• Added large error code display and centered content
• Included two action buttons (Go home and Browse docs)
• Improved visual hierarchy and user experience

docs/layouts/404.html


21. dojo/templates/dojo/templates.html 🐞 Bug fix +2/-2

Template filter correction for finding titles

• Changed truncatechars_html filter to truncatechars for finding titles in template popover
• Applied to both "add from template" and "apply template" links

dojo/templates/dojo/templates.html


22. dojo/templates/dojo/breadcrumbs/finding_breadcrumb.html 🐞 Bug fix +1/-1

Breadcrumb filter correction for finding title

• Changed truncatechars_html filter to truncatechars for finding title in breadcrumb

dojo/templates/dojo/breadcrumbs/finding_breadcrumb.html


23. dojo/templates/dojo/verify_finding.html ✨ Enhancement +18/-0

New finding verification form template

• New template for verifying findings
• Provides form interface for marking findings as verified
• Includes optional comment field
• Extends base template with standard form layout

dojo/templates/dojo/verify_finding.html


24. docs/layouts/_partials/head/custom-head.html Formatting +6/-6

Line ending normalization

• Line ending normalization (CRLF to LF)
• No functional changes to custom head logic

docs/layouts/_partials/head/custom-head.html


25. dojo/templates/base.html ✨ Enhancement +20/-1

Base template system settings and banner enhancements

• Added "Celery Status" link in system settings menu for superusers
• Changed CREATE_CLOUD_BANNER context variable to SHOW_PLG_LINK
• Added support for additional_banners with expandable content sections
• Improved banner rendering with style, source, and expanded HTML support

dojo/templates/base.html


26. docs/layouts/_partials/head/script-header.html ✨ Enhancement +11/-11

Script header minification and optimization

• Minified Reo JavaScript initialization code
• Changed async attribute to defer for better script loading
• Improved code formatting and efficiency

docs/layouts/_partials/head/script-header.html


27. docs/layouts/_default/list.html ✨ Enhancement +16/-14

List page card layout improvements with metadata

• Improved card layout with better indentation and formatting
• Added description and lead text display in list cards
• Enhanced card content with optional metadata fields

docs/layouts/_default/list.html


28. docs/layouts/_partials/sidebar/section-menu.html ✨ Enhancement +32/-32

Section menu styling cleanup

• Removed inline padding style from version label
• Removed border-top style from version menu wrapper
• Applied cleaner CSS class approach for styling

docs/layouts/_partials/sidebar/section-menu.html


29. dojo/reports/widgets.py Miscellaneous +1/-1

Settings import addition

• Added import for django.conf.settings

dojo/reports/widgets.py


30. dojo/templates/report_base.html ✨ Enhancement +18/-0

CSS improvements for text wrapping in report templates

• Added overflow-wrap: break-word CSS property to existing table cell styles
• Created new .report-field CSS class with margin, overflow-wrap, and word-break properties
• Added .report-field pre styles for preformatted text with white-space wrapping and transparent
 background

dojo/templates/report_base.html


31. dojo/templates/dojo/groups.html ✨ Enhancement +1/-1

Display social provider indicator for groups

• Added conditional display of social_provider field as a tag label next to group name
• Uses tag-label tag-color CSS classes for visual consistency

dojo/templates/dojo/groups.html


32. dojo/templates/dojo/url/list.html ✨ Enhancement +1/-1

Add sorting capability to findings column header

• Replaced static "Active (Total) Findings" header with sortable column using dojo_sort template
 tag
• Enables sorting by active_findings field with ordering parameter

dojo/templates/dojo/url/list.html


33. dojo/templates/dojo/findings_list_snippet.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Simplifies HTML handling by removing HTML-aware truncation

dojo/templates/dojo/findings_list_snippet.html


34. dojo/templates/dojo/request_report.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Affects finding title rendering in report table

dojo/templates/dojo/request_report.html


35. dojo/templates/dojo/view_test.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Updates finding title rendering in test view

dojo/templates/dojo/view_test.html


36. dojo/templates/dojo/finding_related_row.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for similar finding title display
• Affects related findings row rendering

dojo/templates/dojo/finding_related_row.html


37. dojo/templates/dojo/add_findings_as_accepted.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Updates accepted findings table rendering

dojo/templates/dojo/add_findings_as_accepted.html


38. dojo/templates/dojo/metrics.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Affects metrics view finding title rendering

dojo/templates/dojo/metrics.html


39. dojo/templates/dojo/view_risk_acceptance.html 🐞 Bug fix +1/-1

Simplify finding title truncation filter

• Changed truncatechars_html filter to truncatechars for finding title display
• Updates risk acceptance findings table rendering

dojo/templates/dojo/view_risk_acceptance.html


40. dojo/templates/dojo/view_group.html ✨ Enhancement +1/-1

Display social provider indicator in group heading

• Added conditional display of social_provider field as a tag label next to group name in heading
• Uses tag-label tag-color CSS classes for consistent styling

dojo/templates/dojo/view_group.html


41. unittests/test_permissions_audit.py 🧪 Tests +1847/-0

Add extensive security permission audit test suite

• Comprehensive security-focused permission test suite covering 11 vulnerability scenarios
• Tests include Risk Acceptance exposure, metadata batch permissions, IDOR vulnerabilities, and
 permission enforcement
• Covers cross-product/engagement access controls, note relationship verification, and role-based
 access restrictions
• Tests for Reader/Writer/Owner role permission boundaries on API and UI endpoints

unittests/test_permissions_audit.py


42. unittests/test_copy_model.py Formatting +360/-360

Normalize line endings in test file

• Reformatted entire file with consistent line endings (CRLF to LF conversion)
• No functional changes to test logic or assertions

unittests/test_copy_model.py


43. dojo/forms.py Dependencies +17/-390

Refactor JIRA imports and clean up unused dependencies

• Removed unused imports: os and validators
• Removed unused reverse import from django.urls
• Removed jira_helper import and replaced with jira_services module
• Added imports from dojo.jira.forms for JIRA-related form classes with backward compatibility
• Removed JIRA_Instance, JIRA_Issue, JIRA_Project model imports (now in jira.forms)
• Updated jira_helper.get_jira_url() call to jira_services.get_url()
• Added initialization of endpoints field initial value in Finding form

dojo/forms.py


44. unittests/test_apiv2_methods_and_endpoints.py Miscellaneous +1/-1

Add celery to API endpoint exemption list

• Added celery to the exempt list in test_is_defined method
• Allows celery endpoint to be excluded from API documentation requirements

unittests/test_apiv2_methods_and_endpoints.py


45. unittests/test_finding_model.py Formatting +679/-679

Test file formatting and whitespace normalization

• File reformatted with consistent indentation and line endings
• No functional changes to test logic or assertions
• All test methods and classes remain structurally identical

unittests/test_finding_model.py


46. dojo/finding/deduplication.py ✨ Enhancement +510/-51

Batch deduplication refactoring with match-only preview support

• Added Endpoint_Status import for improved type handling
• Enhanced set_duplicate() with comprehensive docstring and batch processing support via save
 parameter
• Refactored deduplication functions to return lists of modified findings instead of None
• Added new match-only functions (match_batch_hash_code, match_batch_unique_id,
 match_batch_uid_or_hash, match_batch_legacy, match_batch_of_findings) for
 preview/non-persisting operations
• Introduced _flush_duplicate_changes() for bulk-updating duplicate field changes
• Added do_false_positive_history_batch() for batch false-positive history processing
• Refactored get_endpoints_as_url() and finding_locations() to accept collections instead of
 findings
• Enhanced build_candidate_scope_queryset() with location-aware prefetching and field deferral
• Added _fp_candidates_qs() and _fetch_fp_candidates_for_batch() helpers for false-positive
 candidate matching
• Updated dedupe_batch_of_findings() to return modified findings list
• Added support for unsaved findings in deduplication via unsaved_locations and
 unsaved_endpoints attributes

dojo/finding/deduplication.py


47. dojo/models.py ✨ Enhancement +83/-223

Model refactoring with JIRA migration and deduplication optimization

• Removed credentials field from System_Settings model
• Updated JIRA helper imports from dojo.jira_link.helper to dojo.jira.services with new function
 names
• Moved JIRA model classes (JIRA_Instance, JIRA_Project, JIRA_Issue) to separate module with
 backward-compatible imports
• Added DEDUPLICATION_FIELDS and DEDUPLICATION_DEFERRED_FIELDS constants to Finding model for
 optimized queryset loading
• Enhanced Finding.__init__() to initialize unsaved_locations list for location tracking
• Updated Test.__init__() to initialize unsaved_metadata list
• Refactored location and endpoint handling in _get_unsaved_locations() and
 _get_saved_locations() for V3 feature compatibility
• Made Language_Type.language field unique
• Updated Engagement.delete() to pass self directly instead of keyword argument

dojo/models.py


48. tests/announcement_banner_test.py 🐞 Bug fix +6/-6

Announcement banner selector refinement for system filtering

• Updated CSS selector in all assertion checks from .announcement-banner to
 .announcement-banner:not([data-source])
• Ensures tests only check for user-created announcements, excluding system-generated ones
• Applied consistently across 6 test methods

tests/announcement_banner_test.py


49. .dryrunsecurity.yaml Additional files +2/-1

...

.dryrunsecurity.yaml


50. .gitattributes Additional files +14/-0

...

.gitattributes


51. .github/dependabot.yml Additional files +6/-2

...

.github/dependabot.yml


52. .github/pull_request_template.md Additional files +1/-1

...

.github/pull_request_template.md


53. .github/renovate.json Additional files +4/-2

...

.github/renovate.json


54. .github/workflows/build-docker-images-for-testing.yml Additional files +3/-3

...

.github/workflows/build-docker-images-for-testing.yml


55. .github/workflows/cancel-outdated-workflow-runs.yml Additional files +2/-2

...

.github/workflows/cancel-outdated-workflow-runs.yml


56. .github/workflows/fetch-oas.yml Additional files +1/-1

...

.github/workflows/fetch-oas.yml


57. .github/workflows/gh-pages.yml Additional files +5/-5

...

.github/workflows/gh-pages.yml


58. .github/workflows/integration-tests.yml Additional files +56/-22

...

.github/workflows/integration-tests.yml


59. .github/workflows/k8s-tests.yml Additional files +4/-4

...

.github/workflows/k8s-tests.yml


60. .github/workflows/performance-tests.yml Additional files +74/-0

...

.github/workflows/performance-tests.yml


61. .github/workflows/release-1-create-pr.yml Additional files +9/-3

...

.github/workflows/release-1-create-pr.yml


62. .github/workflows/release-2-tag-docker-push.yml Additional files +1/-1

...

.github/workflows/release-2-tag-docker-push.yml


63. .github/workflows/release-3-master-into-dev.yml Additional files +18/-6

...

.github/workflows/release-3-master-into-dev.yml


64. .github/workflows/release-drafter.yml Additional files +2/-2

...

.github/workflows/release-drafter.yml


65. .github/workflows/release-x-manual-docker-containers.yml Additional files +4/-4

...

.github/workflows/release-x-manual-docker-containers.yml


66. .github/workflows/release-x-manual-helm-chart.yml Additional files +2/-2

...

.github/workflows/release-x-manual-helm-chart.yml


67. .github/workflows/release-x-manual-merge-container-digests.yml Additional files +3/-3

...

.github/workflows/release-x-manual-merge-container-digests.yml


68. .github/workflows/release-x-manual-tag-as-latest.yml Additional files +2/-2

...

.github/workflows/release-x-manual-tag-as-latest.yml


69. .github/workflows/renovate.yaml Additional files +2/-2

...

.github/workflows/renovate.yaml


70. .github/workflows/rest-framework-tests.yml Additional files +2/-2

...

.github/workflows/rest-framework-tests.yml


71. .github/workflows/test-helm-chart.yml Additional files +5/-5

...

.github/workflows/test-helm-chart.yml


72. .github/workflows/unit-tests.yml Additional files +6/-0

...

.github/workflows/unit-tests.yml


73. .github/workflows/update-sample-data.yml Additional files +8/-18

...

.github/workflows/update-sample-data.yml


74. .github/workflows/validate_docs_build.yml Additional files +11/-4

...

.github/workflows/validate_docs_build.yml


75. CLAUDE.md Additional files +249/-0

...

CLAUDE.md


76. Dockerfile.django-alpine Additional files +2/-3

...

Dockerfile.django-alpine


77. Dockerfile.django-debian Additional files +3/-4

...

Dockerfile.django-debian


78. Dockerfile.integration-tests-debian Additional files +2/-2

...

Dockerfile.integration-tests-debian


79. Dockerfile.nginx-alpine Additional files +1/-1

...

Dockerfile.nginx-alpine


80. README.md Additional files +9/-14

...

README.md


81. components/package.json Additional files +2/-2

...

components/package.json


82. docker-compose.override.dev.yml Additional files +20/-1

...

docker-compose.override.dev.yml


83. docker-compose.override.integration_tests.yml Additional files +1/-0

...

docker-compose.override.integration_tests.yml


84. docker-compose.override.unit_tests.yml Additional files +1/-7

...

docker-compose.override.unit_tests.yml


85. docker-compose.override.unit_tests_cicd.yml Additional files +1/-7

...

docker-compose.override.unit_tests_cicd.yml


86. docker-compose.yml Additional files +3/-2

...

docker-compose.yml


87. docker/docker-compose.override.performance_tests_cicd.yml Additional files +6/-0

...

docker/docker-compose.override.performance_tests_cicd.yml


88. docker/entrypoint-integration-tests.sh Additional files +272/-0

...

docker/entrypoint-integration-tests.sh


89. docker/entrypoint-unit-tests-devDocker.sh Additional files +2/-2

...

docker/entrypoint-unit-tests-devDocker.sh


90. docker/entrypoint-unit-tests.sh Additional files +3/-3

...

docker/entrypoint-unit-tests.sh


91. docs/assets/js/custom.js Additional files +92/-60

...

docs/assets/js/custom.js


92. docs/assets/jsconfig.json Additional files +8/-8

...

docs/assets/jsconfig.json


93. docs/assets/scss/common/_custom.scss Additional files +1041/-399

...

docs/assets/scss/common/_custom.scss


94. docs/assets/scss/common/_variables-custom.scss Additional files +55/-55

...

docs/assets/scss/common/_variables-custom.scss


95. docs/config/_default/hugo.toml Additional files +88/-88

...

docs/config/_default/hugo.toml


96. docs/config/_default/languages.toml Additional files +6/-6

...

docs/config/_default/languages.toml


97. docs/config/_default/markup.toml Additional files +33/-33

...

docs/config/_default/markup.toml


98. docs/config/_default/menus/menus.en.toml Additional files +89/-71

...

docs/config/_default/menus/menus.en.toml


99. docs/config/_default/module.toml Additional files +96/-96

...

docs/config/_default/module.toml


100. docs/config/_default/params.toml Additional files +155/-155

...

docs/config/_default/params.toml


101. docs/config/babel.config.js Additional files +17/-17

...

docs/config/babel.config.js


102. docs/config/development/hugo.toml Additional files +1/-1

...

docs/config/development/hugo.toml


103. docs/config/development/params.toml Additional files +6/-0

...

docs/config/development/params.toml


104. docs/config/next/hugo.toml Additional files +2/-2

...

docs/config/next/hugo.toml


105. docs/config/postcss.config.js Additional files +63/-63

...

docs/config/postcss.config.js


106. docs/config/production/hugo.toml Additional files +1/-1

...

docs/config/production/hugo.toml


107. docs/content/admin/notifications/about_notifications.md Additional files +1/-1

...

docs/content/admin/notifications/about_notifications.md


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

...

docs/content/admin/sso/OS__auth0.md


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

...

docs/content/admin/sso/OS__azure_ad.md


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

...

docs/content/admin/sso/OS__github_enterprise.md


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

...

docs/content/admin/sso/OS__gitlab.md


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

...

docs/content/admin/sso/OS__google.md


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

...

docs/content/admin/sso/OS__keycloak.md


114. docs/content/admin/sso/OS__ldap.md Additional files +135/-0

...

docs/content/admin/sso/OS__ldap.md


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

...

docs/content/admin/sso/OS__oidc.md


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

...

docs/content/admin/sso/OS__okta.md


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

...

docs/content/admin/sso/OS__remote_user.md


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

...

docs/content/admin/sso/OS__saml.md


119. docs/content/admin/sso/PRO__auth0.md Additional files +33/-0

...

docs/content/admin/sso/PRO__auth0.md


120. docs/content/admin/sso/PRO__azure_ad.md Additional files +58/-0

...

docs/content/admin/sso/PRO__azure_ad.md


121. docs/content/admin/sso/PRO__github_enterprise.md Additional files +32/-0

...

docs/content/admin/sso/PRO__github_enterprise.md


122. docs/content/admin/sso/PRO__gitlab.md Additional files +32/-0

...

docs/content/admin/sso/PRO__gitlab.md


123. docs/content/admin/sso/PRO__google.md Additional files +38/-0

...

docs/content/admin/sso/PRO__google.md


124. docs/content/admin/sso/PRO__keycloak.md Additional files +53/-0

...

docs/content/admin/sso/PRO__keycloak.md


125. docs/content/admin/sso/PRO__oidc.md Additional files +23/-0

...

docs/content/admin/sso/PRO__oidc.md


126. docs/content/admin/sso/PRO__okta.md Additional files +46/-0

...

docs/content/admin/sso/PRO__okta.md


127. docs/content/admin/sso/PRO__saml.md Additional files +69/-0

...

docs/content/admin/sso/PRO__saml.md


128. docs/content/admin/sso/_index.md Additional files +58/-0

...

docs/content/admin/sso/_index.md


129. docs/content/admin/user_management/configure_sso.md Additional files +10/-0

...

docs/content/admin/user_management/configure_sso.md


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

...

docs/content/admin/user_management/set_user_permissions.md


131. docs/content/admin/user_management/user_permission_chart.md Additional files +2/-0

...

docs/content/admin/user_management/user_permission_chart.md


132. docs/content/archived_docs/_index.md Additional files +0/-0


...

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 28, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (4)

Grey Divider


Action required

1. dojo.jira.services accepts request 📘 Rule violation ⚙ Maintainability
Description
New Jira service-layer functions accept Django request objects (and delegate request-driven form
processing), coupling services to HTTP/framework concerns. This violates the requirement that
services remain framework-agnostic and only accept domain objects/primitives.
Code

dojo/jira/services.py[R95-166]

+def link_finding(request, finding, new_jira_issue_key):
+    """
+    Link a finding to an existing Jira issue.
+
+    Wraps: jira_helper.finding_link_jira
+    """
+    return _get_helper().finding_link_jira(request, finding, new_jira_issue_key)
+
+
+def unlink_finding(request, finding):
+    """
+    Unlink a finding from its Jira issue.
+
+    Wraps: jira_helper.finding_unlink_jira
+    """
+    return _get_helper().finding_unlink_jira(request, finding)
+
+
+def link_finding_group(request, finding_group, new_jira_issue_key):
+    """
+    Link a finding group to an existing Jira issue.
+
+    Wraps: jira_helper.finding_group_link_jira
+    """
+    return _get_helper().finding_group_link_jira(request, finding_group, new_jira_issue_key)
+
+
+def unlink(request, obj):
+    """
+    Unlink an object from its Jira issue.
+
+    Wraps: jira_helper.unlink_jira
+    """
+    return _get_helper().unlink_jira(request, obj)
+
+
+def push_status(obj, jira_instance, jira, issue, *, save=False):
+    """
+    Push finding status to Jira.
+
+    Wraps: jira_helper.push_status_to_jira
+    """
+    return _get_helper().push_status_to_jira(obj, jira_instance, jira, issue, save=save)
+
+
+def update_issue(obj, *args, **kwargs):
+    """
+    Update a Jira issue.
+
+    Wraps: jira_helper.update_jira_issue
+    """
+    return _get_helper().update_jira_issue(obj, *args, **kwargs)
+
+
+def process_project_form(request, instance=None, target=None, product=None, engagement=None):
+    """
+    Process a Jira project configuration form.
+
+    Wraps: jira_helper.process_jira_project_form
+    """
+    return _get_helper().process_jira_project_form(request, instance=instance, target=target,
+                                                    product=product, engagement=engagement)
+
+
+def process_epic_form(request, engagement=None):
+    """
+    Process a Jira epic form.
+
+    Wraps: jira_helper.process_jira_epic_form
+    """
+    return _get_helper().process_jira_epic_form(request, engagement=engagement)
+
Evidence
PR Compliance ID 3 forbids service functions from accepting HTTP/framework objects like request.
The newly added dojo/jira/services.py defines multiple service functions that take request as a
parameter (e.g., link_finding, unlink, process_project_form, process_epic_form).

CLAUDE.md
dojo/jira/services.py[95-166]

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/jira/services.py` exposes service functions that accept Django `request` objects (and request-driven form processing), violating the service-layer framework-agnostic requirement.

## Issue Context
Services should accept only domain objects/primitives and must not depend on HTTP concerns. Request/form handling should live in UI/API layers, which then call services with primitives/models.

## Fix Focus Areas
- dojo/jira/services.py[95-166]

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


2. RiskAcceptanceViewSet.notes() creates Notes 📘 Rule violation ⚙ Maintainability
Description
The new notes action performs multi-step note creation (saving Notes, creating NoteHistory,
and triggering process_tag_notifications) directly inside the API view. This is business workflow
logic that should be moved into a services.py layer, with the view acting as a thin delegator.
Code

dojo/api_v2/views.py[R783-825]

+    @action(detail=True, methods=["get", "post"], permission_classes=(IsAuthenticated, permissions.UserHasRiskAcceptanceRelatedObjectPermission))
+    def notes(self, request, pk=None):
+        risk_acceptance = self.get_object()
+        if request.method == "POST":
+            new_note = serializers.AddNewNoteOptionSerializer(data=request.data)
+            if new_note.is_valid():
+                entry = new_note.validated_data["entry"]
+                private = new_note.validated_data.get("private", False)
+                note_type = new_note.validated_data.get("note_type", None)
+            else:
+                return Response(new_note.errors, status=status.HTTP_400_BAD_REQUEST)
+
+            notes = risk_acceptance.notes.filter(note_type=note_type).first()
+            if notes and note_type and note_type.is_single:
+                return Response("Only one instance of this note_type allowed on a risk acceptance.", status=status.HTTP_400_BAD_REQUEST)
+
+            author = request.user
+            note = Notes(entry=entry, author=author, private=private, note_type=note_type)
+            note.save()
+            history = NoteHistory.objects.create(data=note.entry, time=note.date, current_editor=note.author)
+            note.history.add(history)
+            risk_acceptance.notes.add(note)
+            engagement = risk_acceptance.engagement
+            if engagement:
+                process_tag_notifications(
+                    request=request,
+                    note=note,
+                    parent_url=request.build_absolute_uri(
+                        reverse("view_risk_acceptance", args=(engagement.id, risk_acceptance.id)),
+                    ),
+                    parent_title=f"Risk Acceptance: {risk_acceptance.name}",
+                )
+
+            serialized_note = serializers.NoteSerializer(
+                {"author": author, "entry": entry, "private": private},
+            )
+            return Response(serialized_note.data, status=status.HTTP_201_CREATED)
+
+        notes = risk_acceptance.notes.all()
+        serialized_notes = serializers.RiskAcceptanceToNotesSerializer(
+            {"risk_acceptance_id": risk_acceptance, "notes": notes},
+        )
+        return Response(serialized_notes.data, status=status.HTTP_200_OK)
Evidence
PR Compliance ID 2 requires API views to be thin and delegate business workflows (multi-model save
flows, notifications) into services.py. The added notes action contains the full workflow
inline, including persistence and notification dispatch.

CLAUDE.md
dojo/api_v2/views.py[783-825]

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

## Issue description
`RiskAcceptanceViewSet.notes()` contains business workflow logic (creating notes/history and dispatching tag notifications) inside the API layer.

## Issue Context
Per the architecture rules, views should handle transport concerns (auth, serializer validation, HTTP responses) and delegate domain workflows to a module service function.

## Fix Focus Areas
- dojo/api_v2/views.py[783-825]

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


3. dojo/jira/forms.py not under ui/ 📘 Rule violation ⚙ Maintainability
Description
Jira module UI forms were extracted into dojo/jira/forms.py instead of dojo/jira/ui/forms.py as
required by the module UI layering rules. This breaks the expected module layout and undermines
consistent UI separation across modules.
Code

dojo/jira/forms.py[R1-20]

+import logging
+import os
+from pathlib import Path
+
+from django import forms
+from django.conf import settings
+from django.core import validators
+from django.core.exceptions import ValidationError
+from django.urls import reverse
+
+from dojo.jira import services as jira_services
+from dojo.models import (
+    JIRA_Instance,
+    JIRA_Issue,
+    JIRA_Project,
+)
+from dojo.utils import (
+    get_system_setting,
+    is_finding_groups_enabled,
+)
Evidence
PR Compliance ID 9 requires module-specific UI forms to live in dojo/{module}/ui/forms.py (with
re-exports kept in dojo/forms.py). The PR adds Jira forms at dojo/jira/forms.py and re-exports
them from dojo/forms.py, but not from the required ui/ location.

CLAUDE.md
dojo/jira/forms.py[1-20]
dojo/forms.py[36-49]

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

## Issue description
Jira UI forms are located at `dojo/jira/forms.py` rather than the required `dojo/jira/ui/forms.py`.

## Issue Context
The module layout standard requires UI-layer code (forms) under `ui/` to keep module roots focused on domain/services and to match the `dojo/url/` canonical structure.

## Fix Focus Areas
- dojo/jira/forms.py[1-404]
- dojo/forms.py[36-49]

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


View more (2)
4. dojo/jira/api/serializers.py wrong path 📘 Rule violation ⚙ Maintainability
Description
Jira API serializers were added under dojo/jira/api/serializers.py rather than the required
dojo/jira/api/serializer.py. This deviates from the standardized extraction layout and can break
consistency/expectations for module API serializer placement.
Code

dojo/jira/api/serializers.py[R1-18]

+import json
+
+from django.urls import reverse
+from rest_framework import serializers
+
+from dojo.jira import services as jira_services
+from dojo.models import (
+    JIRA_Instance,
+    JIRA_Issue,
+    JIRA_Project,
+)
+
+
+class JIRAIssueSerializer(serializers.ModelSerializer):
+    url = serializers.SerializerMethodField(read_only=True)
+
+    class Meta:
+        model = JIRA_Issue
Evidence
PR Compliance ID 12 requires module serializers to be defined in dojo/{module}/api/serializer.py.
The PR introduces Jira serializers in a differently named file (serializers.py), violating the
specified module API serializer location convention.

CLAUDE.md
dojo/jira/api/serializers.py[1-18]

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

## Issue description
Jira API serializers were added as `dojo/jira/api/serializers.py`, but the required standardized location is `dojo/jira/api/serializer.py`.

## Issue Context
The compliance standard expects a consistent filename/location across modules for serializer extraction to simplify discovery and re-export conventions.

## Fix Focus Areas
- dojo/jira/api/serializers.py[1-91]
- dojo/api_v2/serializers.py[1377-1381]

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


5. Query helper NameError 🐞 Bug ≡ Correctness
Description
dojo/query_utils.build_count_subquery references Subquery, Count, and IntegerField (and
annotates -> Subquery) without importing them, which triggers a NameError when the module is
imported. Because build_count_subquery is now imported/used by API views, this can break Django
startup and any endpoint module import that touches it.
Code

dojo/api_v2/views.py[164]

+from dojo.query_utils import build_count_subquery
Evidence
api_v2/views.py imports build_count_subquery, which forces importing dojo/query_utils.py. In
dojo/query_utils.py, the function definition itself refers to Subquery in the return annotation
and uses Subquery(...), Count(...), and IntegerField() without defining/importing those
symbols, causing an import-time failure.

dojo/api_v2/views.py[159-166]
dojo/query_utils.py[2-14]

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/query_utils.py` uses `Subquery`, `Count`, and `IntegerField` (and annotates `-> Subquery`) but does not import them, causing a `NameError` as soon as the module is imported.

### Issue Context
Multiple view modules import `build_count_subquery`, so this import-time error can prevent the app from starting.

### Fix Focus Areas
- dojo/query_utils.py[2-14]

### Suggested fix
Add the missing imports at module top, e.g.:
```py
from django.db.models import Count, IntegerField, Subquery
from django.db.models.query import QuerySet
```
(Keeping the current implementation otherwise unchanged.)

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



Remediation recommended

6. Wrong note serializer input 🐞 Bug ≡ Correctness
Description
RiskAcceptanceViewSet.notes() (POST) builds NoteSerializer with a plain dict instead of the
saved Notes model instance, so the 201 response cannot include model fields (e.g., id,
timestamps, note_type, history) and won’t match the schema implied by NoteSerializer/GET
responses. This breaks clients that need the created note’s identifier or full representation.
Code

dojo/api_v2/views.py[R816-819]

+            serialized_note = serializers.NoteSerializer(
+                {"author": author, "entry": entry, "private": private},
+            )
+            return Response(serialized_note.data, status=status.HTTP_201_CREATED)
Evidence
The new endpoint returns NoteSerializer({"author": ..., ...}), but NoteSerializer is a
ModelSerializer over Notes with fields = "__all__"; a dict instance cannot supply the
persisted model fields like id, date, note_type, and history. The code already has the saved
note instance available and should serialize that instead.

dojo/api_v2/views.py[772-825]
dojo/api_v2/serializers.py[873-897]

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

### Issue description
`RiskAcceptanceViewSet.notes()` returns a newly-created note using `NoteSerializer` instantiated with a dict, not the saved `Notes` instance. This prevents the response from including persisted fields (id/date/history/note_type) and can violate the declared response schema.

### Issue Context
The code already creates and saves a `Notes` model instance named `note` before building the response.

### Fix Focus Areas
- dojo/api_v2/views.py[772-825]

### Suggested fix
Replace the dict-based serialization with model-instance serialization, including serializer context:
```py
serialized_note = serializers.NoteSerializer(note, context={"request": request})
return Response(serialized_note.data, status=status.HTTP_201_CREATED)
```
This returns the full representation (including `id`) consistent with `NoteSerializer` (fields="__all__").

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


Grey Divider

Qodo Logo

Comment thread dojo/jira/services.py
Comment on lines +95 to +166
def link_finding(request, finding, new_jira_issue_key):
"""
Link a finding to an existing Jira issue.

Wraps: jira_helper.finding_link_jira
"""
return _get_helper().finding_link_jira(request, finding, new_jira_issue_key)


def unlink_finding(request, finding):
"""
Unlink a finding from its Jira issue.

Wraps: jira_helper.finding_unlink_jira
"""
return _get_helper().finding_unlink_jira(request, finding)


def link_finding_group(request, finding_group, new_jira_issue_key):
"""
Link a finding group to an existing Jira issue.

Wraps: jira_helper.finding_group_link_jira
"""
return _get_helper().finding_group_link_jira(request, finding_group, new_jira_issue_key)


def unlink(request, obj):
"""
Unlink an object from its Jira issue.

Wraps: jira_helper.unlink_jira
"""
return _get_helper().unlink_jira(request, obj)


def push_status(obj, jira_instance, jira, issue, *, save=False):
"""
Push finding status to Jira.

Wraps: jira_helper.push_status_to_jira
"""
return _get_helper().push_status_to_jira(obj, jira_instance, jira, issue, save=save)


def update_issue(obj, *args, **kwargs):
"""
Update a Jira issue.

Wraps: jira_helper.update_jira_issue
"""
return _get_helper().update_jira_issue(obj, *args, **kwargs)


def process_project_form(request, instance=None, target=None, product=None, engagement=None):
"""
Process a Jira project configuration form.

Wraps: jira_helper.process_jira_project_form
"""
return _get_helper().process_jira_project_form(request, instance=instance, target=target,
product=product, engagement=engagement)


def process_epic_form(request, engagement=None):
"""
Process a Jira epic form.

Wraps: jira_helper.process_jira_epic_form
"""
return _get_helper().process_jira_epic_form(request, engagement=engagement)

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. dojo.jira.services accepts request 📘 Rule violation ⚙ Maintainability

New Jira service-layer functions accept Django request objects (and delegate request-driven form
processing), coupling services to HTTP/framework concerns. This violates the requirement that
services remain framework-agnostic and only accept domain objects/primitives.
Agent Prompt
## Issue description
`dojo/jira/services.py` exposes service functions that accept Django `request` objects (and request-driven form processing), violating the service-layer framework-agnostic requirement.

## Issue Context
Services should accept only domain objects/primitives and must not depend on HTTP concerns. Request/form handling should live in UI/API layers, which then call services with primitives/models.

## Fix Focus Areas
- dojo/jira/services.py[95-166]

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

Comment thread dojo/api_v2/views.py
Comment on lines +783 to +825
@action(detail=True, methods=["get", "post"], permission_classes=(IsAuthenticated, permissions.UserHasRiskAcceptanceRelatedObjectPermission))
def notes(self, request, pk=None):
risk_acceptance = self.get_object()
if request.method == "POST":
new_note = serializers.AddNewNoteOptionSerializer(data=request.data)
if new_note.is_valid():
entry = new_note.validated_data["entry"]
private = new_note.validated_data.get("private", False)
note_type = new_note.validated_data.get("note_type", None)
else:
return Response(new_note.errors, status=status.HTTP_400_BAD_REQUEST)

notes = risk_acceptance.notes.filter(note_type=note_type).first()
if notes and note_type and note_type.is_single:
return Response("Only one instance of this note_type allowed on a risk acceptance.", status=status.HTTP_400_BAD_REQUEST)

author = request.user
note = Notes(entry=entry, author=author, private=private, note_type=note_type)
note.save()
history = NoteHistory.objects.create(data=note.entry, time=note.date, current_editor=note.author)
note.history.add(history)
risk_acceptance.notes.add(note)
engagement = risk_acceptance.engagement
if engagement:
process_tag_notifications(
request=request,
note=note,
parent_url=request.build_absolute_uri(
reverse("view_risk_acceptance", args=(engagement.id, risk_acceptance.id)),
),
parent_title=f"Risk Acceptance: {risk_acceptance.name}",
)

serialized_note = serializers.NoteSerializer(
{"author": author, "entry": entry, "private": private},
)
return Response(serialized_note.data, status=status.HTTP_201_CREATED)

notes = risk_acceptance.notes.all()
serialized_notes = serializers.RiskAcceptanceToNotesSerializer(
{"risk_acceptance_id": risk_acceptance, "notes": notes},
)
return Response(serialized_notes.data, status=status.HTTP_200_OK)
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. riskacceptanceviewset.notes() creates notes 📘 Rule violation ⚙ Maintainability

The new notes action performs multi-step note creation (saving Notes, creating NoteHistory,
and triggering process_tag_notifications) directly inside the API view. This is business workflow
logic that should be moved into a services.py layer, with the view acting as a thin delegator.
Agent Prompt
## Issue description
`RiskAcceptanceViewSet.notes()` contains business workflow logic (creating notes/history and dispatching tag notifications) inside the API layer.

## Issue Context
Per the architecture rules, views should handle transport concerns (auth, serializer validation, HTTP responses) and delegate domain workflows to a module service function.

## Fix Focus Areas
- dojo/api_v2/views.py[783-825]

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

Comment thread dojo/jira/forms.py
Comment on lines +1 to +20
import logging
import os
from pathlib import Path

from django import forms
from django.conf import settings
from django.core import validators
from django.core.exceptions import ValidationError
from django.urls import reverse

from dojo.jira import services as jira_services
from dojo.models import (
JIRA_Instance,
JIRA_Issue,
JIRA_Project,
)
from dojo.utils import (
get_system_setting,
is_finding_groups_enabled,
)
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. dojo/jira/forms.py not under ui/ 📘 Rule violation ⚙ Maintainability

Jira module UI forms were extracted into dojo/jira/forms.py instead of dojo/jira/ui/forms.py as
required by the module UI layering rules. This breaks the expected module layout and undermines
consistent UI separation across modules.
Agent Prompt
## Issue description
Jira UI forms are located at `dojo/jira/forms.py` rather than the required `dojo/jira/ui/forms.py`.

## Issue Context
The module layout standard requires UI-layer code (forms) under `ui/` to keep module roots focused on domain/services and to match the `dojo/url/` canonical structure.

## Fix Focus Areas
- dojo/jira/forms.py[1-404]
- dojo/forms.py[36-49]

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

Comment on lines +1 to +18
import json

from django.urls import reverse
from rest_framework import serializers

from dojo.jira import services as jira_services
from dojo.models import (
JIRA_Instance,
JIRA_Issue,
JIRA_Project,
)


class JIRAIssueSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField(read_only=True)

class Meta:
model = JIRA_Issue
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. dojo/jira/api/serializers.py wrong path 📘 Rule violation ⚙ Maintainability

Jira API serializers were added under dojo/jira/api/serializers.py rather than the required
dojo/jira/api/serializer.py. This deviates from the standardized extraction layout and can break
consistency/expectations for module API serializer placement.
Agent Prompt
## Issue description
Jira API serializers were added as `dojo/jira/api/serializers.py`, but the required standardized location is `dojo/jira/api/serializer.py`.

## Issue Context
The compliance standard expects a consistent filename/location across modules for serializer extraction to simplify discovery and re-export conventions.

## Fix Focus Areas
- dojo/jira/api/serializers.py[1-91]
- dojo/api_v2/serializers.py[1377-1381]

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

Comment thread dojo/api_v2/views.py
get_authorized_product_type_members,
get_authorized_product_types,
)
from dojo.query_utils import build_count_subquery
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. Query helper nameerror 🐞 Bug ≡ Correctness

dojo/query_utils.build_count_subquery references Subquery, Count, and IntegerField (and
annotates -> Subquery) without importing them, which triggers a NameError when the module is
imported. Because build_count_subquery is now imported/used by API views, this can break Django
startup and any endpoint module import that touches it.
Agent Prompt
### Issue description
`dojo/query_utils.py` uses `Subquery`, `Count`, and `IntegerField` (and annotates `-> Subquery`) but does not import them, causing a `NameError` as soon as the module is imported.

### Issue Context
Multiple view modules import `build_count_subquery`, so this import-time error can prevent the app from starting.

### Fix Focus Areas
- dojo/query_utils.py[2-14]

### Suggested fix
Add the missing imports at module top, e.g.:
```py
from django.db.models import Count, IntegerField, Subquery
from django.db.models.query import QuerySet
```
(Keeping the current implementation otherwise unchanged.)

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

Adds a per-user UI preference (UserContactInfo.ui_use_tailwind) so users
can opt into the redesigned Tailwind UI while the legacy Bootstrap
templates continue to render via a parallel `templates_classic/` tree
(loaded by `dojo/template_loaders.py`). Includes the migration, classic
copies of dojo.css/index.js/metrics.js, and a context-processor banner
inviting non-opted-in users to enable the new UI ahead of it becoming
the default on September 8th in the 2.62.0 release.

Also makes form widgets uniform width across the New/Edit pages for
Product Type, Product, Engagement, Test, Finding, Risk Acceptance, and
Finding Group: removes the legacy `width: 70% !important` boilerplate
duplicated across ~38 form templates and adds a single rule in
dojo.css that sizes EasyMDE, Select2 (incl. Tagulous tag inputs) and
Chosen widgets to fill their `.form-group` column at every viewport.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Maffooch Maffooch changed the title Merge updates from dev branch into tailwind branch Add UI toggle for classic Bootstrap fallback and align form field widths Apr 28, 2026
Maffooch and others added 2 commits April 29, 2026 12:55
Hoist deferred imports to module scope, replace try/except/pass with
contextlib.suppress, and collapse an if/else into a ternary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Tailwind login template uses `button.login-btn` while the classic
template uses `button.btn-success`; integration tests now match either.
Adds the Work Sans woff2 files (referenced by tailwind-out.css) under
dojo/static/dojo/css/files/ and a copy:fonts step in components/package.json
so future Tailwind builds keep them in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Maffooch Maffooch closed this Apr 29, 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.

1 participant