Skip to content

Conversation

@Nachiket-Roy
Copy link
Contributor

@Nachiket-Roy Nachiket-Roy commented Oct 14, 2025

Added more labs in security labs section closes #4784
2025-10-15_00-00
2025-10-15_00-01

To seed labs and their tasks simply run :
python manage.py seed_all_security_lab

Summary by CodeRabbit

  • Refactor

    • Restructured task detail page into clear, per-lab sections for payload exercises (SQLi, XSS, CSRF, Command Injection, Broken Auth, IDOR, File Upload, Sensitive Data Exposure, Open Redirect, SSRF)
    • Unified and simplified MCQ and simulation submission flows and result display with consistent styling driven by correctness
    • Minor formatting and structural template cleanups
  • Chores

    • Added a management command to seed the six security labs and their tasks for testing/dev environments

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactored the task detail template to replace nested per-lab conditionals with explicit blocks for multiple security lab types and unified MCQ/simulation result rendering and submission flow. Added a new Django management command to seed six security labs and their tasks within a single atomic transaction.

Changes

Cohort / File(s) Summary
UI Template Refactor
website/templates/task_detail.html
Reworked the "Try Your Payload" area: removed deep nested conditionals and introduced explicit per-lab sections (SQL Injection, XSS, CSRF, Command Injection, Broken Authentication, IDOR, File Upload, Sensitive Data Exposure, Open Redirect, SSRF). Expanded and renamed payload input labels/placeholders per lab, unified MCQ and simulation result rendering driven by data.correct, and consolidated simulation submission into a single payload flow. Minor whitespace/formatting and an SVG self-closing change.
New Management Command
website/management/commands/seed_all_security_lab.py
Added Command(BaseCommand) implementing handle to seed six security labs (IDOR, File Upload, Sensitive Data Exposure, Broken Authentication, Open Redirect, SSRF) and their theory/simulation tasks using an inlined labs_data structure and update_or_create within a DB transaction. Emits progress and summary counts.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
actor User
participant Browser
participant Template as task_detail.html
participant Server as Django
participant SeedCmd as manage.py seed_all_security_lab
Note over Browser,Template: MCQ or Simulation interaction
User->>Browser: open task page
Browser->>Template: render per-lab payload inputs & submit handlers
Browser->>Server: POST MCQ answer or simulation payload
Server-->>Browser: response with result { correct: true|false, message }
Browser->>Template: update unified result area (styled by data.correct)

mermaid
sequenceDiagram
autonumber
participant Dev
participant Shell
participant SeedCmd as seed_all_security_lab
participant DB
Dev->>Shell: python manage.py seed_all_security_lab
Shell->>SeedCmd: run Command.handle()
SeedCmd->>DB: begin transaction
loop for each lab
SeedCmd->>DB: update_or_create lab
loop for each task
SeedCmd->>DB: update_or_create task & content
end
end
SeedCmd->>DB: commit
SeedCmd-->>Shell: print progress and totals

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify each per-lab payload block in website/templates/task_detail.html for correct labels, placeholders, and conditionals.
  • Validate unified MCQ and simulation DOM updates and correctness-driven styling (edge cases, JS selectors).
  • Review website/management/commands/seed_all_security_lab.py for idempotency, transactional behavior, completeness of labs_data, and correct associations between labs, tasks, and content.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title is vague and repetitive, using generic phrasing 'Added Labs' and 'Added More Labs' that lacks specificity about what the change actually accomplishes. Revise the title to be more specific and concise, such as: 'Add security labs seeding command and update task detail template' or similar that clearly indicates the main changes.
Out of Scope Changes check ❓ Inconclusive The template changes appear to introduce additional refactoring (MCQ/simulation submission logic and result rendering consolidation) beyond the core objective of adding new labs and consolidating seeding. Clarify whether the MCQ/simulation logic refactoring in task_detail.html is necessary for the new labs or represents scope creep; consider separating template refactoring into a separate PR.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed All coding objectives from #4784 are met: the PR adds 6 new security labs (IDOR, File Upload, Sensitive Data Exposure, Broken Authentication, Open Redirect, SSRF), provides a consolidated seeding command, and updates the Security Labs page template.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent 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 5b4b14b and 160fb87.

📒 Files selected for processing (2)
  • website/management/commands/seed_all_security_lab.py (1 hunks)
  • website/templates/task_detail.html (4 hunks)
🧰 Additional context used
🪛 Ruff (0.14.4)
website/management/commands/seed_all_security_lab.py

10-10: Unused method argument: args

(ARG002)


10-10: Unused method argument: kwargs

