-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Reproducible build #8213
base: master
Are you sure you want to change the base?
Reproducible build #8213
Conversation
Thank you for submitting this PR!
Getting other community members to do a review would be great help too on complex PRs (you can ask in the chats/forums). If you are unsure about something, just leave us a comment.
We currently aim to provide initial feedback/triaging within two business days. Please keep an eye on any labelling actions, as these will indicate priorities and status of your contribution. |
@@ -12,7 +12,8 @@ GOTFLAGS ?= | |||
unexport GOFLAGS | |||
# Override so we can combine with the user's go flags. | |||
# Try to make building as reproducible as possible by stripping the go path. | |||
override GOFLAGS += "-asmflags=all='-trimpath=$(GOPATH)'" "-gcflags=all='-trimpath=$(GOPATH)'" |
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.
There be balrogs here.
I need to be able to:
- Checkout the go-ipfs source locally.
- Run
make install
. - Checkout the https://github.com/ipfs/go-ds-s3/ reop.
- Run
make install IPFS_VERSION=/path/to/go-ipfs/source
(s3 datastore plugin). - Start the IPFS daemon, correctly loading the s3 plugin.
Unfortunately, we've found that:
- The bare
-trimpath
flag works with plugins when go-ipfs is built withgo build github.com/...
. - The bare
-trimpath
flag does not work with plugins when go-ipfs is built withmake build
.
Somewhere in the deep dark reaches of Khazad-dûm (the go compiler), the plugin loader gets confused.
If you can figure out how to reconcile this... I'll be very happy.
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.
Looking into this now.
Some interesting things I found when building without bare -trimpath
.
The only difference between binaries is this path not being trimmed.
/tmp/go-build971257389/b082/_cgo_gotypes.go
I'm guessing this is another issue with the compiler. Maybe an easier one to fix than the plugin loader.
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.
Note: I haven't checked this for at least one go release cycle. The situation may have improved.
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.
It seems the situation has not improved golang/go#31354.
Building the plugins within the same path as the application seems to be a viable option.
This project is able to build plugins with -trimpath
via this method.
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.
I've managed to get the go-ds-s3 plugin working by building inside of the IPFS project root.
Steps I've taken to produce the binary and plugin:
Clone go-ds-s3
repo to extensions
folder.
Copy go.mod
to extensions.mod
Copy go.sum
to extensions.sum
Edit extensions.mod
with the following:
require (
...
github.com/ipfs/go-ds-s3 v0.0.0
)
replace github.com/ipfs/go-ds-s3 => ./extensions/go-ds-s3
Edit extensions/go-ds-s3/go.mod
with the following:
replace github.com/ipfs/go-ipfs => ../../
Copy line below from extensions/go-ds-s3/go.sum
to extensions.sum
github.com/ipfs/go-ipfs v0.8.0/go.mod h1:iU9jeKJrinNYdWSNZyTjpfcmGHH4oflEySOUboEQsoQ=
Build go-ipfs with -trimpath
GOFLAGS=-trimpath make build
Build go-ds-s3 plugin with -trimpath
go build -trimpath -modfile extensions.mod --buildmode=plugin -o s3plugin.so extensions/go-ds-s3/plugin/main/main.go
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.
That's a pretty big step backwards in terms of usability. Plugins are already confusing.
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.
What happens if you use -trimpaths
and the asm/gcflags?
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.
Another acceptable solution would be to make the Makefile not override user-provided flags, but instead set defaults.
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.
That's a pretty big step backwards in terms of usability. Plugins are already confusing.
I totally agree. My goal was to first find a solution and then work on developer ergonomics. Possibly a Dockerfile with everything setup or a script that automates the steps above. I'm hoping to move everything to https://github.com/ipfs/distributions once I find an acceptable solution.
What happens if you use
-trimpaths
and the asm/gcflags?
Using the asm/gcflags somehow overrides -trimpath
and causes the build to be non reproducible. The Go team suggests to avoid using those flags and use -trimpath
instead.
Update: I tried a build using both asm/gcflags and -trimpath
. It was not compatible with plugins.
Another acceptable solution would be to make the Makefile not override user-provided flags, but instead set defaults.
I think this is a good solution. I wasn't able to successfully set -ldflags
via GOFLAGS
but that is probably my lack of experience with Makefiles.
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.
I've managed to reduce the steps as well as allow building from an outside directory.
Clone go-ipfs
and go-ds-s3
to the same directory.
git clone -b v0.8.0 https://github.com/ipfs/go-ipfs.git
git clone -b v0.7.0 https://github.com/ipfs/go-ds-s3.git
Edit the ./go-ds-s3/go.mod
.
go mod edit -replace "github.com/ipfs/go-ipfs=../go-ipfs"
Edit the ./go-ipfs/go.mod
.
go mod edit -require="github.com/ipfs/[email protected]"
go mod edit -replace "github.com/ipfs/go-ipfs=../go-ds-s3"
go mod tidy
# I'm unsure why this is required but possibly due to nested directory structure
go get github.com/ipfs/go-ds-s3/plugin
Comment out this line in ./go-ipfs/mk/golang.mk
.
#override GOFLAGS += "-asmflags=all='-trimpath=$(GOPATH)'" "-gcflags=all='-trimpath=$(GOPATH)'"
Build ipfs
from ./go-ipfs
:
GOFLAGS=-trimpath make build
Build go-ds-s3
from ./go-ipfs
:
go build -trimpath --buildmode=plugin -o go-ds-s3.so ../go-ds-s3/plugin/main/main.go
@@ -13,7 +13,7 @@ PATH := $(realpath $(d)):$(PATH) | |||
# DEPS_OO_$(d) += merkledag/pb/merkledag.pb.go namesys/pb/namesys.pb.go | |||
# DEPS_OO_$(d) += pin/internal/pb/header.pb.go unixfs/pb/unixfs.pb.go | |||
|
|||
$(d)_flags =-ldflags="-X "github.com/ipfs/go-ipfs".CurrentCommit=$(git-hash)" | |||
$(d)_flags =-ldflags="-X "github.com/ipfs/go-ipfs".CurrentCommit=$(git-hash) -s -w -buildid=" | |||
|
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.
Just grabbing this as a spot for a GitHub thread.
It depends what type of reproducible build you're going for. For example, the builds produced for dist.ipfs.io (at least the Linux ones at the moment) have support for CGO which IIUC means that your steps for reproducibility also need to include a shared understanding of the C compiler used.
It's reasonably possible that we'll be releasing binaries built with CGO support in more platforms in the future (e.g. Windows + OS X) if we want to support databases like SQLite, or other libraries which which require CGO.
The area that seems more likely to be able to deal with reproducible builds in this context is within https://github.com/ipfs/distributions. We recently moved over to using Docker containers to do the builds which should help out on the reproducibility front. However, we can make plenty of changes there without running into issues with local builds, etc. since people doing local builds are unlikely to use the heavier deployment + cross compilation machinery in ipfs/distributions.
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.
We are aiming to have reproducible builds for multi-factor releases (multiple parties sign off on the same binary.). CGO support would be preferable as we want to release the same set of binaries as dist.ipfs.io.
I agree having it in the distributions repository makes more sense. My limited understanding of Makefiles is why I ended up copying those build flags in directly. I will make a PR on the distributions repo once I solve the plugin issue.
I was sent to this issue while investigating the rebuild failure on reproducible.archlinux.org and the patch I've appended below makes the package reproducible for us. As @nasdf says, the asm/gcflags interfere with
|
My understanding is that this PR is still undergoing work. I'm going to switch it to a draft PR and whenever this is ready for review (i.e. builds pass, we have tests confirming plugins still work, there aren't unrelated dependencies added to go-ipfs, etc.) please switch back to a non-draft PR and reach out. Thanks for taking a look at this 😄. |
Sooo... Arch does reproduceable builds right now. Can we upstream these changes? :) |
These changes are required to make the build reproducible.
-s -w
flags toldflags
strips out non-deterministic debug info.buildid
to an empty value removes the random go build id.trimpath
flag should be set viaGOFLAGS=-trimpath
.This is the Dockerfile I've been using to test for deterministic binaries.
This script will run the build and print a sha256 of the final binary.
Still need to test cross compiling for all platforms. Any feedback would be appreciated.