Skip to content

fix(release): make archives reproducible so winget hashes match - #121

Merged
timvw merged 1 commit into
mainfrom
fix/reproducible-release-archives
Aug 11, 2026
Merged

fix(release): make archives reproducible so winget hashes match#121
timvw merged 1 commit into
mainfrom
fix/reproducible-release-archives

Conversation

@timvw

@timvw timvw commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Problem

microsoft/winget-pkgs#410145 (0.1.31) was rejected with Error-Hash-Mismatch:

Actual hash:   E26E53D675395CAF80417F1F7A7647CAC4808A1C0E7EE29C833A4BD3CB1E8369
Expected hash: ebc56b3224fd8b627995ec1d3a33d5da6507242690d8050c78f69c888f22fbfa

The published asset is fine — the manifest's hash was wrong.

release.yml runs GoReleaser twice, both with --clean: step 1 builds and uploads the release assets (--skip=winget), step 2 rebuilds everything from scratch to publish winget only (WT_WINGET_ONLY=1, release upload disabled). Archive members carried build/checkout mtimes, so step 2's rebuild produced byte-different archives. The winget manifest got step 2's hash while the release kept step 1's bytes.

This started with 5c616e2 (the two-step split, 2026-07-08): 0.1.29 predates it and its manifest hash matches; 0.1.31 does not.

Fix

  • builds: -trimpath and mod_timestamp: '{{ .CommitTimestamp }}'
  • archives: builds_info.mtime plus explicit LICENSE*/README* entries with pinned mtime — the default globs carried checkout time and mattered as much as the binary
  • migrate format / format_overrides.format to plural formats (singular deprecated since v2.6)

Verification

Two consecutive goreleaser release --snapshot --clean runs:

config windows zip, run 1 run 2
before f9d17d80… 61b22038…
after 4226751f… 4226751f…

All five archives byte-identical after the change. goreleaser check passes (the brews deprecation warning is pre-existing).

The 0.1.31 manifest hash was corrected directly on the winget PR branch; this change prevents a recurrence.

The release workflow runs GoReleaser twice (core with --skip=winget, then
best-effort winget-only), both with --clean. The second run rebuilds from
scratch, and since archive members carried build/checkout mtimes the rebuilt
archives hashed differently than the ones the first run had already uploaded
to the GitHub release. The winget manifest is generated by the second run, so
it shipped a hash no published asset matched -- microsoft/winget-pkgs#410145
was rejected with Error-Hash-Mismatch for 0.1.31.

Pin the binary timestamp (mod_timestamp), add -trimpath, and pin the mtime of
every archive member including the default LICENSE/README globs.

Verified: two consecutive `goreleaser release --snapshot --clean` runs now
produce byte-identical archives for all five targets; before this change the
same two runs produced different hashes.

Also migrates format/format_overrides.format to the plural `formats` form
(singular deprecated since v2.6).
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 37.71%. Comparing base (253789e) to head (a0a8e65).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #121      +/-   ##
==========================================
+ Coverage   37.62%   37.71%   +0.09%     
==========================================
  Files          28       28              
  Lines        3216     3216              
==========================================
+ Hits         1210     1213       +3     
+ Misses       1917     1913       -4     
- Partials       89       90       +1     

see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timvw
timvw merged commit c4e7e43 into main Aug 11, 2026
16 checks passed
@timvw
timvw deleted the fix/reproducible-release-archives branch August 11, 2026 06:52
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