Skip to content

Keep the debug-history archive compressed on download - #4898

Open
chalfontchubby wants to merge 3 commits into
mainfrom
fix/debug-history-archive-content-type
Open

Keep the debug-history archive compressed on download#4898
chalfontchubby wants to merge 3 commits into
mainfrom
fix/debug-history-archive-content-type

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Written by Claude Code on @chalfontchubby's behalf.

The problem

The debug-history bulk download (/debug_history_download_all, added for #4417) arrives as a bare .tar rather than the gzip tarball that was sent. Browsers that unarchive downloads do it by extension, and .tgz is one they recognise. Reproduced on a live deployment.

That breaks the feature's whole purpose, twice over. Measured on a real 15-snapshot history:

Size GitHub accepts?
what we send (.tgz) 4.6 MB yes
what the user gets (.tar) 32 MB no

GitHub's attachment limit is 25 MB, and its allowed archive types are .zip, .gz and .tgz.tar is not on the list. So the expanded download is rejected outright, and would be too large even if it weren't. Compression is doing essential work here; the download has to reach the user still compressed.

The fix

There is no server-side way to decline the unarchiving — it keys on the extension, not on the content type or Content-Disposition. Serving as application/octet-stream with nosniff was tried first and was not enough on its own (verified against a real browser, not just in tests). Both are kept as defence in depth, and they bring this route in line with the single-snapshot download, which already served octet-stream.

So the archive is named predbat_debug_history.tgz.dmp. The unarchiving leaves .dmp alone, GitHub accepts it, and the body is an ordinary gzip tarball that tar xzf reads whatever it is called — nothing needs renaming to open it.

The Debug panel link stays a plain Download all: the file is meant to be opaque and handed straight to an issue. The details are documented in customisation.md and web-interface.md for the few who need to open one themselves.

Testing

Verified on a live deployment: the download now lands as a 5.4 MB .dmp, unpacked with tar xzf, no .tar produced.

Unit tests assert the content type, the nosniff header, the .tgz.dmp filename, and — separately — that the body still starts with the gzip magic number, so serving it as opaque binary cannot quietly become serving something that is not an archive.

Full quick suite and pre-commit green.

🤖 Generated with Claude Code

The bulk download arrived as a bare .tar rather than the gzip tarball that was
sent, because browsers that unarchive downloads do it by extension and .tgz is
one they recognise.

That is fatal twice over. Measured on a real 15-snapshot history: 32MB of yaml,
4.6MB as a tarball. Unpacked it is both over GitHub's 25MB attachment limit and
a file type GitHub rejects outright - .zip, .gz and .tgz are accepted, .tar is
not - so the bug report this feature exists to gather cannot be attached at all.
Compression is doing essential work here, and the download has to reach the user
still compressed.

There is no server-side way to decline the unarchiving: it keys on the
extension, not on the content type or Content-Disposition. Serving it as
application/octet-stream with nosniff was not enough on its own, though both
are kept as defence in depth and bring this route in line with the
single-snapshot download, which already served octet-stream.

So the archive is named predbat_debug_history.tgz.dmp. The unarchiving leaves
.dmp alone, GitHub accepts it, and the body is an ordinary gzip tarball that
"tar xzf" reads whatever it is called, so nothing needs renaming to open it.

The Debug panel link stays a plain "Download all" - the file is meant to be
opaque and handed straight to an issue. The details are documented for the few
who need to open one themselves.

Tests assert the content type, nosniff, the .tgz.dmp filename, and separately
that the body still starts with the gzip magic number, so serving it as opaque
binary cannot quietly become serving something that is not an archive.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The updated docs include an incomplete tar xzf extraction command (missing filename) and one nearby note still refers to .tgz rather than .tgz.dmp, which can mislead users.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes the /debug_history_download_all bulk debug-history download so it remains gzip-compressed when saved by browsers that auto-unpack archives based on filename extension, keeping the download small enough and in an attachment-friendly form for GitHub issue uploads.

Changes:

  • Serve the bulk download as opaque binary (application/octet-stream) with X-Content-Type-Options: nosniff and a .tgz.dmp filename to prevent browser auto-unarchiving.
  • Update the web UI label to keep “Download all” user-facing while changing the on-wire filename.
  • Add/adjust unit tests and docs to assert/describe the new headers/filename behavior and gzip-ness of the body.
File summaries
File Description
docs/web-interface.md Documents the new bulk-download filename and rationale.
docs/customisation.md Updates debug-history documentation to describe the .tgz.dmp download behavior.
apps/predbat/web.py Changes the bulk download response headers/content-type and download filename to keep archives compressed on save.
apps/predbat/tests/test_web_debug_history_routes.py Extends tests to assert opaque-binary response, nosniff, .tgz.dmp filename, and gzip magic bytes.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/customisation.md Outdated
Comment thread docs/web-interface.md Outdated
@chalfontchubby chalfontchubby added the BOT_CLEANUP Trigger: bot should address PR review feedback and CI failures, then commit and push label Sep 3, 2026
@springfall2008 springfall2008 removed the BOT_CLEANUP Trigger: bot should address PR review feedback and CI failures, then commit and push label Sep 3, 2026
@springfall2008
springfall2008 requested a lite review from Copilot September 4, 2026 08:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The change directly addresses the reported browser behavior, keeps the download usable for GitHub attachments, and is covered by targeted unit tests that verify headers, filename, and gzip payload integrity.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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.

3 participants