-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make goreleaser archives reproducible #6299
Merged
derekcollison
merged 1 commit into
nats-io:main
from
alexbozhenko:goreleaser_reproducible
Dec 23, 2024
Merged
Make goreleaser archives reproducible #6299
derekcollison
merged 1 commit into
nats-io:main
from
alexbozhenko:goreleaser_reproducible
Dec 23, 2024
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
a6e8d60
to
48d31ed
Compare
Signed-off-by: Alex Bozhenko <[email protected]>
48d31ed
to
7751bc9
Compare
wallyqs
approved these changes
Dec 23, 2024
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, the binary is already reproducible but this would make the tarballs from the release reproducible as well.
derekcollison
added a commit
that referenced
this pull request
Jan 23, 2025
Similar to #6299 Make packages set mtime to `commitdate`. Upgrade goreleaser to the latest 2.6.1, which includes the feature used in this PR: goreleaser/goreleaser#5392 ``` go install github.com/goreleaser/goreleaser/[email protected] goreleaser release --snapshot --clean -f .goreleaser.yml mv dist/ ~/tmp/dist_before goreleaser release --snapshot --clean -f .goreleaser.yml # now, all the artifacts of the two builds are exactly the same. Only sbom files are different(because those include timestamps) vimdiff dist/SHA256SUMS ~/tmp/dist_before/SHA256SUMS ```  Signed-off-by: Alex Bozhenko <[email protected]>
derekcollison
added a commit
that referenced
this pull request
Feb 20, 2025
## Details We have reproducible binaries, [rpms/debs](#6359) and [archives](#6299). And `goreleaser.yml` holds [all the knobs](https://goreleaser.com/customization/builds/go/) that can be tuned to build the binary. The only thing that affects the build and is not defined in the goreleaser config is the go toolchain version. Currently, we set the version of the go toolchain that is used for releases in Travis: <https://github.com/nats-io/nats-server/blob/5e6017135b4b1d333b435ff55b720275a39bb7af/.travis.yml#L11-L12> <https://github.com/nats-io/nats-server/blob/5e6017135b4b1d333b435ff55b720275a39bb7af/.travis.yml#L67> I spent some time [trying to understand the behavior of go and toolchain directives](https://alexbozhenko.github.io/posts/2024-12-19-understand-go-toolchain-directive-or-your-money-back/). I think setting the toolchain used for releases in .goreleser.yml would make it more explicit and future-proof. With this change, any human or script who has `go>1.21.0` and goreleaser installed can checkout the repo at any commit, run one command, and get binaries that will be _exactly_ as if we were cutting a release on that commit. ``` goreleaser build --snapshot --clean --single-target ``` Several places would benefit from not having to worry about keeping toolchain and all the go build flags in sync: * get-nats.io(already uses gorelaser, but toolchain used to build depends on the build host): <https://github.com/ConnectEverything/client-tools/blob/eba999ac9a1e107205fbf89ba230df3f80458028/build-nightlies.sh#L184-L188> * <redacted> number of private repos If we land this, we can update the above places to use `goreleaser build`, thus making sure we use _exactly the same_ binary everywhere, and forever forget about managing/updating go versions in other places that need to build the binary ## Reproducible test plan ### Before Behavior is not hermetic. We depend on toolchain that happens to be installed on the build host. 1. <details> <summary>Local go(`1.21.0`) < one that is specified in go.mod. Go will download and use toolchain from go.mod:</summary> ``` # go version go version go1.21.0 linux/amd64 # TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target # go version -m dist/nats-server_linux_amd64_v1/nats-server | grep go1 dist/nats-server_linux_amd64_v1/nats-server: go1.22.8 ``` </details> 2. <details> <summary>Local go(`1.23.3`) > one that is specified in go.mod. Local toolchain will be used:</summary> ``` # wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz # sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.3.linux-amd64.tar.gz # go version go version go1.23.3 linux/amd64 # TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target # go version -m dist/nats-server_linux_amd64_v1/nats-server | grep go1 dist/nats-server_linux_amd64_v1/nats-server: go1.23.3 ``` </details> ### After 1. <details> <summary>Local go version (1.23.4) did not affect what was used for the binary</summary> It will download (just like it [downloads all the modules](https://youtu.be/KqTySYYhPUE?feature=shared&t=229)) the version of the toolchain specified in goreleaer config, and use it for building the binary. ``` # go version go version go1.23.4 linux/amd64 # TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target # go version -m dist/nats-server_linux_amd64_v1/nats-server | grep go1 dist/nats-server_linux_amd64_v1/nats-server: go1.23.5 # sha256sum dist/nats-server_linux_amd64_v1/nats-server 95d52ed8656f74abd0c0576d8d9be50fcc00562c8e18215d1f1f04b8c0b6fc3d dist/nats-server_linux_amd64_v1/nats-server ``` </details> 2. <details> <summary>Any go >= go1.21.0 (released 2023-08-08) will build exactly the same binary:</summary> ``` # wget <https://go.dev/dl/go1.21.0.linux-amd64.tar.gz> # sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz # go version go version go1.21.0 linux/amd64 # TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target # go version -m dist/nats-server_linux_amd64_v1/nats-server | grep go1 dist/nats-server_linux_amd64_v1/nats-server: go1.23.5 # sha256sum dist/nats-server_linux_amd64_v1/nats-server 95d52ed8656f74abd0c0576d8d9be50fcc00562c8e18215d1f1f04b8c0b6fc3d dist/nats-server_linux_amd64_v1/nats-server ``` </details> 3. To build using specific toolchain one would set the `GORELEASER_TOOLCHAIN` env variable: ``` # GORELEASER_TOOLCHAIN="go1.22.8" TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target # go version -m dist/nats-server_linux_amd64_v1/nats-server | grep go1 dist/nats-server_linux_amd64_v1/nats-server: go1.22.8 ``` Note that starting from go1.24.0 we can use the [tool directive](https://tip.golang.org/doc/modules/managing-dependencies#tools ) in go.mod, and even version goreleaser itself. It will look something like this: ``` go tool goreleaser build --snapshot --clean --single-target ```
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Use commit time in mod_timestamp, as documented in:
https://goreleaser.com/customization/builds/#reproducible-builds
https://goreleaser.com/blog/reproducible-builds/
https://goreleaser.com/customization/templates/?h=templates#common-fields
Test plan:
Before.
Build two times:
Observe all the shasums are different:

After:
Do the build two times,
Observe that only rpm and deb packages are different

There was a feature added to goreleaser to make packages reproducible too, but I haven't figured out how to use it yet:
goreleaser/nfpm#748
I asked in Discord. We can tackle that separately
Signed-off-by: Alex Bozhenko [email protected]