Skip to content

fix(download): 403/401 and 0-byte downloads are errors, not success - #186

Merged
fentas merged 1 commit into
mainfrom
fix/download-trust
Aug 28, 2026
Merged

fix(download): 403/401 and 0-byte downloads are errors, not success#186
fentas merged 1 commit into
mainfrom
fix/download-trust

Conversation

@fentas

@fentas fentas commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Summary

The download trust pair: a 403/401 response or a 0-byte landing can no longer be reported as a successful download.

Fixes #161
Fixes #163

#161 — empty case http.StatusForbidden:

The status switch in downloadPreset (pkg/binary/download.go) had an empty case http.StatusForbidden:. Go cases do not fall through, so a 403 matched the empty case, returned nil, and the forbidden body was read as the binary. Now:

  • 403 and 401 hard-error via a shared accessDeniedError helper.
  • A rate-limit-shaped response (X-RateLimit-Remaining: 0 header, or a body mentioning "rate limit") gets the hint: rate limit exhausted; set GITHUB_TOKEN to authenticate.
  • Other 403/401 responses get: access denied; check credentials (for GitHub, set GITHUB_TOKEN).
  • The same handling is applied to downloadAsset (provider path), and the 429 message now carries the retry/GITHUB_TOKEN hint too.

#163 — "updated … done!" with 0 B on disk

The raw-binary write paths reported success without checking that any bytes landed. A new verifyWritten check runs after the copy in both downloadPreset and downloadAsset:

  • 0 bytes written -> download of <file> wrote 0 bytes: the server sent an empty body; retry the download
  • byte count differs from a server-sent Content-Length -> download of <file> is incomplete: wrote N bytes, Content-Length is M; retry the download

Tests

httptest-based, in pkg/binary/binary_test.go:

  • 403 + X-RateLimit-Remaining: 0 -> error mentioning GITHUB_TOKEN, no file written
  • 403 + "rate limit" body -> error mentioning GITHUB_TOKEN
  • plain 403 / 401 -> status-named errors
  • 200 + empty body -> 0-byte error naming the file (preset and asset paths)
  • 200 + body -> success, file content byte-equal to the served body

Mutation-checked: re-blanking the 403 case fails all three 403 tests; disabling the 0-byte check fails both empty-body tests. go build ./... && go test ./... green; gofmt -l clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_016DJzGS3pNBzZs1jaEQ74Co

Two trust fixes in the download path:

- The empty `case http.StatusForbidden:` in downloadPreset silently
  matched 403 responses and returned nil, so the forbidden body was
  read as a successful download. 403 and 401 now hard-error via
  accessDeniedError, which detects rate-limit-shaped responses
  (X-RateLimit-Remaining: 0 or a body mentioning "rate limit") and
  hints to set GITHUB_TOKEN. Applied to both downloadPreset and
  downloadAsset. (#161)

- The raw-binary write paths reported success without checking that
  any bytes landed. verifyWritten now rejects 0-byte writes and
  Content-Length mismatches with an error naming the file and the
  observed size, so "updated ... done!" can no longer mask a failed
  download. (#163)

Tests (httptest): 403 with rate-limit header/body -> GITHUB_TOKEN
hint; plain 403 and 401 -> status-named errors; 200 empty body ->
0-byte error; 200 with body -> success with content verified.
Mutation-checked: re-blanking the 403 case fails all three 403
tests; disabling the 0-byte check fails both empty-body tests.

Fixes #161
Fixes #163

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016DJzGS3pNBzZs1jaEQ74Co
@fentas
fentas merged commit 782f5ed into main Aug 28, 2026
8 checks passed
@fentas
fentas deleted the fix/download-trust branch August 28, 2026 06:14
fentas pushed a commit that referenced this pull request Aug 30, 2026
🤖 I have created a release *beep* *boop*
---


## [4.18.7](v4.18.6...v4.18.7)
(2026-08-28)


### Bug Fixes

* **download:** 403/401 and 0-byte downloads are errors, not success
([#186](#186))
([782f5ed](782f5ed))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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.

Failed binary download reports success ('done!' with 0 B) bug(binary): empty case http.StatusForbidden treats 403 downloads as success

1 participant