Skip to content

Conversation

@Ankit-singh-dot
Copy link
Contributor

@Ankit-singh-dot Ankit-singh-dot commented Dec 13, 2025

Closes #3314

Summary

Adds an initial Project Leaderboard page with tabbed views (Dashboard, Projects, Activity).

What’s included

  • New /project_leaderboard/ page
  • Aggregated project-level metrics from related repos
  • Simple tab-based UI using existing Tailwind styles
  • No schema changes, no React

Scope

This PR focuses on the initial backend + template wiring only.
Advanced features (filters, charts, caching) will be added in follow-up PRs.

Issue

Related to #3314

Summary by CodeRabbit

  • New Features

    • New Project Leaderboard page (Dashboard, Projects, Activity) accessible via its dedicated route.
  • UI

    • Client-side tabbed navigation for leaderboard with clear empty-state messages and per-item metrics.
  • Admin Enhancements

    • Superuser-only bulk user deactivation action; user admin shows activity status and hides the action for non-superusers.
  • Refactor

    • Internal middleware cleanup and tighter transaction/error handling (no user-facing behavior changes).

✏️ Tip: You can customize this high-level summary in your review settings.

Screenshot 2025-12-13 at 5 53 58 AM Screenshot 2025-12-13 at 5 53 53 AM

@github-actions
Copy link
Contributor

👋 Hi @Ankit-singh-dot!

This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:

  • The PR author
  • DonnieBLT
  • coderabbitai
  • copilot

Once a valid peer review is submitted, this check will pass automatically. Thank you!

@github-actions github-actions bot added the needs-peer-review PR needs peer review label Dec 13, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

Walkthrough

Adds a Project Leaderboard view, template, and URL; enhances User admin with superuser-only deactivate action and activity filter; and tightens IP-restriction middleware transaction handling, adds a test-mode guard, and stops network loop after a match.

Changes

Cohort / File(s) Summary
URL Routing
blt/urls.py
Imported ProjectLeaderboardView and added path("project_leaderboard/", ProjectLeaderboardView.as_view(), name="project_leaderboard") to urlpatterns.
Leaderboard View
website/views/project_leaderboard.py
New ProjectLeaderboardView(TemplateView) with template_name="projects/project_leaderboard.html". get_context_data prefetches repos, annotates projects with repo_count, total_stars, total_forks, open_issues, and builds dashboard_projects, projects, and activity lists with ordering and limits.
Leaderboard Template
website/templates/projects/project_leaderboard.html
New template implementing three-tab UI (Dashboard / Projects / Activity), iterating over context lists with {% empty %} fallbacks and client-side JS to switch tabs and manage active styles.
Admin: User Management
website/admin.py
Switched to get_user_model(), guarded admin.site.unregister(User) with NotRegistered, added CustomUserAdmin (extends DjangoUserAdmin), ActivityStatusFilter, and deactivate_users action restricted to superusers; registered CustomUserAdmin.
IP Restriction Middleware
blt/middleware/ip_restrict.py
Removed/condensed docstrings, added sys import and a test-mode guard in _record_ip (skip recording during tests), switched some DB updates to transaction.atomic(savepoint=True), tightened exception logging, consolidated cleanup, and changed loop behavior to break after finding a matching IP network.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Browser as Client (Browser)
participant View as Django View (ProjectLeaderboardView)
participant DB as Database (Project, Repo)
Note over View,DB: ORM: prefetch_related('repos') + annotate(repo_count, total_stars, total_forks, open_issues)
Browser->>View: GET /project_leaderboard/
View->>DB: Query Projects.prefetch_related(...).annotate(...)
DB-->>View: Annotated queryset
View-->>Browser: Rendered HTML (projects/project_leaderboard.html) with context lists
Note right of Browser: Client-side JS toggles tabs (Dashboard / Projects / Activity)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • website/admin.py — verify superuser gating for deactivate_users, safe unregister/register flow, ActivityStatusFilter behavior, and HTML rendering in activity_status.
  • website/views/project_leaderboard.py — confirm annotation expressions (aggregates), distinct counts, prefetch usage, ordering, and limit logic.
  • website/templates/projects/project_leaderboard.html — check tab controls accessibility, {% empty %} fallbacks, and JS robustness/resilience.
  • blt/middleware/ip_restrict.py — review transaction.savepoint usage, test-mode guard correctness, error logging changes, and early-exit after matching IP network.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR introduces out-of-scope middleware changes (blt/middleware/ip_restrict.py) unrelated to the leaderboard feature, including transaction handling refactoring and docstring removals to address test failures. Extract middleware fixes into a separate PR. This PR should focus solely on leaderboard functionality (views, templates, URL routing, and user admin enhancements for data access) without transaction management modifications.
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Linked Issues check ❓ Inconclusive The PR partially addresses issue #3314 by providing the initial scaffolding (backend view, template, URL routing, admin enhancements), but defers core acceptance criteria (comprehensive metrics aggregation, real-time updates, caching, advanced filtering/sorting, animations) to follow-up PRs. Clarify whether this PR is intended as a complete MVP or an initial foundation phase. If an MVP, ensure all core metrics and interactive features are implemented; if foundational, explicitly document planned follow-up deliverables in the PR description or issue tracker.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feature/project leaderboard UI' accurately describes the main change: introducing an initial Project Leaderboard with a tabbed UI and backend wiring.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the pre-commit: passed Pre-commit checks passed label Dec 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
website/templates/projects/project_leaderboard.html (1)

7-14: Add ARIA attributes for accessibility.

The tabbed interface is missing proper ARIA attributes for screen reader support. Consider adding role="tab", aria-selected, aria-controls on buttons, and role="tabpanel", aria-labelledby on content divs to meet WCAG accessibility standards.

Example enhancement for one tab button and panel:

-<button class="tab-btn px-4 py-2 text-sm rounded-md font-medium transition bg-red-600 text-white"
-        data-tab="dashboard">Dashboard</button>
+<button class="tab-btn px-4 py-2 text-sm rounded-md font-medium transition bg-red-600 text-white"
+        role="tab"
+        aria-selected="true"
+        aria-controls="dashboard"
+        data-tab="dashboard">Dashboard</button>

-<div id="dashboard" class="tab-content space-y-3">
+<div id="dashboard" class="tab-content space-y-3" role="tabpanel" aria-labelledby="dashboard-tab">

Apply similar changes to all tabs and update the JavaScript to toggle aria-selected when switching tabs.

Also applies to: 16-50

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between a187d4e and 49ec224.

📒 Files selected for processing (4)
  • blt/urls.py (2 hunks)
  • website/admin.py (3 hunks)
  • website/templates/projects/project_leaderboard.html (1 hunks)
  • website/views/project_leaderboard.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
website/views/project_leaderboard.py (1)
website/models.py (1)
  • open_issues (419-420)
website/admin.py (1)
website/models.py (1)
  • is_active (3329-3334)
blt/urls.py (1)
website/views/project_leaderboard.py (1)
  • ProjectLeaderboardView (7-24)
🪛 Ruff (0.14.8)
website/admin.py

107-107: Redefinition of unused User from line 10

(F811)


1303-1303: Unused method argument: request

(ARG002)


1303-1303: Unused method argument: model_admin

(ARG002)


1309-1309: Unused method argument: request

(ARG002)


1346-1346: Unused method argument: obj

(ARG002)


1349-1349: Unused method argument: obj

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (9)
website/admin.py (5)

1-1: LGTM: Dynamic user model loading.

Using get_user_model() and ClassVar is the correct approach for custom user models and provides better flexibility.

Also applies to: 107-108


1282-1297: LGTM: Admin action with proper authorization.

The deactivate_users action correctly restricts the operation to superusers and provides appropriate user feedback.


1299-1315: LGTM: Activity filter implementation.

The ActivityStatusFilter correctly filters users based on last_login presence. The static analysis warnings about unused parameters (request, model_admin) are false positives—Django's API requires these signatures.


1317-1320: LGTM: Defensive unregistration.

The try-except block properly handles the case where User might not be registered, preventing potential crashes.


1323-1364: LGTM: CustomUserAdmin with proper permission restrictions.

The implementation correctly:

  • Restricts all permissions to superusers
  • Conditionally displays the deactivate action
  • Renders activity status with visual indicators

The static analysis warnings about unused obj parameters in permission methods are false positives—Django's admin API requires this signature.

blt/urls.py (1)

303-303: LGTM: URL routing properly configured.

The import and URL pattern registration follow Django conventions correctly. The route is properly named for reverse URL lookups.

Also applies to: 401-405

website/templates/projects/project_leaderboard.html (2)

54-89: LGTM: Tab switching logic is correct.

The JavaScript properly handles:

  • Hiding all tab content
  • Resetting button styles
  • Showing the selected tab
  • Applying active styles

The implementation follows a clean pattern and handles dark mode styling correctly.


17-27: LGTM: Template properly renders context data with fallbacks.

The template correctly:

  • Loops through context variables (dashboard_projects, projects, activity)
  • Uses |default:0 filters for NULL-safe display
  • Provides empty state messages via {% empty %} blocks

Also applies to: 31-38, 42-49

website/views/project_leaderboard.py (1)

15-17: No action needed — Repo model fields are properly defined.

The stars, forks, and open_issues fields exist in the Repo model as IntegerField with default=0. The Sum aggregations are safe and will work correctly.

Comment on lines +13 to +22
projects = Project.objects.prefetch_related("repos").annotate(
repo_count=Count("repos", distinct=True),
total_stars=Sum("repos__stars"),
total_forks=Sum("repos__forks"),
open_issues=Sum("repos__open_issues"),
)

context["dashboard_projects"] = projects.order_by("-total_stars")[:20]
context["projects"] = projects.order_by("-repo_count")
context["activity"] = projects.order_by("-open_issues")
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Cache queryset to avoid multiple database queries.

The projects queryset is evaluated three times (lines 20-22), resulting in three separate database queries with identical annotations. Consider caching the queryset by converting it to a list after annotation.

Apply this diff:

-        projects = Project.objects.prefetch_related("repos").annotate(
+        projects = list(Project.objects.prefetch_related("repos").annotate(
             repo_count=Count("repos", distinct=True),
             total_stars=Sum("repos__stars"),
             total_forks=Sum("repos__forks"),
             open_issues=Sum("repos__open_issues"),
-        )
+        ))
 
         context["dashboard_projects"] = projects.order_by("-total_stars")[:20]
-        context["projects"] = projects.order_by("-repo_count")
-        context["activity"] = projects.order_by("-open_issues")
+        context["projects"] = sorted(projects, key=lambda p: p.repo_count or 0, reverse=True)
+        context["activity"] = sorted(projects, key=lambda p: p.open_issues or 0, reverse=True)

Note: This caches the queryset in memory and uses Python sorting instead of database ORDER BY. For large datasets, consider pagination or keeping database-level sorting with separate querysets.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In website/views/project_leaderboard.py around lines 13 to 22, the annotated
QuerySet is evaluated three times causing duplicate DB queries; convert/evaluate
the annotated QuerySet to an in-memory list once (e.g. list(projects)
immediately after annotate) and then produce the three context values by sorting
that cached list in Python (use stable/explicit keys and handle None values,
e.g. treat missing aggregates as 0), slice for the top 20 dashboard_projects,
and assign the other two sorted lists to context["projects"] and
context["activity"] to avoid repeated database hits.

@github-project-automation github-project-automation bot moved this from Backlog to Ready in 📌 OWASP BLT Project Board Dec 13, 2025
@github-actions
Copy link
Contributor

❌ Tests failed

The Django tests found issues that need to be fixed. Please review the test output below and fix the failing tests.

How to run tests locally

# Install dependencies
poetry install --with dev

# Run all tests
poetry run python manage.py test

# Run tests with verbose output
poetry run python manage.py test -v 3

# Run a specific test
poetry run python manage.py test app.tests.TestClass.test_method
Test output (last 100 lines)
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863/url {}
DEBUG http://localhost:35053 "GET /session/75c738351455dd1361a83c0d14cbd863/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"http://localhost:38663/report/#"} | headers=HTTPHeaderDict({'Content-Length': '43', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
ERROR
test_post_bug_domain_url (website.tests.test_main.MySeleniumTests.test_post_bug_domain_url) ... ERROR
DEBUG DELETE http://localhost:35053/session/75c738351455dd1361a83c0d14cbd863 {}
DEBUG http://localhost:35053 "DELETE /session/75c738351455dd1361a83c0d14cbd863 HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request

