-
-
Notifications
You must be signed in to change notification settings - Fork 323
Feature/project leaderboard #5367
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
base: main
Are you sure you want to change the base?
Feature/project leaderboard #5367
Conversation
- Display 11 OWASP projects with stars, forks, issues, commits - Add Chart.js visualizations and tabbed interface - Include seed command with actual GitHub data - Implement basic filtering and sorting Resolves OWASP-BLT#3314
|
👋 Hi @snigdhachoudhury! This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:
Once a valid peer review is submitted, this check will pass automatically. Thank you! |
|
Warning Rate limit exceeded@snigdhachoudhury has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 48 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughAdds a Project Leaderboard feature: new template and view, REST API endpoints for leaderboard and project stats, GitHub integration service, seeding commands, frontend JS for filtering/charts/auto-refresh, and URL/navigation updates. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Browser as Browser/JS
participant Django as Django View
participant API as Leaderboard API
participant Cache as Cache Layer
participant DB as Database
participant GH as GitHub API
User->>Browser: Open /project_leaderboard/
Browser->>Django: GET /project_leaderboard/
Django->>DB: Query projects & repos
DB-->>Django: Projects data
Django-->>Browser: Render template with initial context
Browser->>API: GET /api/leaderboard/?filters
API->>Cache: Check cached response
alt Cache Hit
Cache-->>API: Return cached JSON
else Cache Miss
API->>DB: Query & aggregate repos
DB-->>API: Repo aggregates
API->>Cache: Store response (5m TTL)
end
API-->>Browser: JSON (projects, totals, filters)
Browser->>Browser: Render leaderboard, charts, attach refresh handlers
sequenceDiagram
actor User
participant Browser as Browser/JS
participant RefreshAPI as RefreshStatsAPI
participant Service as GitHubService
participant GH as GitHub API
participant DB as Database
User->>Browser: Click "Refresh" on a project
Browser->>RefreshAPI: POST /api/project/{id}/refresh/ (CSRF, auth)
RefreshAPI->>DB: Validate project & list repos
loop per repo
RefreshAPI->>Service: refresh_repo_cache(owner,repo)
Service->>GH: GET /repos/{owner}/{repo} and related endpoints
GH-->>Service: Repo metrics (stars,forks,commits,contributors,prs,issues)
Service-->>RefreshAPI: Aggregated stats
RefreshAPI->>DB: Update repo record
end
DB-->>RefreshAPI: Save confirmations
RefreshAPI-->>Browser: JSON (updated repos)
Browser->>Browser: Hide loading, update UI, optionally reload leaderboard
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
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. Comment |
📊 Monthly LeaderboardHi @snigdhachoudhury! Here's how you rank for December 2025:
Leaderboard based on contributions in December 2025. Keep up the great work! 🚀 |
❌ Pre-commit checks failedThe pre-commit hooks found issues that need to be fixed. Please run the following commands locally to fix them: # Install pre-commit if you haven't already
pip install pre-commit
# Run pre-commit on all files
pre-commit run --all-files
# Or run pre-commit on staged files only
pre-commit runAfter running these commands, the pre-commit hooks will automatically fix most issues. 💡 Tip: You can set up pre-commit to run automatically on every commit by running: pre-commit installPre-commit outputFor more information, see the pre-commit documentation. |
❌ Pre-commit checks failedThe pre-commit hooks found issues that need to be fixed. Please run the following commands locally to fix them: # Install pre-commit if you haven't already
pip install pre-commit
# Run pre-commit on all files
pre-commit run --all-files
# Or run pre-commit on staged files only
pre-commit runAfter running these commands, the pre-commit hooks will automatically fix most issues. 💡 Tip: You can set up pre-commit to run automatically on every commit by running: pre-commit installPre-commit outputFor more information, see the pre-commit documentation. |
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.
Pull request overview
This pull request adds a comprehensive project leaderboard feature that displays GitHub metrics for OWASP projects. The implementation includes a full-stack solution with Django views, REST API endpoints, Chart.js visualizations, and data seeding commands.
Key changes:
- New leaderboard dashboard with filterable/sortable project statistics (stars, forks, commits, contributors, etc.)
- REST API endpoints for dynamic data retrieval with caching
- GitHub service integration for fetching repository statistics
- Management commands to seed realistic project data
- Navigation links added across multiple templates (sidebar, navbar, header, homepage)
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| website/views/project_leaderboard.py | Main view logic for leaderboard, filtering/sorting, and JSON API endpoint |
| website/templates/project_leaderboard.html | Leaderboard UI template with tabbed interface and Chart.js visualizations |
| website/static/js/project_leaderboard.js | JavaScript for chart rendering and tab switching functionality |
| website/static/js/leaderboard_filters.js | Advanced filtering/sorting logic with API integration (appears unused in template) |
| website/services/github_service.py | GitHub API integration service with caching for rate limit management |
| website/api/leaderboard_api.py | REST API endpoints for leaderboard data, project stats, and refresh functionality |
| website/management/commands/seed_project_data.py | Management command to seed sample OWASP project data |
| website/management/commands/seed_leaderboard_data.py | Raw SQL-based seeding command for bypassing model validation |
| website/templates/includes/sidenav.html | Removed inline style tag (good), added leaderboard navigation link |
| website/templates/includes/navbar.html | Added leaderboard link to navbar and mobile dropdown menu |
| website/templates/includes/header.html | Added leaderboard link to header dropdown menu |
| website/templates/home.html | Added leaderboard card to tools section |
| blt/urls.py | URL patterns for leaderboard views and API endpoints |
| check_repo_columns.py | Utility script for checking database columns (should not be committed) |
| check_data.py | Utility script for checking seeded data (should not be committed) |
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: 9
♻️ Duplicate comments (3)
website/views/project_leaderboard.py (1)
195-196: Avoid exposing exception details to external users.The exception message is returned directly in the response, which could leak stack trace information or internal details to attackers.
This was already flagged by CodeQL. Consider returning a generic error message:
except Exception as e: - return JsonResponse({"status": "error", "message": f"Failed to refresh stats: {str(e)}"}, status=500) + logger.error(f"Failed to refresh stats for project {project_id}: {e}") + return JsonResponse({"status": "error", "message": "Failed to refresh stats"}, status=500)website/api/leaderboard_api.py (2)
182-185: Incomplete URL substring sanitization for GitHub URL parsing.Checking
"github.com" in repo.repo_urlis insufficient as a malicious URL likehttps://evil.com/github.com/owner/repowould pass the check.This was already flagged by CodeQL. Consider using proper URL parsing:
from urllib.parse import urlparse parsed = urlparse(repo.repo_url) if parsed.netloc == "github.com" or parsed.netloc == "www.github.com": parts = parsed.path.strip("/").split("/") if len(parts) >= 2: owner, repo_name = parts[0], parts[1]
214-216: Avoid exposing exception details to external users.This was already flagged by CodeQL. The exception message should not be returned directly:
except Exception as e: logger.error(f"Error refreshing stats: {e}") - return JsonResponse({"success": False, "error": str(e)}, status=500) + return JsonResponse({"success": False, "error": "An internal error occurred"}, status=500)
🧹 Nitpick comments (13)
check_data.py (1)
1-9: Consider adding a__main__guard and optional Django setupRight now the ORM queries run at import and assume Django is already configured. If you ever want to run this like
python check_data.py, consider:
- Moving the print/loop code into a
main()function guarded byif __name__ == "__main__":.- Optionally mirroring
check_repo_columns.pyby settingDJANGO_SETTINGS_MODULEand callingdjango.setup()here as well.This keeps it clearly in “diagnostic script” territory and avoids surprises if imported elsewhere.
check_repo_columns.py (1)
1-21: Use a context manager and__main__guard for the diagnostic scriptFor a small robustness win:
- Wrap the DB work in
with connection.cursor() as cursor:so the cursor is always closed.- Put the query/print logic under
if __name__ == "__main__":to avoid executing it on import.Example:
Proposed structure
-import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blt.settings') -django.setup() - -from django.db import connection - -cursor = connection.cursor() -cursor.execute(""" +import os +import django +from django.db import connection + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blt.settings") +django.setup() + + +def main(): + with connection.cursor() as cursor: + cursor.execute(""" SELECT column_name, column_default, is_nullable, data_type FROM information_schema.columns WHERE table_name = 'website_repo' AND is_nullable = 'NO' ORDER BY ordinal_position -""") - -print("NOT NULL columns in website_repo:") -print("-" * 80) -for row in cursor.fetchall(): - default = str(row[1]) if row[1] else "None" - print(f"{row[0]:30} | Default: {default:20} | Type: {row[3]}") + """) + + print("NOT NULL columns in website_repo:") + print("-" * 80) + for row in cursor.fetchall(): + default = str(row[1]) if row[1] else "None" + print(f"{row[0]:30} | Default: {default:20} | Type: {row[3]}") + + +if __name__ == "__main__": + main()website/templates/includes/header.html (1)
244-247: Align Project Leaderboard menu item styling with other entriesThe new “Project Leaderboard” link works, but its classes are simpler than neighboring items (no active-state highlighting, no dark-mode text/background variants, no transition classes). For consistency and dark-mode support, consider mirroring the pattern used for
project_list/repo_list(conditional classes based onrequest.resolver_match.url_name,dark:variants,hover:bgetc.).website/templates/home.html (1)
1105-1111: Add dark‑mode classes to the new Project Leaderboard tileThe new tile uses
bg-gray-50and light-mode text classes only, while neighboring tiles usebg-gray-50 dark:bg-gray-900anddark:text-gray-400. To keep the “Tools for Projects” grid consistent in dark mode, consider:
- Adding
dark:bg-gray-900to the wrapper.- Adding
dark:text-gray-400(or similar) to the description text.You can largely copy the class set from the adjacent cards.
website/templates/includes/navbar.html (1)
27-31: Navbar additions for Project Leaderboard and mobile toggle look good; consider minor accessibility polish
- Switching the mobile menu trigger to a
<button>and addinge.preventDefault()/e.stopPropagation()is a nice behavioral cleanup.- New Project Leaderboard links (mobile dropdown and desktop button) follow the existing visual pattern and correct URL name.
If you want to go a bit further for accessibility, you could add
aria-expandedandaria-controlsto#dropdown-toggle-mobileand togglearia-expandedtogether with thehiddenclass on#dropdown-mobile.Also applies to: 45-50, 59-64, 120-123
blt/urls.py (1)
22-27: Leaderboard URLs are wired correctly; consider versioning and guarding refresh endpointsThe new imports and URL patterns:
project_leaderboard/→ProjectLeaderboardView/api/project-leaderboard/,/api/leaderboard/,/api/leaderboard/filters//api/project/<int:project_id>/stats/,/api/project/<int:project_id>/refresh/are consistent with the rest of the URL config and the templates that link to
project_leaderboard.Two follow‑ups to consider:
- API versioning: Most existing REST endpoints live under
/api/v1/.... Aligning these new endpoints to the same versioned prefix (or at least planning for it) will make future evolution easier.- Protection of refresh endpoint: The
RefreshStatsAPIViewpath likely triggers outbound GitHub calls/cache updates. Ensure its DRF permissions, throttling, and any internal rate limiting are configured so anonymous or abusive traffic cannot exhaust your GitHub rate limits or overload the job.Also applies to: 315-315, 1136-1141
website/templates/project_leaderboard.html (2)
483-483: Consider adding Subresource Integrity (SRI) for CDN-loaded script.Loading Chart.js from a CDN without an integrity hash exposes the page to supply-chain attacks if the CDN is compromised.
🔎 Proposed fix
- <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> + <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js" integrity="sha384-..." crossorigin="anonymous"></script>You can generate the correct hash using:
curl -s https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js | openssl dgst -sha384 -binary | openssl base64 -A
530-546: Auto-refresh interval is not cleared on page unload, causing potential memory leak.When navigating away from the page, the
setIntervalcontinues running. While modern browsers handle this, it's good practice to clean up.🔎 Proposed fix
if (autoRefreshCheck) { autoRefreshCheck.addEventListener('change', function() { if (this.checked) { autoRefreshInterval = setInterval(function() { location.reload(); }, 60000); // 1 minute } else { if (autoRefreshInterval) { clearInterval(autoRefreshInterval); autoRefreshInterval = null; } } }); + + // Cleanup on page unload + window.addEventListener('beforeunload', function() { + if (autoRefreshInterval) { + clearInterval(autoRefreshInterval); + } + }); } }website/views/project_leaderboard.py (2)
20-57: Consider using database aggregation instead of Python iteration.The current implementation fetches all repos and aggregates in Python. For larger datasets, this could be optimized using Django's
annotate()withSum().🔎 Suggested approach
from django.db.models import Sum, Count projects = Project.objects.select_related("organization").annotate( stars=Sum("repos__stars"), forks=Sum("repos__forks"), issues=Sum("repos__open_issues"), watchers=Sum("repos__watchers"), contributors=Sum("repos__contributor_count"), commits=Sum("repos__commit_count"), repos_count=Count("repos"), )This moves aggregation to the database layer, reducing memory usage and improving performance.
156-178: Manually instantiating the view works but is unconventional.The approach of creating a
ProjectLeaderboardViewinstance and manually settingrequestworks, but consider extracting the shared logic into a service class or mixin for cleaner separation.website/services/github_service.py (2)
107-109: Consider using more specific exception types.Catching broad
Exceptioncan mask unexpected errors. For HTTP operations,requests.RequestException(already used inget_repo_stats) is more appropriate.🔎 Example for _get_contributors_count
- except Exception as e: + except requests.RequestException as e: logger.warning(f"Could not fetch contributors count: {e}") return 0Also applies to: 128-130, 155-157
175-189: Sequential API calls inget_multiple_reposmay be slow for many repositories.For projects with many repos, consider using
concurrent.futures.ThreadPoolExecutoror async requests to parallelize API calls while respecting rate limits.website/static/js/leaderboard_filters.js (1)
218-226: Hardcoded max values for percentage calculation are inflexible.The
maxValuesobject uses static values that may become outdated as projects grow. Consider calculating the max dynamically from the current dataset.🔎 Proposed approach
Store max values when data is loaded:
renderLeaderboard(projects) { // Calculate max values dynamically this.maxValues = { stars: Math.max(...projects.map(p => p.stats.stars), 1), forks: Math.max(...projects.map(p => p.stats.forks), 1), commits: Math.max(...projects.map(p => p.stats.commits), 1) }; // ... rest of render logic } calculatePercentage(value, metric) { return Math.min((value / this.maxValues[metric]) * 100, 100); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (14)
blt/urls.pycheck_data.pycheck_repo_columns.pywebsite/api/leaderboard_api.pywebsite/management/commands/seed_leaderboard_data.pywebsite/management/commands/seed_project_data.pywebsite/services/github_service.pywebsite/static/js/leaderboard_filters.jswebsite/static/js/project_leaderboard.jswebsite/templates/home.htmlwebsite/templates/includes/header.htmlwebsite/templates/includes/navbar.htmlwebsite/templates/project_leaderboard.htmlwebsite/views/project_leaderboard.py
🧰 Additional context used
🪛 GitHub Actions: Check Console Statements
website/static/js/leaderboard_filters.js
[error] 113-113: Console statement detected: console.error('Error loading leaderboard:', error);. Detected by step 'Run actions/github-script@v7'.
[error] 259-259: Console statement detected: console.error('Error refreshing stats:', error);. Detected by step 'Run actions/github-script@v7'.
🪛 GitHub Check: CodeQL
website/api/leaderboard_api.py
[failure] 183-183: Incomplete URL substring sanitization
The string github.com may be at an arbitrary position in the sanitized URL.
[warning] 216-216: Information exposure through an exception
Stack trace information flows to this location and may be exposed to an external user.
website/views/project_leaderboard.py
[warning] 196-196: Information exposure through an exception
Stack trace information flows to this location and may be exposed to an external user.
🔇 Additional comments (13)
website/management/commands/seed_project_data.py (1)
12-140: Seed command logic looks sound and idempotentUsing
Project.objects.get_or_create(slug=...)and only creating repos whencreatedkeeps this command safe to re-run. Field mappings for stars/forks/issues/commits/contributors onRepoalso look consistent with the intended sample data.website/static/js/project_leaderboard.js (5)
7-23: LGTM!The color palette is well-defined with a clear naming convention. The
shadesarray provides good gradient options for charts with multiple data points.
28-57: LGTM!Tab switching logic is clean with proper state management for button classes and content visibility. The use of
data-tabattributes provides a flexible, data-driven approach.
62-119: LGTM!Chart helper functions are well-configured with responsive behavior, consistent styling, and sensible defaults. The separation between bar and pie chart creation improves reusability.
Also applies to: 124-146
151-212: LGTM!The
initializeChartsfunction handles multiple chart types with proper null checks for both canvas elements and data. The spread operator for sorting preserves the original array, which is good practice.
214-222: LGTM!Proper handling of DOM ready state with fallback for already-loaded documents. Exporting to
windowobject allows template integration.website/templates/project_leaderboard.html (1)
14-91: LGTM!The filter form, tab navigation, dashboard summary cards, project cards grid, and chart containers are well-structured with proper accessibility attributes and responsive design using Tailwind CSS.
Also applies to: 92-117, 121-246, 393-476
website/views/project_leaderboard.py (1)
78-98: LGTM!The sorting logic handles both numeric and string fields correctly with the
isinstancecheck. The context data assembly is comprehensive and well-organized.Also applies to: 100-153
website/services/github_service.py (2)
29-86: LGTM!The caching strategy with 1-hour timeout is sensible for GitHub data. Link header parsing for pagination is the correct approach for getting total counts. Error handling gracefully falls back to safe defaults.
Also applies to: 88-98, 111-131, 132-157, 159-173
20-27: No action needed. GitHub API accepts bothtokenandBearerauthentication formats for personal access tokens, with no preference stated by GitHub. The current implementation usingtoken {github_token}is fully compliant with GitHub's documentation and recommendations.Likely an incorrect or invalid review comment.
website/api/leaderboard_api.py (2)
19-52: LGTM!The caching decorator, query building, sorting logic, and JSON response formatting are well-implemented. The
ProjectStatsAPIViewproperly handles theDoesNotExistcase with a 404 response.Also applies to: 59-117, 120-168
53-54: Language filter logic appears incorrect.Filtering by
repo_url__icontains=languagesearches for the language string in the URL, which won't work as intended. GitHub URLs don't contain language information.If the
Repomodel has alanguagefield, use that instead:if language: - repos = repos.filter(repo_url__icontains=language) + repos = repos.filter(language__iexact=language)If not, consider adding a
languagefield to theRepomodel and populating it from the GitHub API response.website/static/js/leaderboard_filters.js (1)
5-16: LGTM!The class structure is well-organized with clear separation of concerns. Event listener attachment with debouncing for search, CSRF token handling, toast notifications, and animation logic are all properly implemented.
Also applies to: 18-91, 93-118, 228-234, 236-267, 269-299, 301-377, 380-383
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
♻️ Duplicate comments (1)
website/api/leaderboard_api.py (1)
193-200: URL validation remains vulnerable to SSRF attacks.Despite the regex improvement, the validation at lines 193 and 196 can still be bypassed. The substring check and regex pattern will match
github.comanywhere in the URL, not specifically as the domain.Attack vectors:
https://evil.com/github.com/owner/repo✓ passeshttps://github.com.evil.com/owner/repo✓ passeshttps://evil.com?redirect=github.com/owner/repo✓ passes🔎 Proposed fix using proper URL parsing
+ from urllib.parse import urlparse + for repo in project.repos.all(): # Parse owner/repo from URL with strict validation try: - if "github.com" in repo.repo_url: - # Extract owner/repo from GitHub URL - # Expected format: https://github.com/owner/repo or github.com/owner/repo - match = re.search(r"github\.com[:/]([^/]+)/([^/]+)", repo.repo_url) - if match: - owner, repo_name = match.group(1), match.group(2) - # Remove .git suffix if present - repo_name = repo_name.rstrip("/").replace(".git", "") - - # Fetch fresh data - stats = github_service.refresh_repo_cache(owner, repo_name) + parsed = urlparse(repo.repo_url) + # Validate github.com is the actual domain + if parsed.netloc in ("github.com", "www.github.com"): + # Extract owner/repo from path + path_parts = parsed.path.strip("/").split("/") + if len(path_parts) >= 2: + owner = path_parts[0] + repo_name = path_parts[1].replace(".git", "") + + # Fetch fresh data + stats = github_service.refresh_repo_cache(owner, repo_name) + else: + logger.warning(f"Invalid GitHub URL path for repo {repo.id}: {repo.repo_url}") + continue + else: + continue + if stats: repo.stars = stats.get("stars", repo.stars)
🧹 Nitpick comments (2)
website/views/project_leaderboard.py (2)
45-51: Add None-safety for repo metric aggregations.The code sums numeric fields from repos without checking for None values. If any repo has None for stars, forks, etc., the sum will fail with a TypeError.
🔎 Proposed fix using generator with default values
# GitHub Metrics - "stars": sum(r.stars for r in repos), - "forks": sum(r.forks for r in repos), - "issues": sum(r.open_issues for r in repos), - "watchers": sum(r.watchers for r in repos), - "contributors": sum(r.contributor_count for r in repos), - "commits": sum(r.commit_count for r in repos), + "stars": sum(r.stars or 0 for r in repos), + "forks": sum(r.forks or 0 for r in repos), + "issues": sum(r.open_issues or 0 for r in repos), + "watchers": sum(r.watchers or 0 for r in repos), + "contributors": sum(r.contributor_count or 0 for r in repos), + "commits": sum(r.commit_count or 0 for r in repos),
165-170: Consider refactoring to avoid view instantiation pattern.Instantiating
ProjectLeaderboardViewto reuseget_context_datais unconventional and tightly couples the JSON endpoint to the view class. Consider extracting shared logic into a separate service or helper function.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (4)
website/api/leaderboard_api.pywebsite/management/commands/seed_project_data.pywebsite/static/js/leaderboard_filters.jswebsite/views/project_leaderboard.py
🚧 Files skipped from review as they are similar to previous changes (2)
- website/management/commands/seed_project_data.py
- website/static/js/leaderboard_filters.js
🧰 Additional context used
🪛 GitHub Check: CodeQL
website/api/leaderboard_api.py
[failure] 193-193: Incomplete URL substring sanitization
The string github.com may be at an arbitrary position in the sanitized URL.
⏰ 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). (1)
- GitHub Check: Agent
🔇 Additional comments (6)
website/views/project_leaderboard.py (1)
190-206: LGTM! Error handling follows best practices.The error handling correctly logs detailed exception information for debugging (line 205) while returning a generic error message to the user (line 206). This is the recommended approach for security.
website/api/leaderboard_api.py (5)
44-52: LGTM! Input validation properly implemented.The safe integer conversions with try-except blocks correctly handle invalid user input, addressing the concerns from previous reviews.
61-62: LGTM! Language filter now uses the correct field.Using
primary_language__iexactproperly filters by the programming language field instead of searching in URLs.
182-182: LGTM! Authentication properly enforced.The
@method_decorator(login_required)decorator prevents unauthenticated users from triggering potentially expensive GitHub API calls.
216-218: LGTM! Error logging is appropriate.Logging exception details to the server (line 217) is standard practice for debugging and does not expose sensitive information to users. The continue statement ensures processing continues for other repos.
230-232: LGTM! Error handling follows security best practices.The exception is logged for debugging (line 231) while returning a generic error message to the client (line 232), which is the correct approach to avoid information disclosure.
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.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 18 comments.
|
@DonnieBLT hello, can you please review this |
|
Looks good overall — solid feature and clean UI. Nice work! |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 41001 @Jayant2908: I've analyzed all 7 issues against the actual code. Here's my assessment with evidence: ✅ Not Actually Issues (Code Already Handles Correctly)2. Exception Exposure - FALSE POSITIVE ❌Status: Already handled correctly in the code. Looking at the actual code:
The code already follows best practices here. 4. Hardcoded Max Values - FALSE POSITIVE ❌Status: Dynamically calculated, no hardcoding. In const maxValue = Math.max(
...this.projects.map(p => p.stats[dataKey] || 0)
);Maxima are computed dynamically from the current dataset, not hardcoded. 🔴 Should Fix in This PR (Security & Stability)3. Rate Limiting on Refresh Endpoint - VALID
|
Jayant2908
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.
Great work!! Do look at the two fixes mentioned by coderabbitai and you should be good to go!
Project Leaderboard Feature
Added a comprehensive project leaderboard that displays GitHub metrics for OWASP projects.
What's included:
Home.-.Bug.Logging.Tool.and.7.more.pages.-.Personal.-.Microsoft_.Edge.2025-12-25.16-00-08.mp4
closes #3314
Summary by CodeRabbit
New Features
Chores
UI
✏️ Tip: You can customize this high-level summary in your review settings.