(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 (3)
website/management/commands/seed_all_security_lab.py (2)

10-1173: Critical issues from previous reviews have been addressed.

Previous reviews flagged several critical problems (indentation causing tasks to seed only for the last lab, transaction handling, dict payload type mismatches, and TaskContent field cleanup). These have all been resolved in the current code:

  • Transaction wrapping is present (line 1178)
  • Task creation loop is properly indented inside the lab loop
  • All success_payload values are now strings
  • TaskContent fields for the opposite task type are explicitly cleared

The inline data structure spanning 1160+ lines remains a maintainability concern as previously noted, but this is a recommended refactor rather than a blocking issue.


10-10: False positive: unused parameters are part of Django's management command interface.

The static analysis tool flags args and kwargs as unused, but these are standard parameters in Django's BaseCommand.handle() signature and should remain even if not used.

website/templates/task_detail.html (1)

126-199: Explicit per-lab payload sections improve clarity.

The refactored payload input area now provides dedicated labels and placeholders for each of the security labs (SQL Injection, XSS, CSRF, Command Injection, Broken Authentication, IDOR, File Upload, Sensitive Data Exposure, Open Redirect, and SSRF). This explicit approach aligns well with the new labs seeded by seed_all_security_lab.py and makes the user experience clearer despite the verbosity.

Tip

📝 Customizable high-level summaries are now available!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide custom instructions to shape the summary (bullet lists, tables, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example:

"Create a concise high-level summary as a bullet-point list. Then include a Markdown table showing lines added and removed by each contributing author."


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.

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: 0

🧹 Nitpick comments (16)
website/templates/task_detail.html (1)

274-341: Client-side handlers are well-implemented.

The JavaScript submission handlers correctly:

  • Include CSRF tokens in fetch requests
  • Handle errors gracefully
  • Provide visual feedback for success/failure
  • Prevent default form submission

One minor suggestion: consider replacing alert() calls with inline error messages for better UX consistency with the existing result displays.

Optional: Replace alert() with inline error messages:

     .catch(error => {
         console.error('Error:', error);
-        alert('An error occurred. Please try again.');
+        const resultDiv = document.getElementById('mcq-result');
+        const messageDiv = document.getElementById('result-message');
+        resultDiv.classList.remove('hidden');
+        messageDiv.textContent = 'An error occurred. Please try again.';
+        messageDiv.className = 'text-sm font-medium text-red-600';
     });
website/management/commands/create_file_upload_tasks.py (3)

8-8: Unused method parameters.

The args and kwargs parameters are standard in Django management commands but unused here. While this is a minor nitpick, you can clean it up for consistency.

-    def handle(self, *args, **kwargs):
+    def handle(self, *args, **options):

Or simply acknowledge they're unused by the Django framework pattern.


222-222: Unused unpacked variable.

The task_content variable from update_or_create() is never used. Prefix it with an underscore to indicate it's intentionally ignored.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

1-237: Consider extracting common command logic.

All six new lab seed commands share nearly identical structure (get lab, upsert tasks, update total). Consider creating a base class or helper function to reduce duplication and improve maintainability.

Example base class approach:

class BaseLabTaskCommand(BaseCommand):
    lab_name: str
    tasks_data: list

    def handle(self, *args, **options):
        try:
            lab = Labs.objects.get(name=self.lab_name)
        except Labs.DoesNotExist:
            self.stdout.write(self.style.ERROR(f"{self.lab_name} lab not found. Please run create_initial_labs first."))
            return

        for task_data in self.tasks_data:
            task, created = Tasks.objects.update_or_create(...)
            # ... rest of common logic
        
        lab.update_total_tasks()
        self.stdout.write(self.style.SUCCESS(f"{self.lab_name} lab setup complete with {lab.total_tasks} tasks"))
website/management/commands/create_ssrf_tasks.py (3)

8-8: Unused method parameters.

Same issue as in other command files - args and kwargs are unused.


238-238: Unused unpacked variable.

Prefix task_content with underscore to indicate it's intentionally unused.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

27-27: Ambiguous quotation marks in strings.

Lines 27 and 59 use RIGHT SINGLE QUOTATION MARK (') instead of APOSTROPHE ('). While this won't break functionality, it can cause encoding issues in some contexts.

Replace ambiguous quotes:

  • Line 27: Server-Side Request Forgery (SSRF)? should use '
  • Line 59: user's browser should use '

Also applies to: 59-59

website/management/commands/create_open_redirect_tasks.py (2)

8-8: Unused method parameters.

The args and kwargs parameters are unused.


227-227: Unused unpacked variable.

Prefix task_content with underscore.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
website/management/commands/create_broken_auth_tasks.py (2)

8-8: Unused method parameters.

The args and kwargs parameters are unused.


327-327: Unused unpacked variable.

Prefix task_content with underscore.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
website/management/commands/create_data_exposure_tasks.py (2)

8-8: Unused method parameters.

The args and kwargs parameters are unused.


269-269: Unused unpacked variable.

Prefix task_content with underscore.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
website/management/commands/create_idor_tasks.py (3)

8-8: Unused method parameters.

The args and kwargs parameters are unused.


180-180: Unused unpacked variable.

Prefix task_content with underscore.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

63-63: Ambiguous quotation marks in strings.

Lines 63, 69, and 82 use RIGHT SINGLE QUOTATION MARK (') instead of APOSTROPHE (').

Replace with standard apostrophes for better encoding compatibility.

Also applies to: 69-69, 82-82

📜 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 82ad67c and 3698c10.

📒 Files selected for processing (8)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_initial_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
  • website/templates/task_detail.html (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.0)
website/management/commands/create_file_upload_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


222-222: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_data_exposure_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


269-269: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_idor_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


63-63: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


69-69: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


82-82: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


180-180: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_broken_auth_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


327-327: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_open_redirect_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


227-227: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_ssrf_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


27-27: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


59-59: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


238-238: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

⏰ 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 (3)
website/management/commands/create_initial_tasks.py (1)

36-71: LGTM! Clean expansion of lab definitions.

The new lab entries follow the established pattern and provide clear, educational descriptions. The estimated times and ordering are consistent with the existing structure.

website/templates/task_detail.html (2)

146-244: LGTM! Per-lab payload inputs are well-organized.

The conditional rendering of lab-specific payload inputs with contextual placeholders is a good UX pattern. The fallback generic textarea ensures all labs are covered.


48-48: No XSS risk: theory_content is admin-only
theory_content is only modifiable via Django admin or management commands, so rendering it with |safe does not expose untrusted input.

@github-project-automation github-project-automation bot moved this from Backlog to Ready in 📌 OWASP BLT Project Board Oct 14, 2025
@DonnieBLT DonnieBLT requested a review from Copilot October 14, 2025 21:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request adds six new security labs to the platform: Broken Authentication, IDOR, File Upload Vulnerabilities, Sensitive Data Exposure, Open Redirect, and SSRF. Each lab includes comprehensive theory and simulation tasks with MCQ questions and interactive payload testing.

Key Changes:

  • Added 6 new security vulnerability labs with educational content
  • Enhanced task detail template with dynamic per-lab payload inputs and improved UI
  • Created Django management commands to populate labs with theory and simulation tasks

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
website/templates/task_detail.html Enhanced with lab-specific payload inputs, improved layout, and refactored JavaScript handlers
website/management/commands/create_initial_tasks.py Added 6 new lab definitions with descriptions and estimated completion times
website/management/commands/create_broken_auth_tasks.py Complete task set for Broken Authentication lab covering default credentials, session fixation, JWT issues, and brute force
website/management/commands/create_idor_tasks.py IDOR lab tasks covering theory and simulation scenarios for object reference vulnerabilities
website/management/commands/create_file_upload_tasks.py File upload vulnerability tasks including web shell uploads, MIME type bypasses, and path traversal
website/management/commands/create_data_exposure_tasks.py Sensitive data exposure lab with theory and simulations for various data leak scenarios
website/management/commands/create_open_redirect_tasks.py Open redirect vulnerability lab covering phishing scenarios and bypass techniques
website/management/commands/create_ssrf_tasks.py SSRF lab tasks including internal access, redirection chains, and filter bypasses

@Nachiket-Roy Nachiket-Roy force-pushed the feature/added-more-labs branch from 3698c10 to 68ca240 Compare October 26, 2025 17:37
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: 3

♻️ Duplicate comments (1)
website/templates/task_detail.html (1)

274-341: Move inline JS to a static file and harden fetch handling.

Extract to website/static/js/task_detail.js (defer or module import) for CSP, caching, and maintainability. Also check response.ok and guard JSON parsing.

Apply this diff to improve robustness inline (if extraction deferred):

-    fetch("{% url 'submit_answer' lab.id task.id %}", {
+    fetch("{% url 'submit_answer' lab.id task.id %}", {
       method: 'POST',
       headers: {
         'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
         'Content-Type': 'application/x-www-form-urlencoded',
       },
       body: 'answer=' + encodeURIComponent(selectedAnswer)
     })
-    .then(response => response.json())
+    .then(async (response) => {
+        if (!response.ok) {
+            const text = await response.text().catch(() => '');
+            throw new Error(`HTTP ${response.status}: ${text.slice(0,200)}`);
+        }
+        const ct = response.headers.get('content-type') || '';
+        if (!ct.includes('application/json')) throw new Error('Unexpected response type');
+        return response.json();
+    })

Mirror the same pattern for the simulation fetch block.

🧹 Nitpick comments (25)
website/templates/task_detail.html (4)

60-67: Make MCQ option values explicit; avoid relying on first character.

Using value="{{ option.0 }}" assumes options start with “A)”, “B)”, etc. This is brittle for i18n or different option formats. Prefer explicit (value, text) pairs.

Apply this diff (template side), expecting content.mcq_options to be a list of 2-tuples like ("A", "Whitelist …"):

-{% for option in content.mcq_options %}
+{% for value, text in content.mcq_options %}
   <label class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer">
     <input type="radio"
            name="answer"
-           value="{{ option.0 }}"
+           value="{{ value }}"
            class="h-4 w-4 text-[#e74c3c] focus:ring-[#e74c3c] border-gray-300">
-    <span class="ml-3 text-sm text-gray-900">{{ option }}</span>
+    <span class="ml-3 text-sm text-gray-900">{{ text }}</span>
   </label>
{% endfor %}

If changing seed data isn’t feasible now, at least split on ') ' defensively in the template to extract the leading key.


145-244: Replace long {% elif %} chain on lab.name with config-driven rendering.

String-matching on display names is fragile (rename/i18n breaks it). Drive inputs from a stable code/slug or from content.simulation_config (e.g., input_type, placeholder).

Minimal diff showing slug usage:

-{% if lab.name == "SQL Injection" %}
+{% if lab.slug == "sqli" %}
...
-{% elif lab.name == "Cross-Site Scripting (XSS)" %}
+{% elif lab.slug == "xss" %}
...

Better: include in simulation_config:

-<form id="simulation-form">
+<form id="simulation-form" data-input-type="{{ content.simulation_config.input_type|default:'textarea' }}"
+      data-placeholder="{{ content.simulation_config.placeholder|default:'Enter your payload here...' }}">
...
-{% else %}
-  ... generic textarea ...
-{% endif %}
+{% if content.simulation_config.input_type == 'input' %}
+  <input id="payload" name="payload" type="text" ... placeholder="{{ content.simulation_config.placeholder }}">
+{% else %}
+  <textarea id="payload" name="payload" rows="4" ... placeholder="{{ content.simulation_config.placeholder }}"></textarea>
+{% endif %}

This removes the brittle name checks and reduces template size.


269-269: Remove empty layout stub.

<div class="mt-8 flex justify-between"></div> is empty and can be removed.


285-291: CSRF token lookup should target the relevant form.

document.querySelector('[name=csrfmiddlewaretoken]') returns the first token; safer to scope to the form in case multiple forms exist in future.

- 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
+ 'X-CSRFToken': form.querySelector('[name=csrfmiddlewaretoken]').value,

And for simulation:

- 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
+ 'X-CSRFToken': e.currentTarget.querySelector('[name=csrfmiddlewaretoken]').value,

Also applies to: 318-324

website/management/commands/create_file_upload_tasks.py (3)

8-8: Silence unused parameters.

handle(self, *args, **kwargs) doesn’t use args/kwargs. Rename to _args/_kwargs to satisfy Ruff ARG002.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

222-222: Prefix unused variable from update_or_create.

task_content isn’t used. Prefix with underscore to satisfy Ruff RUF059.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

8-16: Wrap seeding in a transaction for atomicity.

If any step fails midway, you can leave partially-updated tasks. Use transaction.atomic() to commit all-or-nothing.

+from django.db import transaction
...
-    def handle(self, *_args, **_kwargs):
+    def handle(self, *_args, **_kwargs):
+        with transaction.atomic():
             try:
                 upload_lab = Labs.objects.get(name="File Upload Vulnerabilities")
             except Labs.DoesNotExist:
                 self.stdout.write(
                     self.style.ERROR("File Upload Vulnerabilities lab not found. Please run create_initial_labs first.")
                 )
                 return
...
-        upload_lab.update_total_tasks()
-        self.stdout.write(
-            self.style.SUCCESS(f"File Upload Vulnerabilities lab setup complete with {upload_lab.total_tasks} tasks")
-        )
+        upload_lab.update_total_tasks()
+        self.stdout.write(self.style.SUCCESS(
+            f"File Upload Vulnerabilities lab setup complete with {upload_lab.total_tasks} tasks"))

Also applies to: 196-237, 234-237

website/management/commands/create_open_redirect_tasks.py (3)

8-8: Silence unused parameters.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

227-227: Prefix unused variable from update_or_create.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

8-14: Guard with transaction.atomic() for all-or-nothing seeding.

+from django.db import transaction
...
-    def handle(self, *_args, **_kwargs):
-        try:
+    def handle(self, *_args, **_kwargs):
+        with transaction.atomic():
+            try:
                 or_lab = Labs.objects.get(name="Open Redirect")
-        except Labs.DoesNotExist:
+            except Labs.DoesNotExist:
                 self.stdout.write(self.style.ERROR("Open Redirect lab not found. Please run create_initial_labs first."))
                 return
...
-        or_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"Open Redirect lab setup complete with {or_lab.total_tasks} tasks"))
+        or_lab.update_total_tasks()
+        self.stdout.write(self.style.SUCCESS(f"Open Redirect lab setup complete with {or_lab.total_tasks} tasks"))