======================================================================
ERROR: test_post_bug_domain_url (website.tests.test_main.MySeleniumTests.test_post_bug_domain_url)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/test/utils.py", line 456, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/work/BLT/BLT/website/tests/test_main.py", line 222, in test_post_bug_domain_url
    WebDriverWait(self.selenium, 30).until(
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/selenium/webdriver/support/wait.py", line 146, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 


======================================================================
ERROR: test_post_bug_domain_url (website.tests.test_main.MySeleniumTests.test_post_bug_domain_url)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/__init__.py", line 194, in call_command
    return command.execute(*args, **defaults)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/base.py", line 460, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/commands/flush.py", line 52, in handle
    sql_list = sql_flush(
               ^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/sql.py", line 11, in sql_flush
    tables = connection.introspection.django_table_names(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 110, in django_table_names
    existing_tables = set(self.table_names(include_views=include_views))
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 57, in table_names
    return get_names(cursor)
           ^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 51, in get_names
    for ti in self.get_table_list(cursor)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/sqlite3/introspection.py", line 80, in get_table_list
    cursor.execute(
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 99, in _execute
    self.db.validate_no_broken_transaction()
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py", line 521, in validate_no_broken_transaction
    raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

----------------------------------------------------------------------
Ran 238 tests in 180.199s

FAILED (errors=2)
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...

For more information, see the Django testing documentation.

@github-actions github-actions bot added the tests: failed Django tests failed label Dec 13, 2025
@github-actions github-actions bot added the changes-requested PR has requested changes from a reviewer label Dec 13, 2025
Comment on lines +13 to +23
projects = Project.objects.prefetch_related("repos").annotate(
repo_count=Count("repos", distinct=True),
total_stars=Sum("repos__stars"),
total_forks=Sum("repos__forks"),
open_issues=Sum("repos__open_issues"),
)

context["dashboard_projects"] = projects.order_by("-total_stars")[:20]
context["projects"] = projects.order_by("-repo_count")
context["activity"] = projects.order_by("-open_issues")

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
website/admin.py (2)

342-342: Remove the unsafe unregister call.

Line 342 unregisters User without error handling, but Lines 1316-1320 now provide a safe try/except approach. The old unregister call should be removed to prevent potential crashes if User isn't registered by default.

Apply this diff:

-admin.site.unregister(User)

955-955: Remove the obsolete User registration.

Line 955 registers User with the old UserAdmin, but Line 1365 now registers User with the new CustomUserAdmin. Line 955 should be removed since it's replaced by the new implementation. The current flow creates an unnecessary register→unregister→register cycle.

Apply this diff:

-admin.site.register(User, UserAdmin)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 49ec224 and b8612d5.

📒 Files selected for processing (1)
  • website/admin.py (3 hunks)
🧰 Additional context used
🪛 Ruff (0.14.8)
website/admin.py

1302-1302: Unused method argument: request

(ARG002)


1302-1302: Unused method argument: model_admin

(ARG002)


1308-1308: Unused method argument: request

(ARG002)


1345-1345: Unused method argument: obj

(ARG002)


1348-1348: Unused method argument: obj

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (5)
website/admin.py (5)

1-1: LGTM!

The new imports are properly used throughout the file for the custom User admin implementation.

Also applies to: 6-9


106-107: LGTM!

Using get_user_model() is the correct Django pattern for dynamic User model resolution, ensuring compatibility with custom user models.


1281-1296: LGTM with note on defensive security.

The permission check inside the action (lines 1283-1289) provides defense-in-depth alongside the get_actions filter (lines 1351-1355), protecting against direct requests or programmatic calls.


1298-1314: LGTM!

The filter logic correctly distinguishes active (has logged in) from inactive (never logged in) users. The static analysis warnings about unused parameters are false positives—these are required by Django's SimpleListFilter API.


1322-1365: LGTM!

The CustomUserAdmin implementation is well-structured with proper permission restrictions, safe HTML rendering, and clear activity status indicators. The static analysis warnings about unused obj parameters are false positives—these are required by Django's admin permission method signatures.

@github-actions
Copy link
Contributor

❌ Tests failed

The Django tests found issues that need to be fixed. Please review the test output below and fix the failing tests.

How to run tests locally

# Install dependencies
poetry install --with dev

# Run all tests
poetry run python manage.py test

# Run tests with verbose output
poetry run python manage.py test -v 3

# Run a specific test
poetry run python manage.py test app.tests.TestClass.test_method
Test output (last 100 lines)
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py", line 1954, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py", line 93, in __iter__
    results = compiler.execute_sql(
              ^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1623, in execute_sql
    cursor.execute(sql, params)
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 122, in execute
    return super().execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 99, in _execute
    self.db.validate_no_broken_transaction()
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py", line 521, in validate_no_broken_transaction
    raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
DEBUG http://localhost:40767 "POST /session/b69eaa260d874c7240463f5c7b67ecc5/url HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG POST http://localhost:40767/session/b69eaa260d874c7240463f5c7b67ecc5/element {'using': 'tag name', 'value': 'body'}
DEBUG http://localhost:40767 "POST /session/b69eaa260d874c7240463f5c7b67ecc5/element HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":{"element-6066-11e4-a52e-4f735466cecf":"f.E9D0EEA8D3D8F77F9FB4856CF0338594.d.22DFB77E2DC57C5BFD09B99CD806CB3D.e.363"}} | headers=HTTPHeaderDict({'Content-Length': '127', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG POST http://localhost:40767/session/b69eaa260d874c7240463f5c7b67ecc5/element {'using': 'tag name', 'value': 'body'}
DEBUG http://localhost:40767 "POST /session/b69eaa260d874c7240463f5c7b67ecc5/element HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":{"element-6066-11e4-a52e-4f735466cecf":"f.E9D0EEA8D3D8F77F9FB4856CF0338594.d.22DFB77E2DC57C5BFD09B99CD806CB3D.e.363"}} | headers=HTTPHeaderDict({'Content-Length': '127', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
DEBUG GET http://localhost:40767/session/b69eaa260d874c7240463f5c7b67ecc5/element/f.E9D0EEA8D3D8F77F9FB4856CF0338594.d.22DFB77E2DC57C5BFD09B99CD806CB3D.e.363/text {}
DEBUG http://localhost:40767 "GET /session/b69eaa260d874c7240463f5c7b67ecc5/element/f.E9D0EEA8D3D8F77F9FB4856CF0338594.d.22DFB77E2DC57C5BFD09B99CD806CB3D.e.363/text HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":"TransactionManagementError at /all_activity/\nAn error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.\nRequest Method: GET\nRequest URL: http://localhost:34365/all_activity/\nDjango Version: 5.2.9\nException Type: TransactionManagementError\nException Value:\nAn error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.\nException Location: /home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py, line 521, in validate_no_broken_transaction\nRaised during: website.views.issue.AllIssuesView\nPython Executable: /home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/bin/python\nPython Version: 3.11.2\nPython Path:\n['/home/runner/work/BLT/BLT',\n '/opt/hostedtoolcache/Python/3.11.2/x64/lib/python311.zip',\n '/opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11',\n '/opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/lib-dynload',\n '/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages',\n '/home/runner/work/BLT/BLT']\nServer time: Sat, 13 Dec 2025 00:56:28 +0000\nTraceback Switch to copy-and-paste view\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/handlers/exception.py, line 55, in inner\n                response = get_response(request)\n                               ^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/utils/deprecation.py, line 119, in __call__\n            response = self.process_request(request)\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/tz_detect/middleware.py, line 15, in process_request\n        tz = request.session.get(\"detected_tz\")\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/base.py, line 74, in get\n        return self._session.get(key, default)\n                   ^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/base.py, line 249, in _get_session\n                self._session_cache = self.load()\n                                           ^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/db.py, line 55, in load\n        s = self._get_session_from_db()\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/db.py, line 34, in _get_session_from_db\n            return self.model.objects.get(\n                        \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/manager.py, line 87, in manager_method\n                return getattr(self.get_queryset(), name)(*args, **kwargs)\n                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 631, in get\n        num = len(clone)\n                   ^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 368, in __len__\n        self._fetch_all()\n             ^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 1954, in _fetch_all\n            self._result_cache = list(self._iterable_class(self))\n                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 93, in __iter__\n        results = compiler.execute_sql(\n                       \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/sql/compiler.py, line 1623, in execute_sql\n            cursor.execute(sql, params)\n                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 122, in execute\n            return super().execute(sql, params)\n                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 79, in execute\n        return self._execute_with_wrappers(\n                    \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 92, in _execute_with_wrappers\n        return executor(sql, params, many, context)\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 99, in _execute\n        self.db.validate_no_broken_transaction()\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py, line 521, in validate_no_broken_transaction\n            raise TransactionManagementError(\n                 ^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n\n\nRequest information\nUSER\n[unable to retrieve the current user]\nGET\nNo GET data\nPOST\nNo POST data\nFILES\nNo FILES data\nCOOKIES\nVariable Value\n_ga\n'GA1.1.1150880405.1765587378'\n_gid\n'GA1.1.1648915276.1765587378'\n_gat\n'1'\ncsrftoken\n'********************'\nsessionid\n'********************'\n_ga_TJDHVT49Y0\n'GS2.1.s1765587377$o1$g1$t1765587387$j50$l0$h0'\nMETA\nVariable Value\nACCEPT_EULA\n'Y'\nACTIONS_RUNNER_ACTION_ARCHIVE_CACHE\n'/opt/actionarchivecache'\nAGENT_TOOLSDIRECTORY\n'/opt/hostedtoolcache'\nANDROID_HOME\n'/usr/local/lib/android/sdk'\nANDROID_NDK\n'/usr/local/lib/android/sdk/ndk/27.3.13750724'\nANDROID_NDK_HOME\n'/usr/local/lib/android/sdk/ndk/27.3.13750724'\nANDROID_NDK_LATEST_HOME\n'/usr/local/lib/android/sdk/ndk/29.0.14206865'\nANDROID_NDK_ROOT\n'/usr/local/lib/android/sdk/ndk/27.3.13750724'\nANDROID_SDK_ROOT\n'/usr/local/lib/android/sdk'\nANT_HOME\n'/usr/share/ant'\nAZURE_EXTENSION_DIR\n'/opt/az/azcliextensions'\nBOOTSTRAP_HASKELL_NONINTERACTIVE\n'1'\nCHROMEWEBDRIVER\n'/usr/local/share/chromedriver-linux64'\nCHROME_BIN\n'/usr/bin/google-chrome'\nCI\n'true'\nCONDA\n'/usr/share/miniconda'\nCONTENT_LENGTH\n''\nCONTENT_TYPE\n'text/plain'\nCSRF_COOKIE\n'ED4kcxLLZTxxzu9fNSbtdyyrnCpTgh9U'\nDEBIAN_FRONTEND\n'noninteractive'\nDISPLAY\n':99'\nDJANGO_SETTINGS_MODULE\n'blt.settings'\nDOTNET_MULTILEVEL_LOOKUP\n'0'\nDOTNET_NOLOGO\n'1'\nDOTNET_SKIP_FIRST_TIME_EXPERIENCE\n'1'\nEDGEWEBDRIVER\n'/usr/local/share/edge_driver'\nENABLE_RUNNER_TRACING\n'true'\nFORCE_COLOR\n'1'\nGATEWAY_INTERFACE\n'CGI/1.1'\nGECKOWEBDRIVER\n'/usr/local/share/gecko_driver'\nGHCUP_INSTALL_BASE_PREFIX\n'/usr/local'\nGITHUB_ACTION\n'run-tests'\nGITHUB_ACTIONS\n'true'\nGITHUB_ACTION_REF\n''\nGITHUB_ACTION_REPOSITORY\n''\nGITHUB_ACTOR\n'Ankit-singh-dot'\nGITHUB_ACTOR_ID\n'183590562'\nGITHUB_API_URL\n'********************'\nGITHUB_BASE_REF\n'main'\nGITHUB_ENV\n'/home/runner/work/_temp/_runner_file_commands/set_env_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19'\nGITHUB_EVENT_NAME\n'pull_request_target'\nGITHUB_EVENT_PATH\n'/home/runner/work/_temp/_github_workflow/event.json'\nGITHUB_GRAPHQL_URL\n'https://api.github.com/graphql'\nGITHUB_HEAD_REF\n'feature/project-leaderboard-ui'\nGITHUB_JOB\n'test'\nGITHUB_OUTPUT\n'/home/runner/work/_temp/_runner_file_commands/set_output_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19'\nGITHUB_PATH\n'/home/runner/work/_temp/_runner_file_commands/add_path_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19'\nGITHUB_REF\n'refs/heads/main'\nGITHUB_REF_NAME\n'main'\nGITHUB_REF_PROTECTED\n'true'\nGITHUB_REF_TYPE\n'branch'\nGITHUB_REPOSITORY\n'OWASP-BLT/BLT'\nGITHUB_REPOSITORY_ID\n'62963654'\nGITHUB_REPOSITORY_OWNER\n'OWASP-BLT'\nGITHUB_REPOSITORY_OWNER_ID\n'160347863'\nGITHUB_RETENTION_DAYS\n'90'\nGITHUB_RUN_ATTEMPT\n'1'\nGITHUB_RUN_ID\n'20184112092'\nGITHUB_RUN_NUMBER\n'15619'\nGITHUB_SERVER_URL\n'https://github.com'\nGITHUB_SHA\n'a187d4ed4ba59e7c7ff0ac230111a178f6bac1a0'\nGITHUB_STATE\n'/home/runner/work/_temp/_runner_file_commands/save_state_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19'\nGITHUB_STEP_SUMMARY\n'/home/runner/work/_temp/_runner_file_commands/step_summary_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19'\nGITHUB_TRIGGERING_ACTOR\n'Ankit-singh-dot'\nGITHUB_WORKFLOW\n'CI/CD Optimized'\nGITHUB_WORKFLOW_REF\n'OWASP-BLT/BLT/.github/workflows/ci-cd.yml@refs/heads/main'\nGITHUB_WORKFLOW_SHA\n'a187d4ed4ba59e7c7ff0ac230111a178f6bac1a0'\nGITHUB_WORKSPACE\n'/home/runner/work/BLT/BLT'\nGOROOT_1_22_X64\n'/opt/hostedtoolcache/go/1.22.12/x64'\nGOROOT_1_23_X64\n'/opt/hostedtoolcache/go/1.23.12/x64'\nGOROOT_1_24_X64\n'/opt/hostedtoolcache/go/1.24.11/x64'\nGOROOT_1_25_X64\n'/opt/hostedtoolcache/go/1.25.5/x64'\nGRADLE_HOME\n'/usr/share/gradle-9.2.1'\nHOME\n'/home/runner'\nHOMEBREW_CLEANUP_PERIODIC_FULL_DAYS\n'3650'\nHOMEBREW_NO_AUTO_UPDATE\n'1'\nHTTP_ACCEPT\n'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'\nHTTP_ACCEPT_ENCODING\n'gzip, deflate, br, zstd'\nHTTP_ACCEPT_LANGUAGE\n'en-US,en;q=0.9'\nHTTP_CONNECTION\n'keep-alive'\nHTTP_COOKIE\n'********************'\nHTTP_HOST\n'localhost:34365'\nHTTP_SEC_CH_UA\n'\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"'\nHTTP_SEC_CH_UA_MOBILE\n'?0'\nHTTP_SEC_CH_UA_PLATFORM\n'\"Linux\"'\nHTTP_SEC_FETCH_DEST\n'document'\nHTTP_SEC_FETCH_MODE\n'navigate'\nHTTP_SEC_FETCH_SITE\n'none'\nHTTP_SEC_FETCH_USER\n'?1'\nHTTP_UPGRADE_INSECURE_REQUESTS\n'1'\nHTTP_USER_AGENT\n('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '\n 'HeadlessChrome/143.0.0.0 Safari/537.36')\nINVOCATION_ID\n'5c126686f80d498c82f6b72b652d2bb0'\nImageOS\n'ubuntu24'\nImageVersion\n'20251208.163.1'\nJAVA_HOME\n'/usr/lib/jvm/temurin-17-jdk-amd64'\nJAVA_HOME_11_X64\n'/usr/lib/jvm/temurin-11-jdk-amd64'\nJAVA_HOME_17_X64\n'/usr/lib/jvm/temurin-17-jdk-amd64'\nJAVA_HOME_21_X64\n'/usr/lib/jvm/temurin-21-jdk-amd64'\nJAVA_HOME_25_X64\n'/usr/lib/jvm/temurin-25-jdk-amd64'\nJAVA_HOME_8_X64\n'/usr/lib/jvm/temurin-8-jdk-amd64'\nJOURNAL_STREAM\n'9:11193'\nLANG\n'C.UTF-8'\nLD_LIBRARY_PATH\n'/opt/hostedtoolcache/Python/3.11.2/x64/lib'\nLOGNAME\n'runner'\nMEMORY_PRESSURE_WATCH\n'/sys/fs/cgroup/system.slice/hosted-compute-agent.service/memory.pressure'\nMEMORY_PRESSURE_WRITE\n'c29tZSAyMDAwMDAgMjAwMDAwMAA='\nNVM_DIR\n'/home/runner/.nvm'\nPATH\n'/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/bin:/opt/hostedtoolcache/Python/3.11.2/x64/bin:/opt/hostedtoolcache/Python/3.11.2/x64:/snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'\nPATH_INFO\n'/all_activity/'\nPIPX_BIN_DIR\n'/opt/pipx_bin'\nPIPX_HOME\n'/opt/pipx'\nPKG_CONFIG_PATH\n'/opt/hostedtoolcache/Python/3.11.2/x64/lib/pkgconfig'\nPOETRY_CACHE_DIR\n'~/.cache/pypoetry'\nPOWERSHELL_DISTRIBUTION_CHANNEL\n'GitHub-Actions-ubuntu24'\nPWD\n'/home/runner/work/BLT/BLT'\nPython2_ROOT_DIR\n'/opt/hostedtoolcache/Python/3.11.2/x64'\nPython3_ROOT_DIR\n'/opt/hostedtoolcache/Python/3.11.2/x64'\nPython_ROOT_DIR\n'/opt/hostedtoolcache/Python/3.11.2/x64'\nQUERY_STRING\n''\nREMOTE_ADDR\n'127.0.0.1'\nREMOTE_HOST\n''\nREQUEST_METHOD\n'GET'\nRUNNER_ARCH\n'X64'\nRUNNER_DEBUG\n'1'\nRUNNER_ENVIRONMENT\n'github-hosted'\nRUNNER_NAME\n'GitHub Actions 1000635303'\nRUNNER_OS\n'Linux'\nRUNNER_TEMP\n'/home/runner/work/_temp'\nRUNNER_TOOL_CACHE\n'/opt/hostedtoolcache'\nRUNNER_TRACKING_ID\n'github_430ce985-ee94-482b-a027-ebe768c56ac7'\nRUNNER_WORKSPACE\n'/home/runner/work/BLT'\nSCRIPT_NAME\n''\nSELENIUM_JAR_PATH\n'/usr/share/java/selenium-server.jar'\nSERVER_NAME\n'localhost'\nSERVER_PORT\n'34365'\nSERVER_PROTOCOL\n'HTTP/1.1'\nSERVER_SOFTWARE\n'WSGIServer/0.2'\nSGX_AESM_ADDR\n'1'\nSHELL\n'/bin/bash'\nSHLVL\n'1'\nSWIFT_PATH\n'/usr/share/swift/usr/bin'\nSYSTEMD_EXEC_PID\n'1921'\nTZ\n'UTC'\nUSER\n'runner'\nVCPKG_INSTALLATION_ROOT\n'/usr/local/share/vcpkg'\nVIRTUAL_ENV\n'/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11'\nXAUTHORITY\n'********************'\nXDG_CONFIG_HOME\n'/home/runner/.config'\nXDG_RUNTIME_DIR\n'/run/user/1001'\n_\n'/opt/hostedtoolcache/Python/3.11.2/x64/bin/poetry'\npythonLocation\n'/opt/hostedtoolcache/Python/3.11.2/x64'\nwsgi.errors\n\u003C_io.TextIOWrapper name='\u003Cstderr>' mode='w' encoding='utf-8'>\nwsgi.file_wrapper\n\u003Cclass 'wsgiref.util.FileWrapper'>\nwsgi.input\n\u003Cdjango.core.handlers.wsgi.LimitedStream object at 0x7fc1ead7d060>\nwsgi.multiprocess\nFalse\nwsgi.multithread\nTrue\nwsgi.run_once\nFalse\nwsgi.url_scheme\n'http'\nwsgi.version\n(1, 0)\nSettings\nUsing settings module None\nSetting Value\nABSOLUTE_URL_OVERRIDES\n{'auth.user': '********************'}\nACCESS_TOKEN\n'********************'\nACCESS_TOKEN_SECRET\n'********************'\nACCOUNT_ADAPTER\n'allauth.account.adapter.DefaultAccountAdapter'\nACCOUNT_EMAIL_REQUIRED\nTrue\nACCOUNT_EMAIL_VERIFICATION\n'mandatory'\nACCOUNT_FORMS\n{'signup': 'website.forms.SignupFormWithCaptcha'}\nACCOUNT_LOGOUT_ON_GET\nTrue\nACCOUNT_USERNAME_REQUIRED\nTrue\nADMINS\n(('Admin', 'blt-support@owasp.org'),)\nADMIN_URL\n'admin'\nALLOWED_HOSTS\n['127.0.0.1', 'localhost', '0.0.0.0', '', 'testserver']\nAPPEND_SLASH\nTrue\nAPP_KEY\n'********************'\nAPP_KEY_SECRET\n'********************'\nASGI_APPLICATION\n'blt.asgi.application'\nAUTHENTICATION_BACKENDS\n'********************'\nAUTH_PASSWORD_VALIDATORS\n'********************'\nAUTH_USER_MODEL\n'********************'\nAVATAR_PATH\n'media/avatars'\nBASE_DIR\n'/home/runner/work/BLT/BLT'\nBEARER_TOKEN\n'********************'\nBITCOIN_RPC_HOST\n'localhost'\nBITCOIN_RPC_PASSWORD\n'********************'\nBITCOIN_RPC_PORT\n'8332'\nBITCOIN_RPC_USER\n'yourusername'\nBLOG_URL\n'blt.owasp.org/blog/'\nBLUESKY_PASSWORD\n'********************'\nBLUESKY_USERNAME\n'default_username'\nCACHES\n{'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',\n             'LOCATION': 'unique-snowflake'}}\nCACHE_MIDDLEWARE_ALIAS\n'default'\nCACHE_MIDDLEWARE_KEY_PREFIX\n'********************'\nCACHE_MIDDLEWARE_SECONDS\n600\nCAPTCHA_TEST_MODE\nTrue\nCHANNEL_LAYERS\n{'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer',\n             'CONFIG': {'hosts': [None]}}}\nCONN_MAX_AGE\n0\nCSRF_COOKIE_AGE\n31449600\nCSRF_COOKIE_DOMAIN\nNone\nCSRF_COOKIE_HTTPONLY\nFalse\nCSRF_COOKIE_NAME\n'csrftoken'\nCSRF_COOKIE_PATH\n'/'\nCSRF_COOKIE_SAMESITE\n'Lax'\nCSRF_COOKIE_SECURE\nFalse\nCSRF_FAILURE_VIEW\n'django.views.csrf.csrf_failure'\nCSRF_HEADER_NAME\n'HTTP_X_CSRFTOKEN'\nCSRF_TRUSTED_ORIGINS\n[]\nCSRF_USE_SESSIONS\nFalse\nDATABASES\n{'default': {'ATOMIC_REQUESTS': False,\n             'AUTOCOMMIT': True,\n             'CONN_HEALTH_CHECKS': False,\n             'CONN_MAX_AGE': 0,\n             'ENGINE': 'django.db.backends.sqlite3',\n             'HOST': '',\n             'NAME': 'file:memorydb_default?mode=memory&cache=shared',\n             'OPTIONS': {},\n             'PASSWORD': '********************',\n             'PORT': '',\n             'TEST': {'CHARSET': None,\n                      'COLLATION': None,\n                      'MIGRATE': True,\n                      'MIRROR': None,\n                      'NAME': None},\n             'TIME_ZONE': None,\n             'USER': ''}}\nDATABASE_ROUTERS\n[]\nDATA_UPLOAD_MAX_MEMORY_SIZE\n2621440\nDATA_UPLOAD_MAX_NUMBER_FIELDS\n1000\nDATA_UPLOAD_MAX_NUMBER_FILES\n100\nDATETIME_FORMAT\n'N j, Y, P'\nDATETIME_INPUT_FORMATS\n['%Y-%m-%d %H:%M:%S',\n '%Y-%m-%d %H:%M:%S.%f',\n '%Y-%m-%d %H:%M',\n '%m/%d/%Y %H:%M:%S',\n '%m/%d/%Y %H:%M:%S.%f',\n '%m/%d/%Y %H:%M',\n '%m/%d/%y %H:%M:%S',\n '%m/%d/%y %H:%M:%S.%f',\n '%m/%d/%y %H:%M']\nDATE_FORMAT\n'N j, Y'\nDATE_INPUT_FORMATS\n['%Y-%m-%d',\n '%m/%d/%Y',\n '%m/%d/%y',\n '%b %d %Y',\n '%b %d, %Y',\n '%d %b %Y',\n '%d %b, %Y',\n '%B %d %Y',\n '%B %d, %Y',\n '%d %B %Y',\n '%d %B, %Y']\nDEBUG\nTrue\nDEBUG_PROPAGATE_EXCEPTIONS\nFalse\nDECIMAL_SEPARATOR\n'.'\nDEFAULT_AUTO_FIELD\n'django.db.models.AutoField'\nDEFAULT_CHARSET\n'utf-8'\nDEFAULT_EXCEPTION_REPORTER\n'django.views.debug.ExceptionReporter'\nDEFAULT_EXCEPTION_REPORTER_FILTER\n'django.views.debug.SafeExceptionReporterFilter'\nDEFAULT_FROM_EMAIL\n'blt-support@owasp.org'\nDEFAULT_INDEX_TABLESPACE\n''\nDEFAULT_TABLESPACE\n''\nDISALLOWED_USER_AGENTS\n[]\nDISCORD_BOT_TOKEN\n'********************'\nDOMAIN_NAME\n'blt.owasp.org'\nDOMAIN_NAME_PREVIOUS\n'BLT'\nEMAIL_BACKEND\n'django.core.mail.backends.locmem.EmailBackend'\nEMAIL_HOST\n'localhost'\nEMAIL_HOST_PASSWORD\n'********************'\nEMAIL_HOST_USER\n''\nEMAIL_PORT\n1025\nEMAIL_SSL_CERTFILE\nNone\nEMAIL_SSL_KEYFILE\n'********************'\nEMAIL_SUBJECT_PREFIX\n'[Django] '\nEMAIL_TIMEOUT\nNone\nEMAIL_TO_STRING\n'BLT \u003Cblt-support@owasp.org>'\nEMAIL_USE_LOCALTIME\nFalse\nEMAIL_USE_SSL\nFalse\nEMAIL_USE_TLS\nFalse\nENABLE_STAGING_REDIRECT\nFalse\nEXTENSION_URL\n'https://github.com/OWASP/BLT-Extension'\nFACEBOOK_URL\n'https://www.facebook.com/groups/owaspfoundation/'\nFILE_UPLOAD_DIRECTORY_PERMISSIONS\nNone\nFILE_UPLOAD_HANDLERS\n['django.core.files.uploadhandler.MemoryFileUploadHandler',\n 'django.core.files.uploadhandler.TemporaryFileUploadHandler']\nFILE_UPLOAD_MAX_MEMORY_SIZE\n2621440\nFILE_UPLOAD_PERMISSIONS\n420\nFILE_UPLOAD_TEMP_DIR\nNone\nFIRST_DAY_OF_WEEK\n0\nFIXTURE_DIRS\n[]\nFORCE_SCRIPT_NAME\nNone\nFORMAT_MODULE_PATH\nNone\nFORMS_URLFIELD_ASSUME_HTTPS\nFalse\nFORM_RENDERER\n'django.forms.renderers.DjangoTemplates'\nFQDN\n'blt.owasp.org'\nGITHUB_TOKEN\n'********************'\nGITHUB_URL\n'https://github.com/OWASP/BLT'\nIGNORABLE_404_URLS\n[]\nINSTALLED_APPS\n('django.contrib.admin',\n 'django.contrib.auth',\n 'django.contrib.contenttypes',\n 'django.contrib.sessions',\n 'django.contrib.messages',\n 'django.contrib.staticfiles',\n 'django.contrib.sites',\n 'django.contrib.humanize',\n 'website',\n 'allauth',\n 'allauth.account',\n 'allauth.socialaccount',\n 'allauth.socialaccount.providers.github',\n 'allauth.socialaccount.providers.facebook',\n 'allauth.socialaccount.providers.google',\n 'django_gravatar',\n 'email_obfuscator',\n 'import_export',\n 'comments',\n 'annoying',\n 'rest_framework',\n 'django_filters',\n 'rest_framework.authtoken',\n 'mdeditor',\n 'tz_detect',\n 'star_ratings',\n 'drf_yasg',\n 'captcha',\n 'dj_rest_auth',\n 'dj_rest_auth.registration',\n 'storages',\n 'channels')\nINTERNAL_IPS\n[]\nIS_TEST\nTrue\nLANGUAGES\n(('en', 'English'),\n ('fr', 'French'),\n ('zh-cn', 'Chinese'),\n ('de', 'German'),\n ('ja', 'Japanese'),\n ('ru', 'Russian'),\n ('hi', 'Hindi'))\nLANGUAGES_BIDI\n['he', 'ar', 'ar-dz', 'ckb', 'fa', 'ug', 'ur']\nLANGUAGE_CODE\n'en-us'\nLANGUAGE_COOKIE_AGE\nNone\nLANGUAGE_COOKIE_DOMAIN\nNone\nLANGUAGE_COOKIE_HTTPONLY\nFalse\nLANGUAGE_COOKIE_NAME\n'django_language'\nLANGUAGE_COOKIE_PATH\n'/'\nLANGUAGE_COOKIE_SAMESITE\nNone\nLANGUAGE_COOKIE_SECURE\nFalse\nLOCALE_PATHS\n('/home/runner/work/BLT/BLT/locale',)\nLOGGING\n{'disable_existing_loggers': False,\n 'formatters': {'simple': {'format': '%(levelname)s %(message)s'},\n                'verbose': {'format': '%(levelname)s %(asctime)s %(module)s '\n                                      '%(process)d %(thread)d %(message)s'}},\n 'handlers': {'console': {'class': 'logging.StreamHandler',\n                          'formatter': 'simple',\n                          'level': 'DEBUG',\n                          'stream': 'ext://sys.stdout'},\n              'mail_admins': {'class': 'django.utils.log.AdminEmailHandler',\n                              'level': 'ERROR'}},\n 'loggers': {'django': {'handlers': ['console', 'mail_admins'],\n                        'level': 'INFO',\n                        'propagate': True},\n             'django.server': {'handlers': ['console'],\n                               'level': 'INFO',\n                               'propagate': True},\n             'website': {'handlers': ['console'],\n                         'level': 'DEBUG',\n                         'propagate': True}},\n 'root': {'handlers': ['console'], 'level': 'DEBUG'},\n 'version': 1}\nLOGGING_CONFIG\n'logging.config.dictConfig'\nLOGIN_REDIRECT_URL\n'/'\nLOGIN_URL\n'/accounts/login/'\nLOGOUT_REDIRECT_URL\n'/'\nMANAGERS\n[]\nMDEDITOR_CONFIGS\n{'default': {'language': 'en',\n             'toolbar': ['undo',\n                         'redo',\n                         '|',\n                         'bold',\n                         'del',\n                         'italic',\n                         'quote',\n                         'ucwords',\n                         'uppercase',\n                         'lowercase',\n                         '|',\n                         'h1',\n                         'h2',\n                         'h3',\n                         'h5',\n                         'h6',\n                         '|',\n                         'list-ul',\n                         'list-ol',\n                         'hr',\n                         '|',\n                         'link',\n                         'reference-link',\n                         'code',\n                         'code-block',\n                         'table',\n                         'datetime',\n                         '||',\n                         'preview',\n                         'fullscreen'],\n             'watch': False}}\nMEDIA_ROOT\n'media'\nMEDIA_URL\n'/media/'\nMESSAGE_STORAGE\n'django.contrib.messages.storage.fallback.FallbackStorage'\nMIDDLEWARE\n['django.contrib.sessions.middleware.SessionMiddleware',\n 'blt.middleware.domain.DomainMiddleware',\n 'django.middleware.locale.LocaleMiddleware',\n 'django.middleware.common.CommonMiddleware',\n 'django.middleware.csrf.CsrfViewMiddleware',\n 'django.contrib.auth.middleware.AuthenticationMiddleware',\n 'django.contrib.messages.middleware.MessageMiddleware',\n 'allauth.account.middleware.AccountMiddleware',\n 'django.middleware.clickjacking.XFrameOptionsMiddleware',\n 'django.middleware.security.SecurityMiddleware',\n 'whitenoise.middleware.WhiteNoiseMiddleware',\n 'blt.middleware.throttling.ThrottlingMiddleware',\n 'tz_detect.middleware.TimezoneMiddleware',\n 'blt.middleware.ip_restrict.IPRestrictMiddleware',\n 'blt.middleware.user_visit_tracking.VisitTrackingMiddleware']\nMIGRATION_MODULES\n{}\nMONTH_DAY_FORMAT\n'F j'\nNUMBER_GROUPING\n0\nOPENAI_API_KEY\n'********************'\nORD_SERVER_URL\n'http://localhost:9001'\nPASSWORD_HASHERS\n'********************'\nPASSWORD_RESET_TIMEOUT\n'********************'\nPORT\n'8000'\nPREPEND_WWW\nFalse\nPRODUCTION_DOMAIN\n'blt.owasp.org'\nPROJECT_NAME\n'BLT'\nPROJECT_NAME_LOWER\n'blt'\nPROJECT_NAME_UPPER\n'BLT'\nPROJECT_ROOT\n'/home/runner/work/BLT/BLT/blt'\nREPORT_EMAIL\n'blank'\nREPORT_EMAIL_PASSWORD\n'********************'\nREST_AUTH\n'********************'\nREST_FRAMEWORK\n{'DEFAULT_AUTHENTICATION_CLASSES': '********************',\n 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n 'DEFAULT_THROTTLE_RATES': {'anon': '100000/day', 'user': '100000/day'},\n 'PAGE_SIZE': 10}\nROOT_URLCONF\n'blt.urls'\nSCOUT_KEY\n'********************'\nSCOUT_MONITOR\nTrue\nSCOUT_NAME\n'BLT'\nSECRET_KEY\n'********************'\nSECRET_KEY_FALLBACKS\n'********************'\nSECURE_CONTENT_TYPE_NOSNIFF\nTrue\nSECURE_CROSS_ORIGIN_OPENER_POLICY\n'same-origin'\nSECURE_HSTS_INCLUDE_SUBDOMAINS\nFalse\nSECURE_HSTS_PRELOAD\nFalse\nSECURE_HSTS_SECONDS\n0\nSECURE_PROXY_SSL_HEADER\n('HTTP_X_FORWARDED_PROTO', 'https')\nSECURE_REDIRECT_EXEMPT\n[]\nSECURE_REFERRER_POLICY\n'same-origin'\nSECURE_SSL_HOST\nNone\nSECURE_SSL_REDIRECT\nFalse\nSENTRY_DSN\nNone\nSERVER_EMAIL\n'blt-support@owasp.org'\nSESSION_CACHE_ALIAS\n'default'\nSESSION_COOKIE_AGE\n1209600\nSESSION_COOKIE_DOMAIN\nNone\nSESSION_COOKIE_HTTPONLY\nTrue\nSESSION_COOKIE_NAME\n'sessionid'\nSESSION_COOKIE_PATH\n'/'\nSESSION_COOKIE_SAMESITE\n'Lax'\nSESSION_COOKIE_SECURE\nFalse\nSESSION_ENGINE\n'django.contrib.sessions.backends.db'\nSESSION_EXPIRE_AT_BROWSER_CLOSE\nFalse\nSESSION_FILE_PATH\nNone\nSESSION_SAVE_EVERY_REQUEST\nFalse\nSESSION_SERIALIZER\n'django.contrib.sessions.serializers.JSONSerializer'\nSETTINGS_MODULE\nNone\nSHORT_DATETIME_FORMAT\n'm/d/Y P'\nSHORT_DATE_FORMAT\n'm/d/Y'\nSIGNING_BACKEND\n'django.core.signing.TimestampSigner'\nSILENCED_SYSTEM_CHECKS\n[]\nSITE_ID\n1\nSOCIALACCOUNT_ADAPTER\n'allauth.socialaccount.adapter.DefaultSocialAccountAdapter'\nSOCIALACCOUNT_PROVIDERS\n{'facebook': {'EXCHANGE_TOKEN': '********************',\n              'FIELDS': ['id',\n                         'email',\n                         'name',\n                         'first_name',\n                         'last_name',\n                         'verified',\n                         'locale',\n                         'timezone',\n                         'link'],\n              'LOCALE_FUNC': \u003Cfunction \u003Clambda> at 0x7fc209f17ec0>,\n              'METHOD': 'oauth2',\n              'SCOPE': ['email'],\n              'VERIFIED_EMAIL': False,\n              'VERSION': 'v7.0'},\n 'github': {'AUTH_PARAMS': '********************', 'SCOPE': ['user', 'repo']},\n 'google': {'AUTH_PARAMS': '********************',\n            'SCOPE': ['profile', 'email']}}\nSOCIALACCOUNT_STORE_TOKENS\n'********************'\nSOCIAL_AUTH_GITHUB_KEY\n'********************'\nSOCIAL_AUTH_GITHUB_SECRET\n'********************'\nSTAGING_DOMAIN\n'blt-staging.herokuapp.com'\nSTAR_RATINGS_RATING_MODEL\n'star_ratings.Rating'\nSTATICFILES_DIRS\n('/home/runner/work/BLT/BLT/website/static',)\nSTATICFILES_FINDERS\n['django.contrib.staticfiles.finders.FileSystemFinder',\n 'django.contrib.staticfiles.finders.AppDirectoriesFinder']\nSTATIC_ROOT\n'/home/runner/work/BLT/BLT/blt/staticfiles'\nSTATIC_URL\n'/static/'\nSTORAGES\n{'default': {'BACKEND': 'django.core.files.storage.FileSystemStorage'},\n 'staticfiles': {'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'}}\nSUPERUSERS\n(('admin123', 'admin123@gmail.com', 'admin@123'),)\nSUPERUSER_EMAIL\n'admin123@gmail.com'\nSUPERUSER_PASSWORD\n'********************'\nSUPERUSER_USERNAME\n'admin123'\nTEMPLATES\n[{'APP_DIRS': False,\n  'BACKEND': 'django.template.backends.django.DjangoTemplates',\n  'DIRS': ['/home/runner/work/BLT/BLT/website/templates'],\n  'OPTIONS': {'context_processors': ['django.template.context_processors.debug',\n                                     'django.template.context_processors.request',\n                                     'django.template.context_processors.media',\n                                     'django.contrib.auth.context_processors.auth',\n                                     'django.contrib.messages.context_processors.messages',\n                                     'django.template.context_processors.i18n'],\n              'debug': False,\n              'loaders': [('django.template.loaders.cached.Loader',\n                           ['django.template.loaders.filesystem.Loader',\n                            'django.template.loaders.app_directories.Loader'])]}}]\nTESTING\nTrue\nTEST_NON_SERIALIZED_APPS\n[]\nTEST_RUNNER\n'django.test.runner.DiscoverRunner'\nTHOUSAND_SEPARATOR\n','\nTHROTTLE_EXEMPT_PATHS\n['/admin/', '/static/', '/media/']\nTHROTTLE_LIMITS\n{'GET': 100, 'OTHER': 30, 'POST': 50}\nTHROTTLE_WINDOW\n60\nTIME_FORMAT\n'P'\nTIME_INPUT_FORMATS\n['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']\nTIME_ZONE\n'UTC'\nTWITTER_URL\n'https://x.com/owasp_blt'\nUSERS_AVATAR_PATH\n'avatars'\nUSE_I18N\nTrue\nUSE_L10N\nTrue\nUSE_THOUSAND_SEPARATOR\nFalse\nUSE_TZ\nTrue\nUSE_X_FORWARDED_HOST\nFalse\nUSE_X_FORWARDED_PORT\nFalse\nUSPTO_API\n'********************'\nWSGI_APPLICATION\nNone\nX_FRAME_OPTIONS\n'SAMEORIGIN'\nYEAR_MONTH_FORMAT\n'F Y'\nYou’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard page generated by the handler for this status code."} | headers=HTTPHeaderDict({'Content-Length': '28847', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request
FAIL
test_post_bug_full_url (website.tests.test_main.MySeleniumTests.test_post_bug_full_url) ... ERROR
DEBUG DELETE http://localhost:40767/session/b69eaa260d874c7240463f5c7b67ecc5 {}
DEBUG http://localhost:40767 "DELETE /session/b69eaa260d874c7240463f5c7b67ecc5 HTTP/1.1" 200 0
DEBUG Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
DEBUG Finished Request

======================================================================
ERROR: test_post_bug_full_url (website.tests.test_main.MySeleniumTests.test_post_bug_full_url)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/__init__.py", line 194, in call_command
    return command.execute(*args, **defaults)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/base.py", line 460, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/commands/flush.py", line 52, in handle
    sql_list = sql_flush(
               ^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/management/sql.py", line 11, in sql_flush
    tables = connection.introspection.django_table_names(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 110, in django_table_names
    existing_tables = set(self.table_names(include_views=include_views))
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 57, in table_names
    return get_names(cursor)
           ^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/introspection.py", line 51, in get_names
    for ti in self.get_table_list(cursor)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/sqlite3/introspection.py", line 80, in get_table_list
    cursor.execute(
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in execute
    return self._execute_with_wrappers(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py", line 99, in _execute
    self.db.validate_no_broken_transaction()
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py", line 521, in validate_no_broken_transaction
    raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

======================================================================
FAIL: test_post_bug_full_url (website.tests.test_main.MySeleniumTests.test_post_bug_full_url)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/test/utils.py", line 456, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/work/BLT/BLT/website/tests/test_main.py", line 185, in test_post_bug_full_url
    self.assertIn("XSS Attack on Google", body.text)
AssertionError: 'XSS Attack on Google' not found in 'TransactionManagementError at /all_activity/\nAn error occurred in the current transaction. You can\'t execute queries until the end of the \'atomic\' block.\nRequest Method: GET\nRequest URL: http://localhost:34365/all_activity/\nDjango Version: 5.2.9\nException Type: TransactionManagementError\nException Value:\nAn error occurred in the current transaction. You can\'t execute queries until the end of the \'atomic\' block.\nException Location: /home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py, line 521, in validate_no_broken_transaction\nRaised during: website.views.issue.AllIssuesView\nPython Executable: /home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/bin/python\nPython Version: 3.11.2\nPython Path:\n[\'/home/runner/work/BLT/BLT\',\n \'/opt/hostedtoolcache/Python/3.11.2/x64/lib/python311.zip\',\n \'/opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11\',\n \'/opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/lib-dynload\',\n \'/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages\',\n \'/home/runner/work/BLT/BLT\']\nServer time: Sat, 13 Dec 2025 00:56:28 +0000\nTraceback Switch to copy-and-paste view\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/core/handlers/exception.py, line 55, in inner\n                response = get_response(request)\n                               ^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/utils/deprecation.py, line 119, in __call__\n            response = self.process_request(request)\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/tz_detect/middleware.py, line 15, in process_request\n        tz = request.session.get("detected_tz")\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/base.py, line 74, in get\n        return self._session.get(key, default)\n                   ^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/base.py, line 249, in _get_session\n                self._session_cache = self.load()\n                                           ^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/db.py, line 55, in load\n        s = self._get_session_from_db()\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/contrib/sessions/backends/db.py, line 34, in _get_session_from_db\n            return self.model.objects.get(\n                        \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/manager.py, line 87, in manager_method\n                return getattr(self.get_queryset(), name)(*args, **kwargs)\n                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 631, in get\n        num = len(clone)\n                   ^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 368, in __len__\n        self._fetch_all()\n             ^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 1954, in _fetch_all\n            self._result_cache = list(self._iterable_class(self))\n                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/query.py, line 93, in __iter__\n        results = compiler.execute_sql(\n                       \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/models/sql/compiler.py, line 1623, in execute_sql\n            cursor.execute(sql, params)\n                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 122, in execute\n            return super().execute(sql, params)\n                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 79, in execute\n        return self._execute_with_wrappers(\n                    \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 92, in _execute_with_wrappers\n        return executor(sql, params, many, context)\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/utils.py, line 99, in _execute\n        self.db.validate_no_broken_transaction()\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/lib/python3.11/site-packages/django/db/backends/base/base.py, line 521, in validate_no_broken_transaction\n            raise TransactionManagementError(\n                 ^^^^^^^^^^^^^^^^^^^^^^^^ \n…\nLocal vars\n\n\nRequest information\nUSER\n[unable to retrieve the current user]\nGET\nNo GET data\nPOST\nNo POST data\nFILES\nNo FILES data\nCOOKIES\nVariable Value\n_ga\n\'GA1.1.1150880405.1765587378\'\n_gid\n\'GA1.1.1648915276.1765587378\'\n_gat\n\'1\'\ncsrftoken\n\'********************\'\nsessionid\n\'********************\'\n_ga_TJDHVT49Y0\n\'GS2.1.s1765587377$o1$g1$t1765587387$j50$l0$h0\'\nMETA\nVariable Value\nACCEPT_EULA\n\'Y\'\nACTIONS_RUNNER_ACTION_ARCHIVE_CACHE\n\'/opt/actionarchivecache\'\nAGENT_TOOLSDIRECTORY\n\'/opt/hostedtoolcache\'\nANDROID_HOME\n\'/usr/local/lib/android/sdk\'\nANDROID_NDK\n\'/usr/local/lib/android/sdk/ndk/27.3.13750724\'\nANDROID_NDK_HOME\n\'/usr/local/lib/android/sdk/ndk/27.3.13750724\'\nANDROID_NDK_LATEST_HOME\n\'/usr/local/lib/android/sdk/ndk/29.0.14206865\'\nANDROID_NDK_ROOT\n\'/usr/local/lib/android/sdk/ndk/27.3.13750724\'\nANDROID_SDK_ROOT\n\'/usr/local/lib/android/sdk\'\nANT_HOME\n\'/usr/share/ant\'\nAZURE_EXTENSION_DIR\n\'/opt/az/azcliextensions\'\nBOOTSTRAP_HASKELL_NONINTERACTIVE\n\'1\'\nCHROMEWEBDRIVER\n\'/usr/local/share/chromedriver-linux64\'\nCHROME_BIN\n\'/usr/bin/google-chrome\'\nCI\n\'true\'\nCONDA\n\'/usr/share/miniconda\'\nCONTENT_LENGTH\n\'\'\nCONTENT_TYPE\n\'text/plain\'\nCSRF_COOKIE\n\'ED4kcxLLZTxxzu9fNSbtdyyrnCpTgh9U\'\nDEBIAN_FRONTEND\n\'noninteractive\'\nDISPLAY\n\':99\'\nDJANGO_SETTINGS_MODULE\n\'blt.settings\'\nDOTNET_MULTILEVEL_LOOKUP\n\'0\'\nDOTNET_NOLOGO\n\'1\'\nDOTNET_SKIP_FIRST_TIME_EXPERIENCE\n\'1\'\nEDGEWEBDRIVER\n\'/usr/local/share/edge_driver\'\nENABLE_RUNNER_TRACING\n\'true\'\nFORCE_COLOR\n\'1\'\nGATEWAY_INTERFACE\n\'CGI/1.1\'\nGECKOWEBDRIVER\n\'/usr/local/share/gecko_driver\'\nGHCUP_INSTALL_BASE_PREFIX\n\'/usr/local\'\nGITHUB_ACTION\n\'run-tests\'\nGITHUB_ACTIONS\n\'true\'\nGITHUB_ACTION_REF\n\'\'\nGITHUB_ACTION_REPOSITORY\n\'\'\nGITHUB_ACTOR\n\'Ankit-singh-dot\'\nGITHUB_ACTOR_ID\n\'183590562\'\nGITHUB_API_URL\n\'********************\'\nGITHUB_BASE_REF\n\'main\'\nGITHUB_ENV\n\'/home/runner/work/_temp/_runner_file_commands/set_env_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19\'\nGITHUB_EVENT_NAME\n\'pull_request_target\'\nGITHUB_EVENT_PATH\n\'/home/runner/work/_temp/_github_workflow/event.json\'\nGITHUB_GRAPHQL_URL\n\'https://api.github.com/graphql\'\nGITHUB_HEAD_REF\n\'feature/project-leaderboard-ui\'\nGITHUB_JOB\n\'test\'\nGITHUB_OUTPUT\n\'/home/runner/work/_temp/_runner_file_commands/set_output_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19\'\nGITHUB_PATH\n\'/home/runner/work/_temp/_runner_file_commands/add_path_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19\'\nGITHUB_REF\n\'refs/heads/main\'\nGITHUB_REF_NAME\n\'main\'\nGITHUB_REF_PROTECTED\n\'true\'\nGITHUB_REF_TYPE\n\'branch\'\nGITHUB_REPOSITORY\n\'OWASP-BLT/BLT\'\nGITHUB_REPOSITORY_ID\n\'62963654\'\nGITHUB_REPOSITORY_OWNER\n\'OWASP-BLT\'\nGITHUB_REPOSITORY_OWNER_ID\n\'160347863\'\nGITHUB_RETENTION_DAYS\n\'90\'\nGITHUB_RUN_ATTEMPT\n\'1\'\nGITHUB_RUN_ID\n\'20184112092\'\nGITHUB_RUN_NUMBER\n\'15619\'\nGITHUB_SERVER_URL\n\'https://github.com\'\nGITHUB_SHA\n\'a187d4ed4ba59e7c7ff0ac230111a178f6bac1a0\'\nGITHUB_STATE\n\'/home/runner/work/_temp/_runner_file_commands/save_state_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19\'\nGITHUB_STEP_SUMMARY\n\'/home/runner/work/_temp/_runner_file_commands/step_summary_eb8f02f5-8e7c-45ec-9f6e-21a77bb44d19\'\nGITHUB_TRIGGERING_ACTOR\n\'Ankit-singh-dot\'\nGITHUB_WORKFLOW\n\'CI/CD Optimized\'\nGITHUB_WORKFLOW_REF\n\'OWASP-BLT/BLT/.github/workflows/ci-cd.yml@refs/heads/main\'\nGITHUB_WORKFLOW_SHA\n\'a187d4ed4ba59e7c7ff0ac230111a178f6bac1a0\'\nGITHUB_WORKSPACE\n\'/home/runner/work/BLT/BLT\'\nGOROOT_1_22_X64\n\'/opt/hostedtoolcache/go/1.22.12/x64\'\nGOROOT_1_23_X64\n\'/opt/hostedtoolcache/go/1.23.12/x64\'\nGOROOT_1_24_X64\n\'/opt/hostedtoolcache/go/1.24.11/x64\'\nGOROOT_1_25_X64\n\'/opt/hostedtoolcache/go/1.25.5/x64\'\nGRADLE_HOME\n\'/usr/share/gradle-9.2.1\'\nHOME\n\'/home/runner\'\nHOMEBREW_CLEANUP_PERIODIC_FULL_DAYS\n\'3650\'\nHOMEBREW_NO_AUTO_UPDATE\n\'1\'\nHTTP_ACCEPT\n\'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\'\nHTTP_ACCEPT_ENCODING\n\'gzip, deflate, br, zstd\'\nHTTP_ACCEPT_LANGUAGE\n\'en-US,en;q=0.9\'\nHTTP_CONNECTION\n\'keep-alive\'\nHTTP_COOKIE\n\'********************\'\nHTTP_HOST\n\'localhost:34365\'\nHTTP_SEC_CH_UA\n\'"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"\'\nHTTP_SEC_CH_UA_MOBILE\n\'?0\'\nHTTP_SEC_CH_UA_PLATFORM\n\'"Linux"\'\nHTTP_SEC_FETCH_DEST\n\'document\'\nHTTP_SEC_FETCH_MODE\n\'navigate\'\nHTTP_SEC_FETCH_SITE\n\'none\'\nHTTP_SEC_FETCH_USER\n\'?1\'\nHTTP_UPGRADE_INSECURE_REQUESTS\n\'1\'\nHTTP_USER_AGENT\n(\'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) \'\n \'HeadlessChrome/143.0.0.0 Safari/537.36\')\nINVOCATION_ID\n\'5c126686f80d498c82f6b72b652d2bb0\'\nImageOS\n\'ubuntu24\'\nImageVersion\n\'20251208.163.1\'\nJAVA_HOME\n\'/usr/lib/jvm/temurin-17-jdk-amd64\'\nJAVA_HOME_11_X64\n\'/usr/lib/jvm/temurin-11-jdk-amd64\'\nJAVA_HOME_17_X64\n\'/usr/lib/jvm/temurin-17-jdk-amd64\'\nJAVA_HOME_21_X64\n\'/usr/lib/jvm/temurin-21-jdk-amd64\'\nJAVA_HOME_25_X64\n\'/usr/lib/jvm/temurin-25-jdk-amd64\'\nJAVA_HOME_8_X64\n\'/usr/lib/jvm/temurin-8-jdk-amd64\'\nJOURNAL_STREAM\n\'9:11193\'\nLANG\n\'C.UTF-8\'\nLD_LIBRARY_PATH\n\'/opt/hostedtoolcache/Python/3.11.2/x64/lib\'\nLOGNAME\n\'runner\'\nMEMORY_PRESSURE_WATCH\n\'/sys/fs/cgroup/system.slice/hosted-compute-agent.service/memory.pressure\'\nMEMORY_PRESSURE_WRITE\n\'c29tZSAyMDAwMDAgMjAwMDAwMAA=\'\nNVM_DIR\n\'/home/runner/.nvm\'\nPATH\n\'/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11/bin:/opt/hostedtoolcache/Python/3.11.2/x64/bin:/opt/hostedtoolcache/Python/3.11.2/x64:/snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin\'\nPATH_INFO\n\'/all_activity/\'\nPIPX_BIN_DIR\n\'/opt/pipx_bin\'\nPIPX_HOME\n\'/opt/pipx\'\nPKG_CONFIG_PATH\n\'/opt/hostedtoolcache/Python/3.11.2/x64/lib/pkgconfig\'\nPOETRY_CACHE_DIR\n\'~/.cache/pypoetry\'\nPOWERSHELL_DISTRIBUTION_CHANNEL\n\'GitHub-Actions-ubuntu24\'\nPWD\n\'/home/runner/work/BLT/BLT\'\nPython2_ROOT_DIR\n\'/opt/hostedtoolcache/Python/3.11.2/x64\'\nPython3_ROOT_DIR\n\'/opt/hostedtoolcache/Python/3.11.2/x64\'\nPython_ROOT_DIR\n\'/opt/hostedtoolcache/Python/3.11.2/x64\'\nQUERY_STRING\n\'\'\nREMOTE_ADDR\n\'127.0.0.1\'\nREMOTE_HOST\n\'\'\nREQUEST_METHOD\n\'GET\'\nRUNNER_ARCH\n\'X64\'\nRUNNER_DEBUG\n\'1\'\nRUNNER_ENVIRONMENT\n\'github-hosted\'\nRUNNER_NAME\n\'GitHub Actions 1000635303\'\nRUNNER_OS\n\'Linux\'\nRUNNER_TEMP\n\'/home/runner/work/_temp\'\nRUNNER_TOOL_CACHE\n\'/opt/hostedtoolcache\'\nRUNNER_TRACKING_ID\n\'github_430ce985-ee94-482b-a027-ebe768c56ac7\'\nRUNNER_WORKSPACE\n\'/home/runner/work/BLT\'\nSCRIPT_NAME\n\'\'\nSELENIUM_JAR_PATH\n\'/usr/share/java/selenium-server.jar\'\nSERVER_NAME\n\'localhost\'\nSERVER_PORT\n\'34365\'\nSERVER_PROTOCOL\n\'HTTP/1.1\'\nSERVER_SOFTWARE\n\'WSGIServer/0.2\'\nSGX_AESM_ADDR\n\'1\'\nSHELL\n\'/bin/bash\'\nSHLVL\n\'1\'\nSWIFT_PATH\n\'/usr/share/swift/usr/bin\'\nSYSTEMD_EXEC_PID\n\'1921\'\nTZ\n\'UTC\'\nUSER\n\'runner\'\nVCPKG_INSTALLATION_ROOT\n\'/usr/local/share/vcpkg\'\nVIRTUAL_ENV\n\'/home/runner/.cache/pypoetry/virtualenvs/blt-yuw0N2NF-py3.11\'\nXAUTHORITY\n\'********************\'\nXDG_CONFIG_HOME\n\'/home/runner/.config\'\nXDG_RUNTIME_DIR\n\'/run/user/1001\'\n_\n\'/opt/hostedtoolcache/Python/3.11.2/x64/bin/poetry\'\npythonLocation\n\'/opt/hostedtoolcache/Python/3.11.2/x64\'\nwsgi.errors\n<_io.TextIOWrapper name=\'<stderr>\' mode=\'w\' encoding=\'utf-8\'>\nwsgi.file_wrapper\n<class \'wsgiref.util.FileWrapper\'>\nwsgi.input\n<django.core.handlers.wsgi.LimitedStream object at 0x7fc1ead7d060>\nwsgi.multiprocess\nFalse\nwsgi.multithread\nTrue\nwsgi.run_once\nFalse\nwsgi.url_scheme\n\'http\'\nwsgi.version\n(1, 0)\nSettings\nUsing settings module None\nSetting Value\nABSOLUTE_URL_OVERRIDES\n{\'auth.user\': \'********************\'}\nACCESS_TOKEN\n\'********************\'\nACCESS_TOKEN_SECRET\n\'********************\'\nACCOUNT_ADAPTER\n\'allauth.account.adapter.DefaultAccountAdapter\'\nACCOUNT_EMAIL_REQUIRED\nTrue\nACCOUNT_EMAIL_VERIFICATION\n\'mandatory\'\nACCOUNT_FORMS\n{\'signup\': \'website.forms.SignupFormWithCaptcha\'}\nACCOUNT_LOGOUT_ON_GET\nTrue\nACCOUNT_USERNAME_REQUIRED\nTrue\nADMINS\n((\'Admin\', \'blt-support@owasp.org\'),)\nADMIN_URL\n\'admin\'\nALLOWED_HOSTS\n[\'127.0.0.1\', \'localhost\', \'0.0.0.0\', \'\', \'testserver\']\nAPPEND_SLASH\nTrue\nAPP_KEY\n\'********************\'\nAPP_KEY_SECRET\n\'********************\'\nASGI_APPLICATION\n\'blt.asgi.application\'\nAUTHENTICATION_BACKENDS\n\'********************\'\nAUTH_PASSWORD_VALIDATORS\n\'********************\'\nAUTH_USER_MODEL\n\'********************\'\nAVATAR_PATH\n\'media/avatars\'\nBASE_DIR\n\'/home/runner/work/BLT/BLT\'\nBEARER_TOKEN\n\'********************\'\nBITCOIN_RPC_HOST\n\'localhost\'\nBITCOIN_RPC_PASSWORD\n\'********************\'\nBITCOIN_RPC_PORT\n\'8332\'\nBITCOIN_RPC_USER\n\'yourusername\'\nBLOG_URL\n\'blt.owasp.org/blog/\'\nBLUESKY_PASSWORD\n\'********************\'\nBLUESKY_USERNAME\n\'default_username\'\nCACHES\n{\'default\': {\'BACKEND\': \'django.core.cache.backends.locmem.LocMemCache\',\n             \'LOCATION\': \'unique-snowflake\'}}\nCACHE_MIDDLEWARE_ALIAS\n\'default\'\nCACHE_MIDDLEWARE_KEY_PREFIX\n\'********************\'\nCACHE_MIDDLEWARE_SECONDS\n600\nCAPTCHA_TEST_MODE\nTrue\nCHANNEL_LAYERS\n{\'default\': {\'BACKEND\': \'channels_redis.core.RedisChannelLayer\',\n             \'CONFIG\': {\'hosts\': [None]}}}\nCONN_MAX_AGE\n0\nCSRF_COOKIE_AGE\n31449600\nCSRF_COOKIE_DOMAIN\nNone\nCSRF_COOKIE_HTTPONLY\nFalse\nCSRF_COOKIE_NAME\n\'csrftoken\'\nCSRF_COOKIE_PATH\n\'/\'\nCSRF_COOKIE_SAMESITE\n\'Lax\'\nCSRF_COOKIE_SECURE\nFalse\nCSRF_FAILURE_VIEW\n\'django.views.csrf.csrf_failure\'\nCSRF_HEADER_NAME\n\'HTTP_X_CSRFTOKEN\'\nCSRF_TRUSTED_ORIGINS\n[]\nCSRF_USE_SESSIONS\nFalse\nDATABASES\n{\'default\': {\'ATOMIC_REQUESTS\': False,\n             \'AUTOCOMMIT\': True,\n             \'CONN_HEALTH_CHECKS\': False,\n             \'CONN_MAX_AGE\': 0,\n             \'ENGINE\': \'django.db.backends.sqlite3\',\n             \'HOST\': \'\',\n             \'NAME\': \'file:memorydb_default?mode=memory&cache=shared\',\n             \'OPTIONS\': {},\n             \'PASSWORD\': \'********************\',\n             \'PORT\': \'\',\n             \'TEST\': {\'CHARSET\': None,\n                      \'COLLATION\': None,\n                      \'MIGRATE\': True,\n                      \'MIRROR\': None,\n                      \'NAME\': None},\n             \'TIME_ZONE\': None,\n             \'USER\': \'\'}}\nDATABASE_ROUTERS\n[]\nDATA_UPLOAD_MAX_MEMORY_SIZE\n2621440\nDATA_UPLOAD_MAX_NUMBER_FIELDS\n1000\nDATA_UPLOAD_MAX_NUMBER_FILES\n100\nDATETIME_FORMAT\n\'N j, Y, P\'\nDATETIME_INPUT_FORMATS\n[\'%Y-%m-%d %H:%M:%S\',\n \'%Y-%m-%d %H:%M:%S.%f\',\n \'%Y-%m-%d %H:%M\',\n \'%m/%d/%Y %H:%M:%S\',\n \'%m/%d/%Y %H:%M:%S.%f\',\n \'%m/%d/%Y %H:%M\',\n \'%m/%d/%y %H:%M:%S\',\n \'%m/%d/%y %H:%M:%S.%f\',\n \'%m/%d/%y %H:%M\']\nDATE_FORMAT\n\'N j, Y\'\nDATE_INPUT_FORMATS\n[\'%Y-%m-%d\',\n \'%m/%d/%Y\',\n \'%m/%d/%y\',\n \'%b %d %Y\',\n \'%b %d, %Y\',\n \'%d %b %Y\',\n \'%d %b, %Y\',\n \'%B %d %Y\',\n \'%B %d, %Y\',\n \'%d %B %Y\',\n \'%d %B, %Y\']\nDEBUG\nTrue\nDEBUG_PROPAGATE_EXCEPTIONS\nFalse\nDECIMAL_SEPARATOR\n\'.\'\nDEFAULT_AUTO_FIELD\n\'django.db.models.AutoField\'\nDEFAULT_CHARSET\n\'utf-8\'\nDEFAULT_EXCEPTION_REPORTER\n\'django.views.debug.ExceptionReporter\'\nDEFAULT_EXCEPTION_REPORTER_FILTER\n\'django.views.debug.SafeExceptionReporterFilter\'\nDEFAULT_FROM_EMAIL\n\'blt-support@owasp.org\'\nDEFAULT_INDEX_TABLESPACE\n\'\'\nDEFAULT_TABLESPACE\n\'\'\nDISALLOWED_USER_AGENTS\n[]\nDISCORD_BOT_TOKEN\n\'********************\'\nDOMAIN_NAME\n\'blt.owasp.org\'\nDOMAIN_NAME_PREVIOUS\n\'BLT\'\nEMAIL_BACKEND\n\'django.core.mail.backends.locmem.EmailBackend\'\nEMAIL_HOST\n\'localhost\'\nEMAIL_HOST_PASSWORD\n\'********************\'\nEMAIL_HOST_USER\n\'\'\nEMAIL_PORT\n1025\nEMAIL_SSL_CERTFILE\nNone\nEMAIL_SSL_KEYFILE\n\'********************\'\nEMAIL_SUBJECT_PREFIX\n\'[Django] \'\nEMAIL_TIMEOUT\nNone\nEMAIL_TO_STRING\n\'BLT <blt-support@owasp.org>\'\nEMAIL_USE_LOCALTIME\nFalse\nEMAIL_USE_SSL\nFalse\nEMAIL_USE_TLS\nFalse\nENABLE_STAGING_REDIRECT\nFalse\nEXTENSION_URL\n\'https://github.com/OWASP/BLT-Extension\'\nFACEBOOK_URL\n\'https://www.facebook.com/groups/owaspfoundation/\'\nFILE_UPLOAD_DIRECTORY_PERMISSIONS\nNone\nFILE_UPLOAD_HANDLERS\n[\'django.core.files.uploadhandler.MemoryFileUploadHandler\',\n \'django.core.files.uploadhandler.TemporaryFileUploadHandler\']\nFILE_UPLOAD_MAX_MEMORY_SIZE\n2621440\nFILE_UPLOAD_PERMISSIONS\n420\nFILE_UPLOAD_TEMP_DIR\nNone\nFIRST_DAY_OF_WEEK\n0\nFIXTURE_DIRS\n[]\nFORCE_SCRIPT_NAME\nNone\nFORMAT_MODULE_PATH\nNone\nFORMS_URLFIELD_ASSUME_HTTPS\nFalse\nFORM_RENDERER\n\'django.forms.renderers.DjangoTemplates\'\nFQDN\n\'blt.owasp.org\'\nGITHUB_TOKEN\n\'********************\'\nGITHUB_URL\n\'https://github.com/OWASP/BLT\'\nIGNORABLE_404_URLS\n[]\nINSTALLED_APPS\n(\'django.contrib.admin\',\n \'django.contrib.auth\',\n \'django.contrib.contenttypes\',\n \'django.contrib.sessions\',\n \'django.contrib.messages\',\n \'django.contrib.staticfiles\',\n \'django.contrib.sites\',\n \'django.contrib.humanize\',\n \'website\',\n \'allauth\',\n \'allauth.account\',\n \'allauth.socialaccount\',\n \'allauth.socialaccount.providers.github\',\n \'allauth.socialaccount.providers.facebook\',\n \'allauth.socialaccount.providers.google\',\n \'django_gravatar\',\n \'email_obfuscator\',\n \'import_export\',\n \'comments\',\n \'annoying\',\n \'rest_framework\',\n \'django_filters\',\n \'rest_framework.authtoken\',\n \'mdeditor\',\n \'tz_detect\',\n \'star_ratings\',\n \'drf_yasg\',\n \'captcha\',\n \'dj_rest_auth\',\n \'dj_rest_auth.registration\',\n \'storages\',\n \'channels\')\nINTERNAL_IPS\n[]\nIS_TEST\nTrue\nLANGUAGES\n((\'en\', \'English\'),\n (\'fr\', \'French\'),\n (\'zh-cn\', \'Chinese\'),\n (\'de\', \'German\'),\n (\'ja\', \'Japanese\'),\n (\'ru\', \'Russian\'),\n (\'hi\', \'Hindi\'))\nLANGUAGES_BIDI\n[\'he\', \'ar\', \'ar-dz\', \'ckb\', \'fa\', \'ug\', \'ur\']\nLANGUAGE_CODE\n\'en-us\'\nLANGUAGE_COOKIE_AGE\nNone\nLANGUAGE_COOKIE_DOMAIN\nNone\nLANGUAGE_COOKIE_HTTPONLY\nFalse\nLANGUAGE_COOKIE_NAME\n\'django_language\'\nLANGUAGE_COOKIE_PATH\n\'/\'\nLANGUAGE_COOKIE_SAMESITE\nNone\nLANGUAGE_COOKIE_SECURE\nFalse\nLOCALE_PATHS\n(\'/home/runner/work/BLT/BLT/locale\',)\nLOGGING\n{\'disable_existing_loggers\': False,\n \'formatters\': {\'simple\': {\'format\': \'%(levelname)s %(message)s\'},\n                \'verbose\': {\'format\': \'%(levelname)s %(asctime)s %(module)s \'\n                                      \'%(process)d %(thread)d %(message)s\'}},\n \'handlers\': {\'console\': {\'class\': \'logging.StreamHandler\',\n                          \'formatter\': \'simple\',\n                          \'level\': \'DEBUG\',\n                          \'stream\': \'ext://sys.stdout\'},\n              \'mail_admins\': {\'class\': \'django.utils.log.AdminEmailHandler\',\n                              \'level\': \'ERROR\'}},\n \'loggers\': {\'django\': {\'handlers\': [\'console\', \'mail_admins\'],\n                        \'level\': \'INFO\',\n                        \'propagate\': True},\n             \'django.server\': {\'handlers\': [\'console\'],\n                               \'level\': \'INFO\',\n                               \'propagate\': True},\n             \'website\': {\'handlers\': [\'console\'],\n                         \'level\': \'DEBUG\',\n                         \'propagate\': True}},\n \'root\': {\'handlers\': [\'console\'], \'level\': \'DEBUG\'},\n \'version\': 1}\nLOGGING_CONFIG\n\'logging.config.dictConfig\'\nLOGIN_REDIRECT_URL\n\'/\'\nLOGIN_URL\n\'/accounts/login/\'\nLOGOUT_REDIRECT_URL\n\'/\'\nMANAGERS\n[]\nMDEDITOR_CONFIGS\n{\'default\': {\'language\': \'en\',\n             \'toolbar\': [\'undo\',\n                         \'redo\',\n                         \'|\',\n                         \'bold\',\n                         \'del\',\n                         \'italic\',\n                         \'quote\',\n                         \'ucwords\',\n                         \'uppercase\',\n                         \'lowercase\',\n                         \'|\',\n                         \'h1\',\n                         \'h2\',\n                         \'h3\',\n                         \'h5\',\n                         \'h6\',\n                         \'|\',\n                         \'list-ul\',\n                         \'list-ol\',\n                         \'hr\',\n                         \'|\',\n                         \'link\',\n                         \'reference-link\',\n                         \'code\',\n                         \'code-block\',\n                         \'table\',\n                         \'datetime\',\n                         \'||\',\n                         \'preview\',\n                         \'fullscreen\'],\n             \'watch\': False}}\nMEDIA_ROOT\n\'media\'\nMEDIA_URL\n\'/media/\'\nMESSAGE_STORAGE\n\'django.contrib.messages.storage.fallback.FallbackStorage\'\nMIDDLEWARE\n[\'django.contrib.sessions.middleware.SessionMiddleware\',\n \'blt.middleware.domain.DomainMiddleware\',\n \'django.middleware.locale.LocaleMiddleware\',\n \'django.middleware.common.CommonMiddleware\',\n \'django.middleware.csrf.CsrfViewMiddleware\',\n \'django.contrib.auth.middleware.AuthenticationMiddleware\',\n \'django.contrib.messages.middleware.MessageMiddleware\',\n \'allauth.account.middleware.AccountMiddleware\',\n \'django.middleware.clickjacking.XFrameOptionsMiddleware\',\n \'django.middleware.security.SecurityMiddleware\',\n \'whitenoise.middleware.WhiteNoiseMiddleware\',\n \'blt.middleware.throttling.ThrottlingMiddleware\',\n \'tz_detect.middleware.TimezoneMiddleware\',\n \'blt.middleware.ip_restrict.IPRestrictMiddleware\',\n \'blt.middleware.user_visit_tracking.VisitTrackingMiddleware\']\nMIGRATION_MODULES\n{}\nMONTH_DAY_FORMAT\n\'F j\'\nNUMBER_GROUPING\n0\nOPENAI_API_KEY\n\'********************\'\nORD_SERVER_URL\n\'http://localhost:9001\'\nPASSWORD_HASHERS\n\'********************\'\nPASSWORD_RESET_TIMEOUT\n\'********************\'\nPORT\n\'8000\'\nPREPEND_WWW\nFalse\nPRODUCTION_DOMAIN\n\'blt.owasp.org\'\nPROJECT_NAME\n\'BLT\'\nPROJECT_NAME_LOWER\n\'blt\'\nPROJECT_NAME_UPPER\n\'BLT\'\nPROJECT_ROOT\n\'/home/runner/work/BLT/BLT/blt\'\nREPORT_EMAIL\n\'blank\'\nREPORT_EMAIL_PASSWORD\n\'********************\'\nREST_AUTH\n\'********************\'\nREST_FRAMEWORK\n{\'DEFAULT_AUTHENTICATION_CLASSES\': \'********************\',\n \'DEFAULT_FILTER_BACKENDS\': (\'django_filters.rest_framework.DjangoFilterBackend\',),\n \'DEFAULT_PAGINATION_CLASS\': \'rest_framework.pagination.PageNumberPagination\',\n \'DEFAULT_THROTTLE_RATES\': {\'anon\': \'100000/day\', \'user\': \'100000/day\'},\n \'PAGE_SIZE\': 10}\nROOT_URLCONF\n\'blt.urls\'\nSCOUT_KEY\n\'********************\'\nSCOUT_MONITOR\nTrue\nSCOUT_NAME\n\'BLT\'\nSECRET_KEY\n\'********************\'\nSECRET_KEY_FALLBACKS\n\'********************\'\nSECURE_CONTENT_TYPE_NOSNIFF\nTrue\nSECURE_CROSS_ORIGIN_OPENER_POLICY\n\'same-origin\'\nSECURE_HSTS_INCLUDE_SUBDOMAINS\nFalse\nSECURE_HSTS_PRELOAD\nFalse\nSECURE_HSTS_SECONDS\n0\nSECURE_PROXY_SSL_HEADER\n(\'HTTP_X_FORWARDED_PROTO\', \'https\')\nSECURE_REDIRECT_EXEMPT\n[]\nSECURE_REFERRER_POLICY\n\'same-origin\'\nSECURE_SSL_HOST\nNone\nSECURE_SSL_REDIRECT\nFalse\nSENTRY_DSN\nNone\nSERVER_EMAIL\n\'blt-support@owasp.org\'\nSESSION_CACHE_ALIAS\n\'default\'\nSESSION_COOKIE_AGE\n1209600\nSESSION_COOKIE_DOMAIN\nNone\nSESSION_COOKIE_HTTPONLY\nTrue\nSESSION_COOKIE_NAME\n\'sessionid\'\nSESSION_COOKIE_PATH\n\'/\'\nSESSION_COOKIE_SAMESITE\n\'Lax\'\nSESSION_COOKIE_SECURE\nFalse\nSESSION_ENGINE\n\'django.contrib.sessions.backends.db\'\nSESSION_EXPIRE_AT_BROWSER_CLOSE\nFalse\nSESSION_FILE_PATH\nNone\nSESSION_SAVE_EVERY_REQUEST\nFalse\nSESSION_SERIALIZER\n\'django.contrib.sessions.serializers.JSONSerializer\'\nSETTINGS_MODULE\nNone\nSHORT_DATETIME_FORMAT\n\'m/d/Y P\'\nSHORT_DATE_FORMAT\n\'m/d/Y\'\nSIGNING_BACKEND\n\'django.core.signing.TimestampSigner\'\nSILENCED_SYSTEM_CHECKS\n[]\nSITE_ID\n1\nSOCIALACCOUNT_ADAPTER\n\'allauth.socialaccount.adapter.DefaultSocialAccountAdapter\'\nSOCIALACCOUNT_PROVIDERS\n{\'facebook\': {\'EXCHANGE_TOKEN\': \'********************\',\n              \'FIELDS\': [\'id\',\n                         \'email\',\n                         \'name\',\n                         \'first_name\',\n                         \'last_name\',\n                         \'verified\',\n                         \'locale\',\n                         \'timezone\',\n                         \'link\'],\n              \'LOCALE_FUNC\': <function <lambda> at 0x7fc209f17ec0>,\n              \'METHOD\': \'oauth2\',\n              \'SCOPE\': [\'email\'],\n              \'VERIFIED_EMAIL\': False,\n              \'VERSION\': \'v7.0\'},\n \'github\': {\'AUTH_PARAMS\': \'********************\', \'SCOPE\': [\'user\', \'repo\']},\n \'google\': {\'AUTH_PARAMS\': \'********************\',\n            \'SCOPE\': [\'profile\', \'email\']}}\nSOCIALACCOUNT_STORE_TOKENS\n\'********************\'\nSOCIAL_AUTH_GITHUB_KEY\n\'********************\'\nSOCIAL_AUTH_GITHUB_SECRET\n\'********************\'\nSTAGING_DOMAIN\n\'blt-staging.herokuapp.com\'\nSTAR_RATINGS_RATING_MODEL\n\'star_ratings.Rating\'\nSTATICFILES_DIRS\n(\'/home/runner/work/BLT/BLT/website/static\',)\nSTATICFILES_FINDERS\n[\'django.contrib.staticfiles.finders.FileSystemFinder\',\n \'django.contrib.staticfiles.finders.AppDirectoriesFinder\']\nSTATIC_ROOT\n\'/home/runner/work/BLT/BLT/blt/staticfiles\'\nSTATIC_URL\n\'/static/\'\nSTORAGES\n{\'default\': {\'BACKEND\': \'django.core.files.storage.FileSystemStorage\'},\n \'staticfiles\': {\'BACKEND\': \'django.contrib.staticfiles.storage.ManifestStaticFilesStorage\'}}\nSUPERUSERS\n((\'admin123\', \'admin123@gmail.com\', \'admin@123\'),)\nSUPERUSER_EMAIL\n\'admin123@gmail.com\'\nSUPERUSER_PASSWORD\n\'********************\'\nSUPERUSER_USERNAME\n\'admin123\'\nTEMPLATES\n[{\'APP_DIRS\': False,\n  \'BACKEND\': \'django.template.backends.django.DjangoTemplates\',\n  \'DIRS\': [\'/home/runner/work/BLT/BLT/website/templates\'],\n  \'OPTIONS\': {\'context_processors\': [\'django.template.context_processors.debug\',\n                                     \'django.template.context_processors.request\',\n                                     \'django.template.context_processors.media\',\n                                     \'django.contrib.auth.context_processors.auth\',\n                                     \'django.contrib.messages.context_processors.messages\',\n                                     \'django.template.context_processors.i18n\'],\n              \'debug\': False,\n              \'loaders\': [(\'django.template.loaders.cached.Loader\',\n                           [\'django.template.loaders.filesystem.Loader\',\n                            \'django.template.loaders.app_directories.Loader\'])]}}]\nTESTING\nTrue\nTEST_NON_SERIALIZED_APPS\n[]\nTEST_RUNNER\n\'django.test.runner.DiscoverRunner\'\nTHOUSAND_SEPARATOR\n\',\'\nTHROTTLE_EXEMPT_PATHS\n[\'/admin/\', \'/static/\', \'/media/\']\nTHROTTLE_LIMITS\n{\'GET\': 100, \'OTHER\': 30, \'POST\': 50}\nTHROTTLE_WINDOW\n60\nTIME_FORMAT\n\'P\'\nTIME_INPUT_FORMATS\n[\'%H:%M:%S\', \'%H:%M:%S.%f\', \'%H:%M\']\nTIME_ZONE\n\'UTC\'\nTWITTER_URL\n\'https://x.com/owasp_blt\'\nUSERS_AVATAR_PATH\n\'avatars\'\nUSE_I18N\nTrue\nUSE_L10N\nTrue\nUSE_THOUSAND_SEPARATOR\nFalse\nUSE_TZ\nTrue\nUSE_X_FORWARDED_HOST\nFalse\nUSE_X_FORWARDED_PORT\nFalse\nUSPTO_API\n\'********************\'\nWSGI_APPLICATION\nNone\nX_FRAME_OPTIONS\n\'SAMEORIGIN\'\nYEAR_MONTH_FORMAT\n\'F Y\'\nYou’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard page generated by the handler for this status code.'

----------------------------------------------------------------------
Ran 239 tests in 146.605s

FAILED (failures=1, errors=1)
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...

For more information, see the Django testing documentation.

@Ankit-singh-dot
Copy link
Contributor Author

@coderabbitai can you please tell me why my test case is failing i have check the pre-commit

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Get the PR check runs to see test failures
echo "=== Fetching PR check runs for #5275 ==="
gh pr checks 5275 --repo OWASP-BLT/BLT

echo -e "\n=== Fetching detailed logs for failed checks ==="
# Get more details about failed checks
gh pr view 5275 --repo OWASP-BLT/BLT --json statusCheckRollup --jq '.statusCheckRollup[] | select(.conclusion == "FAILURE" or .conclusion == "failure") | {name: .name, conclusion: .conclusion, detailsUrl: .detailsUrl}'

echo -e "\n=== Looking for test files ==="
# Find test files in the repository
fd -e py test_ | head -20

echo -e "\n=== Checking if there are tests for views ==="
fd -e py test.*view

echo -e "\n=== Checking for project-related tests ==="
rg -l "class.*Project.*Test" --type py

Length of output: 3653


🏁 Script executed:

#!/bin/bash

# Get the detailed logs from the failed test run
echo "=== Fetching detailed test failure logs ==="
gh run view 20184112092 --repo OWASP-BLT/BLT --log-failed

echo -e "\n=== Checking for any existing project leaderboard tests ==="
rg -n "project.*leaderboard" --type py -i

echo -e "\n=== Checking the new view file for any issues ==="
cat website/views/project_leaderboard.py

echo -e "\n=== Checking if Project model has the expected fields ==="
rg -n "class Project" --type py -A 30 website/models.py | head -50

Length of output: 7659


🏁 Script executed:

#!/bin/bash

# Get the actual test run logs, not just the failure step
echo "=== Fetching the actual test run output ==="
gh run view 20184112092 --repo OWASP-BLT/BLT --log | grep -A 50 "Run tests" | grep -B 5 -A 30 "FAILED\|ERROR\|Error"

echo -e "\n=== Searching for more specific test errors ==="
gh run view 20184112092 --repo OWASP-BLT/BLT --log | grep -B 3 -A 10 "test_.*FAILED\|ERROR.*test_\|AssertionError\|ImportError\|ModuleNotFoundError"

echo -e "\n=== Looking at the Run Tests job specifically ==="
gh api repos/OWASP-BLT/BLT/actions/runs/20184112092/jobs | jq '.jobs[] | select(.name == "Run Tests") | .steps[] | select(.conclusion == "failure") | {name: .name, number: .number}'

Length of output: 126508


🏁 Script executed:

#!/bin/bash

# Let's look at the IP restriction middleware that's causing the issue
echo "=== Checking the IP restriction middleware ==="
cat blt/middleware/ip_restrict.py | head -160 | tail -20

echo -e "\n=== Let's see if there are any recent changes to admin.py that might affect transactions ==="
git diff main HEAD -- website/admin.py | head -100

echo -e "\n=== Check if there are test database settings ==="
rg -n "TEST.*DATABASE\|ATOMIC_REQUESTS" --type py blt/settings.py website/tests/ | head -20

Length of output: 3958


@Ankit-singh-dot, I found the issue! Your tests are failing due to a transaction management problem in the IP restriction middleware, not because of your new project leaderboard code.

The Problem

The test failures show this error pattern:

  1. Initial error in blt/middleware/ip_restrict.py:

    ERROR Error recording IP 127.0.0.1: cannot start a transaction within a transaction
    
  2. Follow-up error in all subsequent database queries:

    TransactionManagementError: An error occurred in the current transaction. 
    You can't execute queries until the end of the 'atomic' block.
    

Root Cause

The _record_ip method in blt/middleware/ip_restrict.py uses with transaction.atomic() to record IP addresses. During tests:

  • Django's test framework already wraps each test in an atomic transaction
  • The middleware tries to start a nested transaction.atomic() block
  • SQLite (used in tests) rejects nested transactions
  • Once the transaction fails, it's marked as broken, causing all subsequent database queries to fail

The Fix

You need to make the IP recording middleware test-safe. Here's the fix for blt/middleware/ip_restrict.py:

def _record_ip(self, ip, agent, path):
    """
    Helper method to record IP information
    """
    # Skip IP recording during tests to avoid transaction conflicts
    from django.conf import settings
    if settings.TESTING or 'test' in sys.argv:
        return
        
    try:
        with transaction.atomic():
            # Check if we're in a broken transaction
            if transaction.get_rollback():
                logger.warning(f"Skipping IP recording for {ip} - transaction marked for rollback")
                return

            # ... rest of the existing code

Alternative fix (more robust): Use transaction.atomic(savepoint=True) and catch the exception:

def _record_ip(self, ip, agent, path):
    """
    Helper method to record IP information
    """
    try:
        # Use savepoint to handle nested transactions gracefully
        with transaction.atomic(savepoint=True):
            # Try to update existing record using atomic QuerySet.update() with F()
            updated = IP.objects.filter(address=ip, path=path).update(
                agent=agent,
                count=models.Case(
                    models.When(count__lt=MAX_COUNT, then=models.F("count") + 1),
                    default=models.Value(MAX_COUNT),
                    output_field=models.BigIntegerField(),
                ),
                # ... rest of your code
    except Exception as e:
        # Silently fail IP recording - it's not critical
        logger.debug(f"Could not record IP {ip}: {e}")

Summary

Your project leaderboard code is fine! The issue is pre-existing middleware code that doesn't handle the test environment properly. Apply one of the fixes above to blt/middleware/ip_restrict.py and your tests should pass.

@Ankit-singh-dot
Copy link
Contributor Author

@DonnieBLT my test case is failing because blt/middleware/ip_restrict.py should i resolve this or not because all test cases are being passed and cli approved
and for now i have kept database level ordering since this is the initial implementation and helps keep the logic straightforward. I’ll look into caching or optimization in a follow-up PR once we have a better idea of expected data size and pagination needs.

@github-actions github-actions bot added has-conflicts PR has merge conflicts that need to be resolved files-changed: 5 PR changes 5 files and removed files-changed: 4 PR changes 4 files labels Dec 13, 2025
Comment on lines +21 to +22
context["projects"] = projects.order_by("-repo_count")
context["activity"] = projects.order_by("-open_issues")

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
blt/middleware/ip_restrict.py (2)

66-73: Minor: Redundant None check in list comprehension.

The explicit if blocked_agent is not None check at line 72 is redundant since blocked_agents() already filters out None values at line 51.

Apply this diff to simplify:

     user_agent_str = str(user_agent).strip().lower()
     return any(
-        blocked_agent.lower() in user_agent_str for blocked_agent in blocked_agents if blocked_agent is not None
+        blocked_agent.lower() in user_agent_str for blocked_agent in blocked_agents
     )

99-100: Optional: Use explicit conversion flag in f-string.

Static analysis suggests using an explicit conversion flag for better clarity.

Apply this diff:

-            logger.error(f"Error incrementing block count: {str(e)}", exc_info=True)
+            logger.error(f"Error incrementing block count: {e!s}", exc_info=True)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between b8612d5 and cfb87ac.

📒 Files selected for processing (1)
  • blt/middleware/ip_restrict.py (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
blt/middleware/ip_restrict.py (1)
website/models.py (2)
  • Blocked (1479-1489)
  • IP (1122-1136)
🪛 Ruff (0.14.8)
blt/middleware/ip_restrict.py

100-100: Use explicit conversion flag

Replace with conversion flag

(RUF010)


137-137: Do not catch blind exception: Exception

(BLE001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run pre-commit
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (8)
blt/middleware/ip_restrict.py (8)

3-3: Approve the import addition.

The sys import is appropriately added to support the test-mode detection guard in _record_ip.


57-64: LGTM: Improved IP validation.

The added IP address validation prevents exceptions from invalid input and provides clear error logging before checking network ranges.


80-80: LGTM: Savepoint addresses nested transaction issue.

Using transaction.atomic(savepoint=True) correctly resolves the test failure caused by nested transactions, as discussed in the PR comments.


88-97: Verify user-agent matching logic is intentional.

The matching at line 92 checks if the blocked agent string is a substring of the incoming user_agent (agent.lower() in user_agent.lower()). This means a blocked agent "bot" would match "robot", "chatbot", etc. Confirm this substring matching is the intended behavior rather than exact matching.

Additionally, the null checks if agent and user_agent are good defensive guards, though agent is already filtered for None values in blocked_agents().


117-139: LGTM: Savepoint and error handling improvements.

The combination of savepoint=True at line 117 and the catch-and-suppress exception handling at lines 137-138 ensures IP logging never breaks requests or tests, which aligns with the docstring's promise. Logging at debug level is appropriate for non-critical tracking failures.


102-106: LGTM: Async implementation is correct.

The async methods properly delegate to their sync counterparts using sync_to_async, and the control flow correctly handles IP blocking, network range checking, and user-agent filtering.

Also applies to: 143-168


133-135: Verify duplicate deletion logic.

The duplicate cleanup deletes all but the first record (ordered by created) for a given IP/path combination. This approach is correct but will execute on every request where a duplicate exists. Consider if this is a common case that warrants logging or monitoring.

#!/bin/bash
# Check if duplicate IP records are a known issue in the codebase
rg -n "duplicate.*IP\|IP.*duplicate" --type=py -C2

25-30: The filter(None, queryset) is necessary and appropriate for all three cache keys.

The method is used for three different querysets:

  1. blocked_ips (line 34): address field - filtering None is safe; IP addresses should never be None
  2. blocked_ip_network (line 40): ip_network field - filtering None is necessary to prevent ValueError when ipaddress.ip_network(range_str) is called on line 42 with a None value
  3. blocked_agents (line 52): Already pre-filtered on line 51; the additional filter(None, ...) is redundant but harmless

The filtering is defensive programming that prevents crashes (especially for network ranges with malformed database entries) rather than optional cleanup.

Comment on lines +113 to +114
if "test" in sys.argv:
return
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Test detection is fragile; consider using Django's test runner detection.

The check if "test" in sys.argv may produce false positives (e.g., a file named "test.py" passed as argument) or false negatives (test runners that don't include "test" in argv). Django provides more reliable ways to detect test mode.

Consider using Django's official approach:

-        if "test" in sys.argv:
+        from django.conf import settings
+        if getattr(settings, 'TESTING', False):
             return

Then ensure your test settings include TESTING = True.

Alternatively, check the database connection:

-        if "test" in sys.argv:
+        from django.db import connection
+        if connection.settings_dict.get('NAME', '').startswith('test_'):
             return
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if "test" in sys.argv:
return
from django.conf import settings
if getattr(settings, 'TESTING', False):
return
🤖 Prompt for AI Agents
In blt/middleware/ip_restrict.py around lines 113-114, replace the fragile
sys.argv test with a Django-aware test detection: import django.conf.settings
and check getattr(settings, "TESTING", False) (i.e., if getattr(settings,
"TESTING", False): return). Update test configuration (or pytest/conftest) to
set TESTING = True during test runs; this avoids false positives/negatives from
argv and uses an explicit, reliable flag.

@github-actions github-actions bot added tests: passed Django tests passed and removed tests: failed Django tests failed labels Dec 13, 2025
@github-actions github-actions bot removed the has-conflicts PR has merge conflicts that need to be resolved label Dec 13, 2025
@Ankit-singh-dot
Copy link
Contributor Author

@DonnieBLT please review this pr have changed some testing file as coderabbit is suggesting and the CI failure was caused by nested transactions in ip_restrict middleware during django tests i made the middleware test-safe by using savepoints and skipping non-critical IP logging during tests. Production behavior remains unchanged.

please let me know if any-things required to fix or removed
thanks

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/admin.py (1)

342-342: Simplify User admin registration flow.

The current registration sequence creates unnecessary operations:

  1. Line 342: Unregister User (bare call, no exception handling)
  2. Line 955: Register User with default UserAdmin
  3. Lines 1316-1319: Unregister User again (with safe try/except)
  4. Line 1394: Register User with CustomUserAdmin

Since the goal is to use CustomUserAdmin (line 1394), line 955 should be removed. Additionally, line 342's bare unregister is redundant with the safer try/except version at lines 1316-1319.

Apply this diff:

-admin.site.unregister(User)
-

 
 # class UserAdmin(ImportExportModelAdmin):

And remove line 955:

 admin.site.register(UserProfile, UserProfileAdmin)
-admin.site.register(User, UserAdmin)
 admin.site.register(Domain, DomainAdminPanel)

This simplifies the flow to: safe unregister (lines 1316-1319) → register with CustomUserAdmin (line 1394).

Also applies to: 955-955, 1316-1319, 1394-1394

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5559831 and 79ce927.

📒 Files selected for processing (1)
  • website/admin.py (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run pre-commit
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (4)
website/admin.py (4)

1281-1295: LGTM: Proper permission checks and bulk operation.

The deactivate_users action correctly restricts deactivation to superusers and uses efficient bulk updates. The permission check is also enforced at the action-list level (lines 1360-1364), providing defense in depth.


1298-1313: LGTM: Clean filter implementation.

The ActivityStatusFilter follows Django admin conventions and provides a clear way to filter users by login activity. The logic correctly distinguishes between active (has logged in) and inactive (never logged in) users.


1328-1392: LGTM: Well-optimized admin implementation.

The CustomUserAdmin class demonstrates good practices:

  • Query optimization: Lines 1367-1372 use annotate() with Count() to compute activity metrics in a single query, preventing N+1 issues.
  • Proper permissions: Comprehensive superuser-only restrictions across module/view/change permissions.
  • Safe HTML rendering: Line 1388's format_html() safely renders styled status indicators.
  • Sortable metrics: admin_order_field attributes enable sorting by bug_count and forum_comment_count.

1281-1394: Past review concern about PR scope remains unaddressed.

A previous review comment noted that these User admin enhancements (activity filters, deactivation action, custom admin) are not clearly connected to the Project Leaderboard feature described in the PR objectives. That comment was not marked as addressed.

Per the previous review: "Consider moving unrelated changes to a separate PR for better traceability, or document why these admin changes are necessary for the leaderboard feature."

Please clarify whether these admin changes:

  1. Are a necessary prerequisite for the leaderboard feature (if so, document the dependency), or
  2. Should be split into a separate PR for better change tracking

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 79ce927 and ec2257a.

📒 Files selected for processing (1)
  • website/admin.py (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (4)
website/admin.py (4)

1-9: LGTM!

The import additions are appropriate and correctly used throughout the file:

  • ClassVar for type hints in the CustomUserAdmin
  • NotRegistered for safe unregistration
  • get_user_model() for dynamic User model resolution
  • DjangoUserAdmin aliased to avoid conflicts with the existing UserAdmin import

106-107: LGTM!

Using get_user_model() is the correct Django pattern for retrieving the User model dynamically, ensuring compatibility with custom user models.


1281-1295: LGTM!

The deactivate_users admin action is well-implemented with proper superuser permission checks and efficient bulk updates. The error handling and user feedback are appropriate.


1298-1313: LGTM!

The ActivityStatusFilter correctly filters users based on login activity using the last_login field. The implementation follows Django's SimpleListFilter pattern properly.

Comment on lines +1316 to +1365
try:
admin.site.unregister(User)
except NotRegistered:
pass


class CustomUserAdmin(DjangoUserAdmin):
actions: ClassVar[list] = [deactivate_users]

list_display = (
"username",
"email",
"is_active",
"activity_status",
"last_login",
"date_joined",
)

list_filter = (
"is_active",
ActivityStatusFilter,
)

search_fields = ("username", "email")
ordering = ("-last_login",)

def has_module_permission(self, request):
return request.user.is_superuser

def has_view_permission(self, request, obj=None):
return request.user.is_superuser

def has_change_permission(self, request, obj=None):
return request.user.is_superuser

def get_actions(self, request):
actions = super().get_actions(request)
if not request.user.is_superuser:
actions.pop("deactivate_users", None)
return actions

def activity_status(self, obj):
if obj.last_login:
return format_html('<span style="color: green; font-weight: 600;">Active</span>')
return format_html('<span style="color: red; font-weight: 600;">Inactive</span>')

activity_status.short_description = "Activity"


admin.site.register(User, CustomUserAdmin)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove redundant User registration at line 955.

The CustomUserAdmin implementation is well-designed with proper superuser-only access controls and the safe unregister pattern. However, line 955 registers User with the basic UserAdmin, and then line 1365 registers it again with CustomUserAdmin, resulting in the second registration overwriting the first.

To clean up this redundancy, remove line 955:

-admin.site.register(User, UserAdmin)

The proper registration with CustomUserAdmin at line 1365 will then be the only registration, making the code clearer and avoiding the redundant intermediate registration.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In website/admin.py around lines 1316 to 1365, remove the earlier redundant
registration of User at line 955 so the module only registers User once with
CustomUserAdmin at line 1365; locate and delete the standalone
admin.site.register(User) (or the block that registers User with the default
UserAdmin) at line 955, keep the safe unregister pattern and the CustomUserAdmin
class intact, and run tests / Django server to confirm no duplicate-registration
errors.

@Ankit-singh-dot
Copy link
Contributor Author

Ankit-singh-dot commented Dec 13, 2025

@DonnieBLT please review this pr by mistake pushed into wrong branch but fixed it now ..

I have changed some testing file as coderabbit is suggesting and the CI failure was caused by nested transactions in ip_restrict middleware during django tests i made the middleware test-safe by using savepoints and skipping non-critical IP logging during tests. Production behavior remains unchanged.

please let me know if any-things required to fix or removed
thanks

@DonnieBLT
Copy link
Collaborator

this should show some data - @nitinawari was working on this and had a good looking dashboard - please collaborate to work together or pickup

Copy link
Collaborator

@DonnieBLT DonnieBLT left a comment

Choose a reason for hiding this comment

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

limit changes only to the project leaderboard

blocked_ip_network.append(network)
except ValueError as e:
logger.error(f"Invalid IP network {range_str}: {str(e)}")
continue
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is this PR modifying anything in this file?

@DonnieBLT DonnieBLT added the d13 label Dec 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes-requested PR has requested changes from a reviewer d13 files-changed: 5 PR changes 5 files last-active: 0d PR last updated 0 days ago needs-peer-review PR needs peer review pre-commit: passed Pre-commit checks passed tests: passed Django tests passed

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

🏆 Feature Request: Engaging Project Leaderboard with Comprehensive Stats

2 participants