-
-
Notifications
You must be signed in to change notification settings - Fork 313
Added Security Incidents Summary to Dashboard #4029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThe changes modify the repository's Git configuration and enhance the company cyber dashboard. A new entry is added to the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WebServer
participant DashboardView as OrganizationDashboardAnalyticsView
participant DB as Issue Model
User->>WebServer: Request analytics page
WebServer->>DashboardView: Call get() method
DashboardView->>DashboardView: Execute get_security_incidents_summary()
DashboardView->>DB: Query security-related issues (label=4)
DB-->>DashboardView: Return security metrics (count, recent incidents, avg resolution, severity, top domains)
DashboardView->>WebServer: Return context with security_incidents_summary
WebServer->>User: Render analytics page with new security incidents card and details
Assessment against linked issues
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (3)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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 (3)
website/templatetags/custom_tags.py (1)
207-210: Enhance docstring with parameter and return detailsImprove the function documentation by adding parameter and return value details.
@register.filter def format_security_timedelta(td): - """Convert a timedelta object into a human-readable string.""" + """Convert a timedelta object into a human-readable string. + + Args: + td (timedelta): The timedelta object to format + + Returns: + str: A formatted string like "X days, Y hours, Z minutes" or "N/A" if td is None + """ if not td: return "N/A"website/templates/organization/organization_analytics.html (1)
282-329: Add error handling for potentially missing dataThe security incidents summary section should handle the case where
security_incidents_summarymight be None or any of its properties might be missing.Add checks before accessing potentially missing properties:
<div id="security-incidents" class="w-full px-8 mt-8"> <div class="bg-white rounded-xl p-6 shadow-sm"> <h2 class="text-2xl font-bold text-gray-900 mb-6">Security Incidents Summary</h2> + {% if security_incidents_summary %} <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <!-- Recent Incidents --> <div class="bg-gray-50 p-4 rounded-lg"> <h3 class="text-lg font-semibold text-gray-800 mb-2">Recent Incidents (30 days)</h3> <p class="text-3xl font-bold text-red-600">{{ security_incidents_summary.recent_incidents }}</p> </div> <!-- Other sections... --> </div> + {% else %} + <div class="bg-gray-50 p-4 rounded-lg"> + <p class="text-gray-600">No security incidents data available</p> + </div> + {% endif %} </div> </div>website/views/company.py (1)
214-216: Potential database compatibility issue with timedelta calculationUsing database-level subtraction with
F("closed_date") - F("created")might work for PostgreSQL, but could cause issues with other database backends. Consider performing this calculation in Python after fetching the data.# Calculate average resolution time resolved_issues = security_issues.filter(status="resolved") resolved_issues = resolved_issues.filter(closed_date__isnull=False) - avg_resolution_time = resolved_issues.aggregate(avg_time=Avg(F("closed_date") - F("created")))["avg_time"] + # Fetch the issues and calculate average timedelta in Python + resolved_issues_list = resolved_issues.values('closed_date', 'created') + if resolved_issues_list: + total_timedelta = timedelta() + count = 0 + for issue in resolved_issues_list: + if issue['closed_date'] and issue['created']: + total_timedelta += issue['closed_date'] - issue['created'] + count += 1 + avg_resolution_time = total_timedelta / count if count > 0 else None + else: + avg_resolution_time = None
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.gitignore(1 hunks)website/templates/organization/organization_analytics.html(2 hunks)website/templatetags/custom_tags.py(1 hunks)website/views/company.py(3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
website/views/company.py (1)
website/models.py (1) (1)
Issue(443-546)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Run Tests
- GitHub Check: docker-test
🔇 Additional comments (4)
.gitignore (1)
22-22: LGTM: Added .qodo to .gitignoreAdding
.qodofiles to .gitignore is a good practice to avoid tracking project-specific configuration files.website/templates/organization/organization_analytics.html (1)
73-85: LGTM: Security issues card implements consistent design patternThe new card for security issues follows the same design pattern as the existing cards, maintaining UI consistency.
website/views/company.py (2)
414-414: LGTM: Context variable integrationGood job including the security incidents summary in the template context. This properly connects the backend data with the frontend template.
195-226:Details
❓ Verification inconclusive
Handle potential missing severity field more robustly
The try-except block suggests that the
severityfield might not exist in theIssuemodel, which is concerning for a new feature. Consider checking if the model field exists before deployment or ensuring the field is added if needed.
🏁 Script executed:
#!/bin/bash # Check if the Issue model has a severity field echo "Checking if the Issue model has a severity field..." python -c " from website.models import Issue from django.db import models issue_fields = [field.name for field in Issue._meta.get_fields()] if 'severity' in issue_fields: print('✅ Severity field exists in Issue model') else: print('❌ Severity field DOES NOT exist in Issue model') print('Available fields:', issue_fields) "Length of output: 715
Attention: Missing Dependency Affecting Severity Field Verification
- The check for the
severityfield in theIssuemodel could not be completed because of a missing dependency (annoying). The error (ModuleNotFoundError: No module named 'annoying') prevented the Python-based verification from running successfully.- As the try/except strategy in
website/views/company.pyis intended to handle an absentseverityfield, it’s critical to confirm whether this field should exist. However, before that, the missing dependency must be resolved.- Action Items:
- Ensure that the
annoyingpackage is installed (or consider an alternative) so that the model file can be imported without errors.- Manually verify whether the
Issuemodel includes theseverityfield by checkingwebsite/models.py(e.g., searching for “severity =” within theIssueclass).- Once confirmed, either add the missing field or adjust the handling in the code to match the intended model structure.
There was a problem hiding this 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 (1)
website/views/company.py (1)
195-227: Nicely structured security incidents summary method with good error handling.The method effectively:
- Filters security-related issues (label=4)
- Gracefully handles the possible absence of the severity field
- Calculates recent incidents (last 30 days)
- Computes average resolution time
- Identifies top affected domains
However, there's potential for a None value in the average resolution time calculation if no issues are resolved.
Consider adding a fallback for the average resolution time when no issues are resolved:
avg_resolution_time = resolved_issues.aggregate(avg_time=Avg(F("closed_date") - F("created")))["avg_time"] + # Provide default value when no resolved issues exist + if avg_resolution_time is None: + avg_resolution_time = timedelta(0)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
website/views/company.py(3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
website/views/company.py (1)
website/models.py (1) (1)
Issue(443-546)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Run Tests
- GitHub Check: docker-test
- GitHub Check: Analyze (python)
🔇 Additional comments (2)
website/views/company.py (2)
11-11: Import additions look appropriate for the new functionality.The new imports (
FieldErrorfromdjango.core.exceptionsandAvg,Ffromdjango.db.models) align well with the requirements of the new security incidents summary feature.Also applies to: 14-14
414-414: The implementation correctly adds security data to the context.The data provided by
get_security_incidents_summary()is properly added to the template context.
There was a problem hiding this 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 (1)
website/templatetags/custom_tags.py (1)
208-217: The timedelta formatter looks good, with a minor readability enhancement suggestion.The implementation correctly calculates days, hours, and minutes from a timedelta object, properly extracting each time component. I see that the previous review comment about correctly handling days extraction has been addressed.
Consider handling pluralization for a more natural reading experience:
@register.filter def format_security_timedelta(td): """Convert a timedelta object into a human-readable string.""" if not td: return "N/A" total_seconds = int(td.total_seconds()) days = total_seconds // (24 * 3600) # Calculate days first hours = (total_seconds % (24 * 3600)) // 3600 # Get remaining hours after days minutes = (total_seconds % 3600) // 60 # Get remaining minutes - return f"{days} days, {hours} hours, {minutes} minutes" + day_label = "day" if days == 1 else "days" + hour_label = "hour" if hours == 1 else "hours" + minute_label = "minute" if minutes == 1 else "minutes" + return f"{days} {day_label}, {hours} {hour_label}, {minutes} {minute_label}"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
website/templatetags/custom_tags.py(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Run Tests
- GitHub Check: docker-test
There was a problem hiding this 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 (1)
website/templatetags/custom_tags.py (1)
208-217: Clean implementation of the time formatter filter!The implementation correctly calculates days, hours, and minutes from a timedelta object, addressing the previous feedback about hours calculation. This will provide a consistent and readable time format for security incidents in the dashboard.
Here are a few minor suggestions to make the function even more robust:
- Consider handling negative timedeltas (perhaps with an absolute value conversion)
- The function could be enhanced to display only non-zero components (e.g., "2 hours, 30 minutes" instead of "0 days, 2 hours, 30 minutes")
- Expand the docstring to include parameter and return value descriptions
@register.filter def format_security_timedelta(td): - """Convert a timedelta object into a human-readable string.""" + """ + Convert a timedelta object into a human-readable string. + + Args: + td (timedelta): The timedelta object to format + + Returns: + str: A human-readable string representation (e.g., "2 days, 5 hours, 30 minutes") + or "N/A" if the input is None/empty + """ if not td: return "N/A" - total_seconds = int(td.total_seconds()) + # Handle negative timedeltas by taking absolute value + total_seconds = int(abs(td.total_seconds())) days = total_seconds // (24 * 3600) # Calculate days first hours = (total_seconds % (24 * 3600)) // 3600 # Get remaining hours after days minutes = (total_seconds % 3600) // 60 # Get remaining minutes - return f"{days} days, {hours} hours, {minutes} minutes" + # Build parts of the string, including only non-zero components + parts = [] + if days > 0: + parts.append(f"{days} days") + if hours > 0 or days > 0: + parts.append(f"{hours} hours") + if minutes > 0 or hours > 0 or days > 0: + parts.append(f"{minutes} minutes") + if not parts: + return "0 minutes" # Handle case where all values are zero + return ", ".join(parts)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
website/templatetags/custom_tags.py(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Run Tests
- GitHub Check: docker-test
|
@DonnieBLT Hello sir please review this PR |
DonnieBLT
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the timesince filter instead
|
@DonnieBLT The changes have been implemented. Requesting a PR review. |
|
/giphy nice work |
* added Security Issue * fix * fix isort * ruff format fix * ruff fix * fix
closes #2470
Summary by CodeRabbit