Also applies to: 202-239

website/management/commands/create_ssrf_tasks.py (4)

8-8: Silence unused parameters.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

238-238: Prefix unused variable from update_or_create.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

25-54: Normalize curly quotes to ASCII for copy-paste fidelity.

Strings include (U+2019). Replace with ' to avoid issues in rendered HTML and linters (RUF001).

Example:

-<p>... user’s privileges ...</p>
+<p>... user's privileges ...</p>

Apply similarly across theory content blocks.

Also applies to: 57-63


8-18: Wrap entire seed in transaction.atomic().

+from django.db import transaction
...
-    def handle(self, *_args, **_kwargs):
-        try:
+    def handle(self, *_args, **_kwargs):
+        with transaction.atomic():
+            try:
                 ssrf_lab = Labs.objects.get(name="Server-Side Request Forgery (SSRF)")
-        except Labs.DoesNotExist:
+            except Labs.DoesNotExist:
                 self.stdout.write(
                     self.style.ERROR(
                         "Server-Side Request Forgery (SSRF) lab not found. Please run create_initial_labs first."
                     )
                 )
                 return
...
-        ssrf_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"SSRF lab setup complete with {ssrf_lab.total_tasks} tasks"))
+        ssrf_lab.update_total_tasks()
+        self.stdout.write(self.style.SUCCESS(f"SSRF lab setup complete with {ssrf_lab.total_tasks} tasks"))

Also applies to: 208-251

website/management/commands/create_broken_auth_tasks.py (3)

8-8: Silence unused parameters.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

327-327: Prefix unused variable from update_or_create.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

8-18: Use transaction.atomic() to ensure all-or-nothing task seeding.

+from django.db import transaction
...
-    def handle(self, *_args, **_kwargs):
-        try:
+    def handle(self, *_args, **_kwargs):
+        with transaction.atomic():
+            try:
                 auth_lab = Labs.objects.get(name="Broken Authentication")
-        except Labs.DoesNotExist:
+            except Labs.DoesNotExist:
                 self.stdout.write(
                     self.style.ERROR(
                         "Broken Authentication lab not found. Please run create_initial_labs first."
                     )
                 )
                 return
...
-        auth_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"Broken Authentication lab setup complete with {auth_lab.total_tasks} tasks"))
+        auth_lab.update_total_tasks()
+        self.stdout.write(self.style.SUCCESS(
+            f"Broken Authentication lab setup complete with {auth_lab.total_tasks} tasks"))

Also applies to: 302-340

website/management/commands/create_idor_tasks.py (4)

8-8: Silence lint for unused args/kwargs.

Rename to underscore-prefixed to appease Ruff ARG002.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

180-180: Prefix unused variable to satisfy Ruff RUF059.

The returned object isn’t used.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

1-3: Wrap seeding in a transaction for consistency.

Atomic ensures all tasks/content are applied together; avoids partial state if an error occurs mid‑loop.

