Skip to content

feat: add upload pipeline timeline to CommitAdmin#717

Open
thomasrockhu-codecov wants to merge 1 commit intomainfrom
tomhu/commit-admin-pipeline-timeline
Open

feat: add upload pipeline timeline to CommitAdmin#717
thomasrockhu-codecov wants to merge 1 commit intomainfrom
tomhu/commit-admin-pipeline-timeline

Conversation

@thomasrockhu-codecov
Copy link
Copy Markdown
Contributor

@thomasrockhu-codecov thomasrockhu-codecov commented Feb 19, 2026

Summary

  • Adds a read-only Upload Pipeline Timeline field to the Django admin Commit detail page
  • Aggregates data from CommitReport, ReportSession, and UploadBreadcrumb models
  • Displays all uploads grouped by report type (Coverage, Bundle Analysis, Test Results) with state color-coding, breadcrumb events with timestamps/milestones/errors, and commit-level breadcrumbs
  • No new models or migrations required

Test plan

  • Navigate to a Commit detail page in Django admin and verify the timeline renders
  • Test with a commit that has multiple report types (coverage + BA + TR)
  • Verify breadcrumbs appear nested under their associated uploads
  • Verify commit-level breadcrumbs (no upload_ids) appear in a separate section
  • Test with a commit that has no reports (should show "No reports found")

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_timeline field to the Django admin Commit detail page.

The new view queries up to 200 UploadBreadcrumb records 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.

"</tr></thead><tbody>" + "".join(rows) + "</tbody></table>"
)

return format_html(html)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)

Fix in Cursor Fix in Web

@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 7.89474% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.18%. Comparing base (9b95e6b) to head (1ab84b7).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/codecov-api/core/admin.py 7.89% 35 Missing ⚠️
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              
Flag Coverage Δ
apiunit 96.17% <7.89%> (-0.20%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codecov-notifications
Copy link
Copy Markdown

codecov-notifications bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 7.89474% with 35 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/codecov-api/core/admin.py 7.89% 35 Missing ⚠️

📢 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>
@thomasrockhu-codecov thomasrockhu-codecov force-pushed the tomhu/commit-admin-pipeline-timeline branch from afe4c6f to 1ab84b7 Compare February 19, 2026 13:27
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

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:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

error = data.get("error", "")
error_text = data.get("error_text", "")
task_name = data.get("task_name", "")
parent_task_id = data.get("parent_task_id", "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)

Fix in Cursor Fix in Web

)

return format_html(
'<div style="max-height:600px;overflow:auto">{}</div>', format_html(table)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant