feat: add upload pipeline timeline to CommitAdmin#717
feat: add upload pipeline timeline to CommitAdmin#717thomasrockhu-codecov wants to merge 1 commit intomainfrom
Conversation
apps/codecov-api/core/admin.py
Outdated
| "</tr></thead><tbody>" + "".join(rows) + "</tbody></table>" | ||
| ) | ||
|
|
||
| return format_html(html) |
There was a problem hiding this comment.
XSS via unescaped data in format_html call
Medium Severity
The entire HTML string is built with f-strings embedding database values (error_text, milestone, error, upload.state, upload.upload_type), then passed to format_html(html) with no format arguments. Without args, format_html simply marks the pre-built string as safe — none of the interpolated values are HTML-escaped. The error_text field is a free-form string with no HTML sanitization, making this a stored XSS in the admin panel. Django 5.0+ deprecates this usage and 6.0+ will raise a ValueError.
Additional Locations (2)
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #717 +/- ##
==========================================
- Coverage 92.25% 92.18% -0.07%
==========================================
Files 1302 1302
Lines 47837 47875 +38
Branches 1628 1628
==========================================
+ Hits 44131 44134 +3
- Misses 3397 3432 +35
Partials 309 309
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Add an upload_pipeline_timeline readonly field to the Django admin CommitAdmin page that queries UploadBreadcrumb records for the commit and renders them as an HTML table. The timeline shows: - Timestamp of each breadcrumb - Task name (Celery task that produced the breadcrumb) - Parent task ID (preceding task in the chain) - Detail (milestone, endpoint, error info) - Upload IDs associated with each breadcrumb Depends on PR #714 for new BreadcrumbData fields (task_name, parent_task_id) and lock lifecycle milestones. Co-authored-by: Cursor <cursoragent@cursor.com>
afe4c6f to
1ab84b7
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| color = "#388e3c" | ||
| elif milestone in ("la", "pu", "nt"): | ||
| color = "#1565c0" | ||
| else: |
There was a problem hiding this comment.
Milestone color-coding values don't match actual enum
Medium Severity
The milestone color-coding checks for values "lac", "lr", and "la" which don't exist in the Milestones enum. The actual enum values are fcd, cp, pfr, rfr, wfcu, cu, pu, nt, uc, ns. This means multiple milestones that are supposed to display as green or blue will instead fall through to the default gray color, making the timeline less useful.
| error = data.get("error", "") | ||
| error_text = data.get("error_text", "") | ||
| task_name = data.get("task_name", "") | ||
| parent_task_id = data.get("parent_task_id", "") |
There was a problem hiding this comment.
Referencing non-existent fields from breadcrumb data model
Medium Severity
The code extracts task_name and parent_task_id from breadcrumb_data, but BreadcrumbData is a Pydantic model with extra="forbid" that only permits milestone, endpoint, uploader, error, and error_text. These fields can never exist in the data, so the "Task" and "Parent Task ID" table columns will always be empty, wasting space in the timeline UI.
Additional Locations (1)
| ) | ||
|
|
||
| return format_html( | ||
| '<div style="max-height:600px;overflow:auto">{}</div>', format_html(table) |
There was a problem hiding this comment.
Unescaped user data in HTML creates XSS risk
Low Severity
HTML table rows are constructed using f-strings with values from breadcrumb_data (especially error_text, a free-form string), then the entire string is passed to format_html(table) with no substitution arguments, which is equivalent to mark_safe. This bypasses Django's auto-escaping. The rest of the codebase consistently uses format_html with placeholder arguments for dynamic values.


Summary
CommitReport,ReportSession, andUploadBreadcrumbmodelsTest plan
Made with Cursor
Note
Low Risk
Admin-only UI addition that reads existing breadcrumb data and doesn’t change processing logic or persisted data; main risk is performance/formatting issues on commits with many breadcrumbs.
Overview
Adds a new read-only
upload_pipeline_timelinefield to the Django adminCommitdetail page.The new view queries up to 200
UploadBreadcrumbrecords for the commit/repo and renders them as a scrollable, color-coded HTML table showing timestamp, task/parent task IDs, milestone/endpoint/error details, and related upload IDs (or an empty-state message when none exist).Written by Cursor Bugbot for commit 1ab84b7. This will update automatically on new commits. Configure here.