-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand
+from django.db import transaction
@@
-        for task_data in tasks_data:
-            task, created = Tasks.objects.update_or_create(
+        with transaction.atomic():
+            for task_data in tasks_data:
+                task, created = Tasks.objects.update_or_create(
                 lab=idor_lab,
                 order=task_data["order"],
                 defaults={
                     "name": task_data["name"],
                     "description": task_data["description"],
                     "task_type": task_data["task_type"],
                     "is_active": True,
                 },
-            )
+                )
@@
-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+                _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
@@
-        idor_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"IDOR lab setup complete with {idor_lab.total_tasks} tasks"))
+        idor_lab.update_total_tasks()
+        idor_lab.refresh_from_db(fields=["total_tasks"])
+        self.stdout.write(self.style.SUCCESS(f"IDOR lab setup complete with {idor_lab.total_tasks} tasks"))

Also applies to: 155-193


192-193: Ensure printed total reflects DB value.

If update_total_tasks saves to DB, refresh the in‑memory object before printing.

-        idor_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"IDOR lab setup complete with {idor_lab.total_tasks} tasks"))
+        idor_lab.update_total_tasks()
+        idor_lab.refresh_from_db(fields=["total_tasks"])
+        self.stdout.write(self.style.SUCCESS(f"IDOR lab setup complete with {idor_lab.total_tasks} tasks"))
website/management/commands/create_data_exposure_tasks.py (4)

8-8: Silence lint for unused args/kwargs.

Rename to underscore‑prefixed names.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

269-269: Prefix unused variable to satisfy Ruff RUF059.

Discard the object; keep the created flag.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)

1-3: Make seeding atomic.

Apply a single transaction for consistent writes across tasks and contents.

-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand
+from django.db import transaction
@@
-        for task_data in tasks_data:
-            task, created = Tasks.objects.update_or_create(
+        with transaction.atomic():
+            for task_data in tasks_data:
+                task, created = Tasks.objects.update_or_create(
                 lab=sde_lab,
                 order=task_data["order"],
                 defaults={
                     "name": task_data["name"],
                     "description": task_data["description"],
                     "task_type": task_data["task_type"],
                     "is_active": True,
                 },
-            )
+                )
@@
-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+                _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
@@
-        sde_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"Sensitive Data Exposure lab setup complete with {sde_lab.total_tasks} tasks"))
+        sde_lab.update_total_tasks()
+        sde_lab.refresh_from_db(fields=["total_tasks"])
+        self.stdout.write(self.style.SUCCESS(f"Sensitive Data Exposure lab setup complete with {sde_lab.total_tasks} tasks"))

Also applies to: 239-282


281-282: Refresh before printing the total.

Guarantees the printed value matches DB state.

-        sde_lab.update_total_tasks()
-        self.stdout.write(self.style.SUCCESS(f"Sensitive Data Exposure lab setup complete with {sde_lab.total_tasks} tasks"))
+        sde_lab.update_total_tasks()
+        sde_lab.refresh_from_db(fields=["total_tasks"])
+        self.stdout.write(self.style.SUCCESS(f"Sensitive Data Exposure lab setup complete with {sde_lab.total_tasks} tasks"))
📜 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 3698c10 and 68ca240.

📒 Files selected for processing (8)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_initial_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
  • website/templates/task_detail.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/management/commands/create_initial_tasks.py
🧰 Additional context used
🪛 Ruff (0.14.1)
website/management/commands/create_idor_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


63-63: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


69-69: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


82-82: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


180-180: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_data_exposure_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


269-269: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_open_redirect_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


227-227: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_ssrf_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


27-27: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


59-59: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


238-238: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_file_upload_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


222-222: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_broken_auth_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


327-327: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

⏰ 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/management/commands/create_file_upload_tasks.py (1)

196-206: LGTM on idempotent upsert pattern.

Using update_or_create keyed by (lab, order) with clear defaults is correct and repeatable for seeds.

website/management/commands/create_open_redirect_tasks.py (1)

203-212: LGTM on idempotent upsert pattern.

website/management/commands/create_ssrf_tasks.py (1)

209-218: LGTM on idempotent upsert pattern.

website/management/commands/create_broken_auth_tasks.py (1)

303-312: LGTM on consistent upsert pattern and clear task metadata.

website/management/commands/create_idor_tasks.py (1)

1-193: No issues identified—all model contracts and lab names verified.

The code correctly uses lab names, task types, and TaskContent fields that are properly defined in the Django models. Labs.update_total_tasks() is called, and the conditional logic for populating theory versus simulation content aligns with the Tasks.TASK_TYPES choices.

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: 0

♻️ Duplicate comments (3)
website/management/commands/create_idor_tasks.py (3)

61-61: Replace curly quotes with straight apostrophes.

The curly quote in "it's" triggers RUF001. This issue was flagged in a previous review and remains unresolved.

Apply this diff:

-                <p>If changing these identifiers reveals unauthorized information, it's an IDOR vulnerability.</p>
+                <p>If changing these identifiers reveals unauthorized information, it's an IDOR vulnerability.</p>

67-67: Replace curly quotes with straight apostrophes.

The curly quote in "user B's" triggers RUF001. This issue was flagged in a previous review and remains unresolved.

Apply this diff:

-                <p>If user A can access user B's data by changing the ID, the endpoint lacks proper access control.</p>
+                <p>If user A can access user B's data by changing the ID, the endpoint lacks proper access control.</p>

80-80: Replace curly quotes with straight apostrophes.

The curly quote in "user's" triggers RUF001. This issue was flagged in a previous review and remains unresolved.

Apply this diff:

-                "description": "Try to access another user's profile by modifying the user_id parameter.",
+                "description": "Try to access another user's profile by modifying the user_id parameter.",
🧹 Nitpick comments (5)
website/management/commands/create_idor_tasks.py (3)

1-3: Consolidate imports from the same module.

Lines 1 and 3 import from the same module. Combine them for cleaner code.

Apply this diff:

-from django.core.management.base import BaseCommand
 from website.models import Labs, TaskContent, Tasks
-from django.core.management.base import CommandError
+from django.core.management.base import BaseCommand, CommandError

12-15: Consider exception chaining for traceback preservation.

While the current error handling is functional, using raise ... from exc preserves the exception chain for debugging.

Apply this diff:

-        except Labs.DoesNotExist:
+        except Labs.DoesNotExist as exc:
             raise CommandError(
                 "Insecure Direct Object Reference (IDOR) lab not found. Please run create_initial_labs first."
-            )
+            ) from exc

178-178: Prefix unused variable with underscore.

task_content is unpacked but never used. Signal this intent to silence RUF059.

Apply this diff:

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
website/management/commands/create_data_exposure_tasks.py (2)

9-15: Good fix! CommandError is now raised as requested in the past review.

The exception handling properly fails fast with a non-zero exit. One minor improvement: consider adding exception chaining to distinguish this from errors in exception handling itself.

Apply this diff to add proper exception chaining:

         except Labs.DoesNotExist:
-            raise CommandError(
+            raise CommandError(
                 "Sensitive Data Exposure lab not found. Please run create_initial_labs first."
-            )
+            ) from None

Note: The static analysis warning about unused args and kwargs parameters is a false positive—these are part of Django's management command signature.


237-267: Prefix unused variable with underscore.

The task creation logic is sound and uses update_or_create correctly for idempotency. However, the task_content variable on line 267 is unpacked but never used—only content_created is needed.

