Gobuild: reproducible binaries with the Go module proxy

Gobuild deterministically compiles programs written in Go that are available through the Go module proxy, and returns the binary.

The Go module proxy ensures source code stays available, and you are highly likely to get the same code each time you fetch it. Gobuild aims to do the same for binaries.

Try a module

Recent builds

Notes about this gobuild instance

Builds are verified against https://gobuild02.gobuilds.org, a linux/arm64 gobuild instance.

URLs

You can compose URLs to a specific module, build or result:

Examples

The first URL fetches the requested Go module to find the commands (main packages). In case of a single command, it redirects to a URL of the second form. In case of multiple commands, it lists them, linking to URLs of the second form. Links are to the latest module and Go versions, and with goos/goarch guessed based on user-agent.

The second URL first resolves "latest" for the module and Go version with a redirect. For URLs with explicit versions, it starts a build for the requested parameters if no build is available yet. After a successful build, it redirects to a URL of the third kind.

The third URL represents a successful build. The URL includes the sum: The versioned raw-base64-url-encoded 20-byte prefix of the sha256 sum. The page links to the binary, the build output log file, and to builds of the same command with different module versions, goversions, goos/goarch.

You need not and cannot refresh a successful build: it would yield the same result.

Transparency log

Gobuild maintains a transparency log containing the hashes of all successful builds, similar to the Go module checksum database. Gobuild's "get" subcommand looks up a content hash through the transparency log, locally keeping track of the last known tree state. This ensures the list of successful builds and their hashes is append-only, and modifications or removals by the server will be detected when you run "gobuild get".

Examples

gobuild get github.com/mjl-/gobuild@latest
gobuild get -sum 0N7e6zxGtHCObqNBDA_mXKv7-A9M -target linux/amd64 -goversion go1.14.1 github.com/mjl-/gobuild@v0.0.8

If you run your own gobuild instance, specify the verifierkey on the command-line:

gobuild get -verifierkey beta.gobuilds.org+3979319f+AReBl47t6/Zl24/pmarcKhJtsfAU2c1F5Wtu4hrOgOQQ ...

Details

Only "go build" is run, for pure Go code. None of "go test", "go generate", build tags, cgo, custom compile/link flags, makefiles, etc. This means gobuild cannot build all Go applications.

Gobuild looks up module versions through the Go module proxy. That's why shorthand versions like "@v1" don't resolve.

The go.mod of a project must be complete and clean: no missing dependencies, no replace statements, module name must match requested build.

Gobuild automatically downloads a Go toolchain (SDK) from https://go.dev/dl/ when it is first referenced. It also periodically queries that page for the latest supported releases, for redirecting to the latest supported toolchains.

Gobuild can be configured to verify builds with other gobuild instances, requiring all to return the same hash for a build to be considered successful.

To build, gobuild executes:

GO19CONCURRENTCOMPILATION=0 GO111MODULE=on GOPROXY=https://proxy.golang.org/ \
	CGO_ENABLED=0 GOOS=$goos GOARCH=$goarch GOTOOLCHAIN=$goversion \
	$goversion install -trimpath -ldflags=-buildid= -- $module/$package@$version

For the stripped variant, -ldflags='-buildid= -s' is used.

It's easy to run a local or internal gobuild instance. For configuration details, see this empty example config.

Code is available at github.com/mjl-/gobuild, under MIT-license.

Why gobuild

Get binaries for any module without having a Go toolchain installed: Useful when working on a machine that's not yours, or for your colleagues or friends who don't have a Go compiler installed.

Simplify your software release process: You no longer need to cross compile for many architectures and upload binaries to a release page. You never forget a GOOS/GOARCH target. Just link to the build URL for your module and binaries will be created on demand.

Binaries for the most recent Go toolchain: Go binaries include the runtime and standard library of the Go toolchain used to compile, including bugs. Gobuild links or can redirect to binaries built with the latest Go toolchain, so no need to publish new binaries after an updated Go toolchain is released.

Verify reproducibility: Configure gobuild to check against other gobuild instances with different configuration to build trust that your binaries are indeed reproducible.

Caveats

A central service like gobuilds.org that provides binaries is an attractive target for attackers. By only building code available through the Go module proxy, and only building with official Go toolchains, the options for attack are limited. Further security measures are the isolation of the gobuild proces and of the build commands (minimal file system view, mostly read-only; limited network; disallowing escalation of privileges).

The transparency log is only used when downloading binaries using the "gobuild get" command, which uses and updates the users local cache of the signed append-only transparency log with hashes of built binaries. If users only download binaries through the convenient web interface, no verification of the transparency log takes place. The transparency log gives the option of verification, that alone may give users confidence the binaries are not tampered with. A nice way of continuously verifying that a gobuild instance, such as gobuilds.org, is behaving correctly is to set up your own gobuild instance that uses gobuilds.org as URL to verify builds against.

Gobuild will build binaries with different (typically newer) Go toolchains than an author has tested their software with. So those binaries are essentially untested. This may cause bugs. However, point releases typically contain only stability/security fixes that don't normally cause issues and are desired. The Go 1 compatibility promise means code will typically work as intended with new Go toolchain versions. But an author can always link to a build with a specific Go toolchain version. A user simply has the additional option to download a build by a newer Go toolchain version.

gobuild v0.0.27 go1.22.5 on linux/amd64