Bug description
Every nightly appcast served from files.cmux.com currently advertises this response header:
content-type: application/x-www-form-urlencoded
These are Sparkle XML/RSS documents and should be served as application/xml (or another appropriate XML media type). The GitHub release assets are recorded as application/xml; the bad metadata is on the R2 copies used by installed apps.
This is not the cause of the updater stall in #12279—Sparkle successfully parsed the feed there—but it is a release-pipeline defect that can cause strict clients, gateways, content sniffing, or future Sparkle behavior to mishandle the feed.
Reproduction
for feed in appcast.xml appcast-arm64.xml appcast-x86_64.xml appcast-universal.xml; do
curl -sSI "https://files.cmux.com/nightly/$feed" \
| grep -iE '^(HTTP/|content-type:|content-length:|last-modified:)'
done
Observed 2026-09-10 after successful nightly run https://github.com/manaflow-ai/cmux/actions/runs/34536136724:
appcast.xml
HTTP/2 200
content-type: application/x-www-form-urlencoded
content-length: 3634
last-modified: Thu, 10 Sep 2026 22:25:53 GMT
appcast-arm64.xml
HTTP/2 200
content-type: application/x-www-form-urlencoded
content-length: 3609
last-modified: Thu, 10 Sep 2026 22:25:52 GMT
appcast-x86_64.xml
HTTP/2 200
content-type: application/x-www-form-urlencoded
content-length: 3614
last-modified: Thu, 10 Sep 2026 22:25:53 GMT
appcast-universal.xml
HTTP/2 200
content-type: application/x-www-form-urlencoded
content-length: 3634
last-modified: Thu, 10 Sep 2026 22:25:53 GMT
All four documents are well-formed enough for Sparkle to load; the defect is their stored HTTP metadata.
Root cause
.github/workflows/nightly.yml uploads each feed through:
python3 scripts/ci/upload-r2-object.py --file ... --key nightly/<appcast> ...
In scripts/ci/upload-r2-object.py, _build_signed_request adds cache-control, x-amz-content-sha256, and x-amz-date, but no content-type. For a PUT with a byte body, urllib.request.Request supplies Content-Type: application/x-www-form-urlencoded; R2 stores that metadata and Cloudflare returns it to clients.
The recent per-architecture nightly work expanded the upload loop to all four feeds, so the same bad default is now applied consistently to the universal, arm64, and x86_64 tracks.
Expected behavior
- XML appcasts are uploaded with an explicitly signed/stored
Content-Type: application/xml (or application/rss+xml).
- The uploader either accepts an explicit
--content-type or safely infers it from the file extension; callers for non-XML immutable objects can specify their own type.
- Dry-run/request tests assert the
Content-Type header and its inclusion in SigV4 signed headers.
- The four current nightly R2 keys are republished so a
HEAD request reports the correct media type.
Bug description
Every nightly appcast served from
files.cmux.comcurrently advertises this response header:content-type: application/x-www-form-urlencodedThese are Sparkle XML/RSS documents and should be served as
application/xml(or another appropriate XML media type). The GitHub release assets are recorded asapplication/xml; the bad metadata is on the R2 copies used by installed apps.This is not the cause of the updater stall in #12279—Sparkle successfully parsed the feed there—but it is a release-pipeline defect that can cause strict clients, gateways, content sniffing, or future Sparkle behavior to mishandle the feed.
Reproduction
Observed 2026-09-10 after successful nightly run https://github.com/manaflow-ai/cmux/actions/runs/34536136724:
All four documents are well-formed enough for Sparkle to load; the defect is their stored HTTP metadata.
Root cause
.github/workflows/nightly.ymluploads each feed through:In
scripts/ci/upload-r2-object.py,_build_signed_requestaddscache-control,x-amz-content-sha256, andx-amz-date, but nocontent-type. For aPUTwith a byte body,urllib.request.RequestsuppliesContent-Type: application/x-www-form-urlencoded; R2 stores that metadata and Cloudflare returns it to clients.The recent per-architecture nightly work expanded the upload loop to all four feeds, so the same bad default is now applied consistently to the universal, arm64, and x86_64 tracks.
Expected behavior
Content-Type: application/xml(orapplication/rss+xml).--content-typeor safely infers it from the file extension; callers for non-XML immutable objects can specify their own type.Content-Typeheader and its inclusion in SigV4 signed headers.HEADrequest reports the correct media type.