Apply this diff:

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
📜 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 68ca240 and 3ffce5b.

📒 Files selected for processing (2)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.1)
website/management/commands/create_idor_tasks.py

9-9: Unused method argument: args

(ARG002)


9-9: Unused method argument: kwargs

(ARG002)


13-15: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


13-15: Avoid specifying long messages outside the exception class

(TRY003)


178-178: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_data_exposure_tasks.py

9-9: Unused method argument: args

(ARG002)


9-9: Unused method argument: kwargs

(ARG002)


13-15: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


13-15: Avoid specifying long messages outside the exception class

(TRY003)


267-267: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

⏰ 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 (3)
website/management/commands/create_data_exposure_tasks.py (3)

1-8: LGTM! Command structure and imports are appropriate.

The imports include CommandError which is properly used later in the exception handling, and the command structure follows Django conventions.


17-235: Well-structured and comprehensive task definitions.

The tasks_data structure is thorough and educational, with a good mix of theory and simulation exercises. The HTML content is clean, MCQ questions are relevant, and simulation configs include helpful hints and clear success criteria.


269-282: LGTM! Output and finalization are well-implemented.

The output messages clearly distinguish between creation and updates, and the final call to update_total_tasks() ensures the lab's metadata stays current.

@Nachiket-Roy Nachiket-Roy force-pushed the feature/added-more-labs branch from 3ffce5b to dd63aba Compare November 9, 2025 18:04
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: 6

♻️ Duplicate comments (5)
website/management/commands/create_open_redirect_tasks.py (1)

1-240: Same code duplication issue as other seed commands.

This file has the identical structural duplication discussed in create_file_upload_tasks.py. A base class refactor would eliminate this repetition.

website/management/commands/create_ssrf_tasks.py (1)

1-251: Same code duplication issue as other seed commands.

This file has the identical structural duplication discussed in create_file_upload_tasks.py. A base class refactor would eliminate this repetition.

website/management/commands/create_idor_tasks.py (1)

1-191: Same code duplication issue as other seed commands.

This file has the identical structural duplication discussed in create_file_upload_tasks.py. A base class refactor would eliminate this repetition.

website/management/commands/create_broken_auth_tasks.py (1)

1-340: Same code duplication issue as other seed commands.

This file has the identical structural duplication discussed in create_file_upload_tasks.py. A base class refactor would eliminate this repetition.

website/management/commands/create_data_exposure_tasks.py (1)

1-282: Same code duplication issue as other seed commands.

This file has the identical structural duplication discussed in create_file_upload_tasks.py. A base class refactor would eliminate this repetition.

🧹 Nitpick comments (2)
website/management/commands/create_file_upload_tasks.py (2)

8-8: Clean up unused parameters.

The args and kwargs parameters are required by Django's command signature but unused here. Prefix with underscore to indicate they're intentionally unused.

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

222-222: Unused variable can be replaced with underscore.

The task_content variable is unpacked but never used.

-            task_content, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
+            _, content_created = TaskContent.objects.update_or_create(task=task, defaults=content_data)
📜 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 3ffce5b and dd63aba.

📒 Files selected for processing (8)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_initial_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
  • website/templates/task_detail.html (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
website/management/commands/create_file_upload_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


222-222: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_open_redirect_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


227-227: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_ssrf_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


27-27: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


59-59: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)


238-238: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_data_exposure_tasks.py

9-9: Unused method argument: args

(ARG002)


9-9: Unused method argument: kwargs

(ARG002)


13-15: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


13-15: Avoid specifying long messages outside the exception class

(TRY003)


267-267: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_broken_auth_tasks.py

8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


327-327: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

website/management/commands/create_idor_tasks.py

9-9: Unused method argument: args

(ARG002)


9-9: Unused method argument: kwargs

(ARG002)


13-15: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


13-15: Avoid specifying long messages outside the exception class

(TRY003)


178-178: Unpacked variable task_content is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

⏰ 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/management/commands/create_initial_tasks.py (1)

36-71: LGTM! Well-structured lab entries.

The six new lab definitions are clear, well-described, and properly sequenced. The estimated times and descriptions align well with the complexity of each security topic.

website/management/commands/create_idor_tasks.py (1)

13-15: Good use of CommandError for CI/automation.

This command correctly raises CommandError instead of returning, ensuring proper exit codes. This is the pattern the other seed commands should follow.

website/templates/task_detail.html (1)

1-342: Well-structured template refactor with clear per-lab inputs.

The template reorganization improves clarity by:

  • Separating theory, MCQ, and simulation sections into distinct cards
  • Providing lab-specific payload inputs with appropriate placeholders
  • Maintaining proper CSRF protection and error handling

The per-lab conditionals (lines 146-244) are appropriately tailored to each lab's requirements, with textareas for complex payloads and text inputs for simpler ones.

website/management/commands/create_data_exposure_tasks.py (1)

13-15: Good use of CommandError for CI/automation.

This command correctly raises CommandError instead of returning, ensuring proper exit codes. This is the pattern the other seed commands should follow.

@Nachiket-Roy
Copy link
Contributor Author

Nachiket-Roy commented Nov 9, 2025

@DonnieBLT Could you please review it when you get time and let me know if it’s ready to be merged, or if any further changes are needed?

Also, should I continue keeping this branch updated with periodic rebases until the PR is merged, or will that be handled during merge?

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: 0

♻️ Duplicate comments (1)
website/management/commands/create_ssrf_tasks.py (1)

16-16: Fix curly quote to satisfy linter.

Line 16 contains a RIGHT SINGLE QUOTATION MARK (') that triggers RUF001. Replace with a straight apostrophe.

Apply this diff:

-                <p>SSRF is a vulnerability that allows attackers to trick a server into making unintended HTTP requests. The attacker controls the target URL or request destination and uses the server's privileges to access internal systems or sensitive data.</p>
+                <p>SSRF is a vulnerability that allows attackers to trick a server into making unintended HTTP requests. The attacker controls the target URL or request destination and uses the server's privileges to access internal systems or sensitive data.</p>
🧹 Nitpick comments (8)
website/management/commands/base_lab_seeder.py (2)

11-12: Consider adding exception chaining for better error context.

When re-raising an exception during exception handling, using from None makes it explicit that this is intentional error conversion rather than a secondary error.

Apply this diff:

         except Labs.DoesNotExist:
-            raise CommandError(f"{self.lab_name} lab not found. Please run create_initial_tasks first.")
+            raise CommandError(f"{self.lab_name} lab not found. Please run create_initial_tasks first.") from None

5-6: Consider annotating mutable class attributes with ClassVar.

The linter flags tasks_data as a mutable class attribute. While each subclass overrides this, adding type annotations improves clarity and satisfies the linter.

Apply this diff:

+from typing import ClassVar
+
 class LabSeederCommand(BaseCommand):
     lab_name = None  # Override in subclass
-    tasks_data = []  # Override in subclass
+    tasks_data: ClassVar[list] = []  # Override in subclass
website/management/commands/create_open_redirect_tasks.py (1)

7-174: Consider adding ClassVar annotation for consistency.

Similar to the base class, the tasks_data class attribute would benefit from a type annotation.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates Open Redirect lab tasks"
     lab_name = "Open Redirect"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
website/management/commands/create_ssrf_tasks.py (1)

8-195: Consider adding ClassVar annotation for consistency.

The tasks_data class attribute would benefit from a type annotation, similar to other seeder commands.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates Server-Side Request Forgery (SSRF) lab tasks with theory and simulation content"
     lab_name = "Server-Side Request Forgery (SSRF)"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
website/management/commands/create_data_exposure_tasks.py (1)

7-208: Consider adding ClassVar annotation for consistency.

The tasks_data class attribute would benefit from a type annotation, consistent with the pattern across seeder commands.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates Sensitive Data Exposure lab tasks"
     lab_name = "Sensitive Data Exposure"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
website/management/commands/create_file_upload_tasks.py (1)

7-173: Consider adding ClassVar annotation for consistency.

The tasks_data class attribute would benefit from a type annotation to align with best practices.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates File Upload Vulnerabilities lab tasks"
     lab_name = "File Upload Vulnerabilities"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
website/management/commands/create_idor_tasks.py (1)

7-136: Consider adding ClassVar annotation for consistency.

The tasks_data class attribute would benefit from a type annotation to match the pattern across all seeder commands.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates Insecure Direct Object Reference (IDOR) lab tasks"
     lab_name = "Insecure Direct Object Reference (IDOR)"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
website/management/commands/create_broken_auth_tasks.py (1)

7-276: Consider adding ClassVar annotation for consistency.

The tasks_data class attribute would benefit from a type annotation, maintaining consistency across all seeder commands.

Apply this diff:

+from typing import ClassVar
 from .base_lab_seeder import LabSeederCommand

 class Command(LabSeederCommand):
     help = "Creates Broken Authentication / Authentication Bypass lab tasks"
     lab_name = "Broken Authentication"

-    tasks_data = [
+    tasks_data: ClassVar[list] = [
         # ... existing task definitions ...
     ]
📜 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 dd63aba and 77fdccd.

📒 Files selected for processing (7)
  • website/management/commands/base_lab_seeder.py (1 hunks)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
website/management/commands/create_file_upload_tasks.py

7-173: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/base_lab_seeder.py

6-6: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


8-8: Unused method argument: args

(ARG002)


8-8: Unused method argument: kwargs

(ARG002)


12-12: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


12-12: Avoid specifying long messages outside the exception class

(TRY003)

website/management/commands/create_open_redirect_tasks.py

7-174: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_ssrf_tasks.py

8-195: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


48-48: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)

website/management/commands/create_broken_auth_tasks.py

7-276: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_data_exposure_tasks.py

7-208: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_idor_tasks.py

7-136: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

⏰ 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 (7)
website/management/commands/base_lab_seeder.py (1)

8-57: LGTM! Well-structured base class.

The extraction of common seeding logic into this base class successfully eliminates ~1,200 lines of duplication across the six task seeder commands. The separation of concerns (_build_content_data, _log_task_status) makes the code maintainable and testable.

website/management/commands/create_open_redirect_tasks.py (1)

1-174: Well-structured Open Redirect lab tasks.

The task progression from introduction through exploitation to prevention is logical and comprehensive. The use of LabSeederCommand eliminates the error handling concerns from past reviews.

website/management/commands/create_ssrf_tasks.py (1)

4-195: Comprehensive SSRF lab structure.

The seven tasks cover the essential SSRF concepts from basic attacks to advanced bypasses and prevention techniques. The simulation configs provide practical, hands-on learning scenarios.

website/management/commands/create_data_exposure_tasks.py (1)

1-208: Excellent data exposure lab coverage.

The nine tasks effectively span the entire data exposure lifecycle: understanding risks, transport security, multiple simulation scenarios, and remediation. The past error handling concern was properly addressed.

website/management/commands/create_file_upload_tasks.py (1)

1-173: Great file upload lab structure.

The refactoring to use LabSeederCommand successfully addressed the ~1,200 lines of duplication flagged in past reviews. The seven tasks provide comprehensive coverage from basic concepts to advanced bypass techniques.

website/management/commands/create_idor_tasks.py (1)

1-136: Well-designed IDOR lab.

The five tasks efficiently cover IDOR fundamentals: introduction, common scenarios, practical exploits, and prevention. The past issues with error handling and curly quotes were properly resolved.

website/management/commands/create_broken_auth_tasks.py (1)

1-276: Exceptionally comprehensive authentication lab.

The twelve tasks provide thorough coverage of authentication vulnerabilities, from basic default credentials through advanced JWT forgery and brute-force scenarios. This is the most detailed lab in the set, appropriately reflecting the complexity of authentication security.

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: 7

Caution

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

⚠️ Outside diff range comments (1)
website/templates/task_detail.html (1)

126-207: Refactor template conditionals to use a type field instead of fragile name string matching.

The review concern is valid. All 10 labs referenced in the template (SQL Injection, XSS, CSRF, Command Injection, Broken Authentication, IDOR, File Upload Vulnerabilities, Sensitive Data Exposure, Open Redirect, SSRF) are created in create_initial_tasks.py via Labs.objects.get_or_create(name=...). However, hardcoded string matching on lab.name creates a maintainability risk:

  • If any lab name is changed, renamed for i18n, or accidentally misspelled in the seeder, the template conditionals fail silently, falling back to generic input
  • Adding new labs requires edits in two places (seeder + template)
  • The Lab model has no type, slug, or alternative identifier field

Recommended solution: Add a type field to the Lab model (e.g., type = models.CharField(max_length=50, choices=[('sql_injection', 'SQL Injection'), ...])) and update template conditionals to use lab.type instead of lab.name. This decouples the UI from database name strings and prevents silent failures.

🧹 Nitpick comments (3)
website/management/commands/base_lab_seeder.py (2)

10-10: Prefix unused parameters with underscore.

The args and kwargs parameters are not used. Prefix them with underscores to indicate they are intentionally unused.

Apply this diff:

-    def handle(self, *args, **kwargs):
+    def handle(self, *_args, **_kwargs):

Based on static analysis.


10-14: Validate class attributes before processing.

If a subclass forgets to override lab_name or tasks_data, the error messages may be unclear. Consider adding validation at the start of handle to provide better error messages.

Add validation after line 10:

    def handle(self, *args, **kwargs):
        if not self.lab_name:
            raise CommandError("lab_name must be set in the subclass")
        if not self.tasks_data:
            raise CommandError("tasks_data must be defined in the subclass")
        
        try:
            lab = Labs.objects.get(name=self.lab_name)
        except Labs.DoesNotExist as err:
            raise CommandError(
                f"{self.lab_name} lab not found. Please run create_initial_tasks first."
            ) from err
website/templates/task_detail.html (1)

233-299: Move JavaScript to a separate file. Per the previous review (line 234 comment), embedding substantial JavaScript in the template reduces maintainability and reusability. Extract the MCQ and simulation submission handlers to a separate .js file and include it via <script src="..."></script>.

This refactor would also:

  • Enable browser caching of the script
  • Allow linting and minification tools to process the code
  • Improve template readability
  • Enable testing/unit testing of the handlers
📜 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 77fdccd and 66f31a6.

📒 Files selected for processing (8)
  • website/management/commands/base_lab_seeder.py (1 hunks)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/migrations/0165_add_badge_icons.py (1 hunks)
  • website/templates/task_detail.html (4 hunks)
🧰 Additional context used
🪛 Ruff (0.14.3)
website/management/commands/create_broken_auth_tasks.py

8-277: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_idor_tasks.py

8-137: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_file_upload_tasks.py

8-174: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/base_lab_seeder.py

8-8: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


10-10: Unused method argument: args

(ARG002)


10-10: Unused method argument: kwargs

(ARG002)


14-14: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


14-14: Avoid specifying long messages outside the exception class

(TRY003)

website/management/commands/create_data_exposure_tasks.py

8-209: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_open_redirect_tasks.py

8-175: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

⏰ 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/migrations/0165_add_badge_icons.py (1)

96-96: Minor refactor is correct but seems unrelated to PR objectives.

The change from shutil.copy to shutil.copyfile is technically appropriate here. Since media_icon_path is a complete file path (line 90) and badge icons don't require metadata preservation, copyfile is suitable and slightly more efficient.

However, this migration deals with badge icons and appears unrelated to the PR's stated objective of adding security labs. Consider whether this change should be in a separate PR for clarity.

website/management/commands/base_lab_seeder.py (2)

36-44: LGTM!

The content data building logic correctly handles both theory and simulation task types, with appropriate defaults for missing fields.


46-55: LGTM!

The logging logic is clear and provides useful feedback about task and content creation/update status.

website/templates/task_detail.html (2)

27-27: SVG self-closing tag is correct.


120-220: Template structure is logically sound. The MCQ and simulation flows are properly separated, result areas are appropriately hidden/shown via JavaScript, and CSRF handling is consistent throughout.

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 66f31a6 and 58700a9.

📒 Files selected for processing (7)
  • website/management/commands/base_lab_seeder.py (1 hunks)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/management/commands/create_idor_tasks.py
  • website/management/commands/create_data_exposure_tasks.py
🧰 Additional context used
🪛 Ruff (0.14.3)
website/management/commands/create_ssrf_tasks.py

50-50: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)

website/management/commands/base_lab_seeder.py

12-12: Unused method argument: args

(ARG002)


12-12: Unused method argument: kwargs

(ARG002)


16-16: Avoid specifying long messages outside the exception class

(TRY003)

⏰ 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/management/commands/base_lab_seeder.py (1)

1-57: LGTM! Excellent refactoring.

The base class successfully eliminates ~1,200 lines of duplication across the lab seeder commands. The ClassVar annotations address RUF012, exception chaining preserves debug context, and the separation of concerns (content building, status logging) is clean.

Note: The static analysis flags for unused args/kwargs are false positives—Django's BaseCommand API requires this signature. The TRY003 hint about message length is a minor style preference; the current message is clear and appropriately descriptive.

website/management/commands/create_open_redirect_tasks.py (1)

1-177: LGTM! Well-structured lab seeder.

The command correctly extends LabSeederCommand, defines appropriate ClassVar annotations, and provides comprehensive Open Redirect lab content covering theory, simulations, and defensive practices. All past review concerns have been addressed.

website/management/commands/create_ssrf_tasks.py (1)

1-197: Overall structure is solid.

The command correctly extends LabSeederCommand and provides comprehensive SSRF lab content. ClassVar annotations are in place, and the base class pattern is properly followed. Just fix the curly quote flagged above.

website/management/commands/create_file_upload_tasks.py (1)

1-176: LGTM! Comprehensive file upload lab content.

The command properly extends LabSeederCommand, includes appropriate ClassVar annotations, and provides well-structured tasks covering file upload vulnerabilities, validation techniques, and defensive practices. All past review concerns have been addressed.

website/management/commands/create_broken_auth_tasks.py (1)

1-279: LGTM! Thorough authentication lab content.

The command correctly extends LabSeederCommand, properly annotates tasks_data with ClassVar, and provides extensive broken authentication content covering default credentials, session management, JWT vulnerabilities, password reset flaws, and brute-force defenses. All past review concerns have been resolved.

@Nachiket-Roy Nachiket-Roy force-pushed the feature/added-more-labs branch from 996757a to ac774f7 Compare November 10, 2025 22:41
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: 5

Caution

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

⚠️ Outside diff range comments (1)
website/management/commands/create_sql_injection_tasks.py (1)

8-324: Apply the Ruff suggestion: annotate mutable class attribute with ClassVar.

Mutable class attributes like tasks_data should be annotated with typing.ClassVar to clearly indicate they're class-level (not instance-level) and to prevent potential sharing issues across instances.

Apply this diff:

+from typing import ClassVar
+
 from .base_lab_seeder import LabSeederCommand


 class Command(LabSeederCommand):
     help = "Creates SQL Injection lab tasks with theory and simulation content"
     lab_name = "SQL Injection"

-    tasks_data = [
+    tasks_data: ClassVar[list[dict]] = [
         {
             "name": "Introduction to SQL Injection",

As per static analysis hints.

🧹 Nitpick comments (3)
website/templates/task_detail.html (3)

126-200: Well-refactored per-lab payload input blocks.

The explicit {% elif %} structure replaces the deeply nested conditionals, improving readability and maintainability. Each lab has clear, contextual labels and helpful placeholder examples. This addresses the prior review feedback on nested conditionals.

One architectural note: the lab name string matching (e.g., lab.name == "SQL Injection") is brittle and depends on exact lab name consistency. Consider using a slug or ID-based approach for future robustness, but this is acceptable for now.


234-266: MCQ handler is solid; minor UX improvement available.

The MCQ submission handler properly validates input, includes CSRF protection, and handles errors. Result styling based on data.correct is clean and clear.

Minor consideration: the submit button is not disabled during the fetch, which allows users to click multiple times and send duplicate requests. This is not a critical issue (server-side validation should prevent duplicate processing), but disabling the button until the response returns would improve UX.


268-299: Simulation handler is well-structured with unified payload submission.

The simulation form handler properly validates and trims payload input, maintains CSRF security, and handles errors gracefully. The unified result rendering (lines 286-293) is clean and consistent with MCQ styling.

Same minor UX consideration as MCQ: the submit button lacks disabled state during the async request, allowing potential duplicate submissions. This is not critical but could be improved.

📜 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 cfb4eac and ac774f7.

📒 Files selected for processing (15)
  • website/management/commands/base_lab_seeder.py (1 hunks)
  • website/management/commands/create_broken_auth_tasks.py (1 hunks)
  • website/management/commands/create_commands_injection_tasks.py (1 hunks)
  • website/management/commands/create_csrf_tasks.py (1 hunks)
  • website/management/commands/create_data_exposure_tasks.py (1 hunks)
  • website/management/commands/create_file_upload_tasks.py (1 hunks)
  • website/management/commands/create_idor_tasks.py (1 hunks)
  • website/management/commands/create_initial_tasks.py (1 hunks)
  • website/management/commands/create_open_redirect_tasks.py (1 hunks)
  • website/management/commands/create_sql_injection_tasks.py (7 hunks)
  • website/management/commands/create_ssrf_tasks.py (1 hunks)
  • website/management/commands/create_xss_tasks.py (1 hunks)
  • website/management/commands/seed_all_labs.py (1 hunks)
  • website/migrations/0165_add_badge_icons.py (1 hunks)
  • website/templates/task_detail.html (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website/management/commands/create_file_upload_tasks.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • website/management/commands/create_idor_tasks.py
  • website/management/commands/create_initial_tasks.py
  • website/migrations/0165_add_badge_icons.py
  • website/management/commands/create_open_redirect_tasks.py
🧰 Additional context used
🪛 Ruff (0.14.4)
website/management/commands/base_lab_seeder.py

12-12: Unused method argument: args

(ARG002)


12-12: Unused method argument: kwargs

(ARG002)


16-16: Avoid specifying long messages outside the exception class

(TRY003)

website/management/commands/seed_all_labs.py

20-20: Unused method argument: args

(ARG002)


20-20: Unused method argument: kwargs

(ARG002)

website/management/commands/create_commands_injection_tasks.py

8-153: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_sql_injection_tasks.py

8-324: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

website/management/commands/create_csrf_tasks.py

8-178: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


22-22: String contains ambiguous (RIGHT SINGLE QUOTATION MARK). Did you mean ``` (GRAVE ACCENT)?

(RUF001)

website/management/commands/create_xss_tasks.py

8-186: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

⏰ 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/templates/task_detail.html (2)

27-27: SVG self-closing tag is a good formatting improvement.

The refactored SVG path using self-closing syntax is valid and improves template consistency.


233-300: JavaScript handlers are secure and well-structured.

Both MCQ and simulation handlers follow consistent patterns for CSRF protection, validation, and error handling. The unified result rendering improves maintainability. The fetch-based approach is modern and appropriate.

One note on the past review feedback about embedded JavaScript: while a separate file would enhance modularity, the current approach is acceptable given the context-specific nature of Django URL tags and CSRF token injection.

website/management/commands/create_sql_injection_tasks.py (2)

1-6: LGTM! Clean refactoring to data-driven approach.

The transition from BaseCommand to LabSeederCommand with declarative class attributes (lab_name, help) is a good architectural improvement that promotes code reuse and consistency across lab seeders.


83-278: No issues found - simulation_config variations are intentionally supported.

Verification confirms the system is designed for flexible simulation_config structures. The view consumer in website/views/Simulation.py only requires the success_payload field to function; all other fields are optional metadata. All SQL injection simulation tasks (lines 83, 138, 199, 259) correctly include success_payload, and the additional fields like table_structure, blind_type, database_type, and time_function are inert but intentional for frontend hints and task documentation.

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

♻️ Duplicate comments (2)
website/management/commands/create_csrf_tasks.py (1)

1-10: LGTM! Previous issues resolved.

The ClassVar annotation has been properly added and imports are correct. The curly apostrophe issue on line 24 has also been fixed.

website/management/commands/create_xss_tasks.py (1)

1-10: LGTM! ClassVar annotation properly added.

The previous lint issue has been resolved with the correct type annotation.

🧹 Nitpick comments (2)
website/management/commands/create_sql_injection_tasks.py (2)

80-98: Standardize result field naming across simulations.

Line 96 uses expected_result while other simulations in this file (lines 152, 211, 272) use success_criteria. Pick one field name and use it consistently throughout the file.

-                "expected_result": "Successfully logged in as admin without knowing the password",
+                "success_criteria": "Successfully logged in as admin without knowing the password",

198-220: Consider removing the unique expected_approach field.

Line 218 introduces an expected_approach field not present in any other lab's simulation config. Unless this field serves a specific purpose consumed by the base seeder or frontend, consider removing it for consistency or adding it to other relevant simulations.

📜 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 ac774f7 and 621f11d.

📒 Files selected for processing (4)
  • website/management/commands/create_commands_injection_tasks.py (1 hunks)
  • website/management/commands/create_csrf_tasks.py (1 hunks)
  • website/management/commands/create_sql_injection_tasks.py (7 hunks)
  • website/management/commands/create_xss_tasks.py (1 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

@Nachiket-Roy Nachiket-Roy force-pushed the feature/added-more-labs branch from 8be3080 to 81adab5 Compare November 11, 2025 11:23
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 8be3080 and 81adab5.

📒 Files selected for processing (5)
  • website/management/commands/create_commands_injection_tasks.py (1 hunks)
  • website/management/commands/create_csrf_tasks.py (1 hunks)
  • website/management/commands/create_sql_injection_tasks.py (7 hunks)
  • website/management/commands/create_xss_tasks.py (1 hunks)
  • website/management/commands/seed_all_labs.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/management/commands/create_sql_injection_tasks.py
🧰 Additional context used
🪛 Ruff (0.14.4)
website/management/commands/seed_all_labs.py

20-20: Unused method argument: args

(ARG002)


20-20: Unused method argument: kwargs

(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

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: 0

🧹 Nitpick comments (2)
website/management/commands/seed_all_labs.py (2)

14-14: Consider matching the order of imports for consistency.

The order of commands in ALL_LABS doesn't match the import order. While this doesn't affect functionality, aligning them would improve readability and make it easier to verify completeness.

Apply this diff if you'd like to match the import order:

-ALL_LABS = [BrokenAuth, DataExposure, FileUpload, IDOR, OpenRedirect, SSRF, XSS, CSRF, SQL, CI]
+ALL_LABS = [BrokenAuth, CI, CSRF, DataExposure, FileUpload, IDOR, OpenRedirect, SQL, SSRF, XSS]

21-26: Consider adding error handling to continue seeding if one lab fails.

If any seeder's handle() method raises an exception, the entire seeding process stops and remaining labs won't be seeded. Consider wrapping each seeder call in a try-except block to log failures and continue with remaining labs.

Apply this diff to add error handling:

     def handle(self, *_args, **_kwargs):
         for Seeder in ALL_LABS:
             self.stdout.write(self.style.WARNING(f"Seeding: {Seeder.lab_name}"))
-            seeder = Seeder()
-            seeder.stdout = self.stdout
-            seeder.stderr = self.stderr
-            seeder.handle()
+            try:
+                seeder = Seeder()
+                seeder.stdout = self.stdout
+                seeder.stderr = self.stderr
+                seeder.handle()
+            except Exception as e:
+                self.stdout.write(self.style.ERROR(f"Failed to seed {Seeder.lab_name}: {e}"))
+                continue
 
         self.stdout.write(self.style.SUCCESS("All labs seeded successfully"))
📜 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 81adab5 and b16e7a4.

📒 Files selected for processing (1)
  • website/management/commands/seed_all_labs.py (1 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 (3)
website/management/commands/seed_all_labs.py (3)

1-12: LGTM!

The import structure is clean and consistent. All lab seeder commands are imported with descriptive aliases.


20-26: Past review concern has been addressed.

The stdout and stderr are now properly forwarded to each seeder instance (lines 24-25), which resolves the AttributeError that would occur when child seeders call self.stdout.write(). The unused parameters are also correctly prefixed with underscores.


22-22: All seeder classes define the lab_name attribute—no changes required.

Verification confirms that all 10 imported seeder classes in seed_all_labs.py define the lab_name attribute at line 8. The code at line 22 is safe to access Seeder.lab_name for every class in the ALL_LABS list.

@Nachiket-Roy Nachiket-Roy force-pushed the feature/added-more-labs branch from c57fb0d to 160fb87 Compare November 16, 2025 08:22
@DonnieBLT DonnieBLT merged commit 7189a11 into OWASP-BLT:main Nov 16, 2025
18 checks passed
@Nachiket-Roy Nachiket-Roy deleted the feature/added-more-labs branch November 17, 2025 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

files-changed: 2 PR changes 2 files LGTM unresolved-conversations: 0 PR has 0 unresolved conversations

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Enhance: Add more labs under security labs page

2 participants