raboof / sbt-reproducible-builds   0.32

Apache License 2.0 GitHub

Make your published artifacts bit-by-bit reproducible, and compare with other certifications

Scala versions: 2.12
sbt plugins: 1.0

sbt-reproducible-builds

sbt plugin to make sbt builds more reproducible.

For general information on 'Reproducible Builds', see https://reproducible-builds.org/

This plugin provides a number of features:

  • Strip 'accidental' sources of nondeterminism (e.g. timestamps) from the packaged jar
  • Produce a 'buildinfo' file describing the build environment used and containing a cryptographic hash of the resulting artifacts.
  • Upload this (signed) certification when publishing
  • Upload this (signed) certification to a reproducible-builds-certification-repository instance
  • Check your local build against already-uploaded certifications (WiP)

Project status

This is a pre-1.0 version: you are welcome to use it, but there are no guarantees, and syntax, behaviour and default configuration may still change in future versions.

Usage

Stripping nondeterminism from artifacts

Then add to your project/plugins.sbt:

addSbtPlugin("net.bzzt" % "sbt-reproducible-builds" % "0.32")

And to build.sbt:

enablePlugins(ReproducibleBuildsPlugin)

After sbt package, the stripped artifact can be found under target/scala-${scalaBinaryVersion}/stripped/${reproducibleBuildsPackageName}-${version}.jar. The generated buildinfo that will be published along with your release will look something like this:

name=simple
group-id=net.bzzt
artifact-id=simple_2.12
version=0.1.0-SNAPSHOT
java.version=1.8.0_191
os.name=Linux
build-tool=sbt
sbt.version=1.2.3
scala.version=2.12.7
scala.binary-version=2.12
date=1546548168000
outputs.0.filename=simple_2.12-0.1.0-SNAPSHOT.pom
outputs.0.length=783
outputs.0.checksums.sha512=a24500ee9a44c55abb0b4461d4f405e4c2d988e43479a0385943226dd2487faf65a28e121b7f539b764df21ad27debed5bbf7fd07df34d413a81def2af589f1b
outputs.1.filename=simple_2.12-0.1.0-SNAPSHOT.jar
outputs.1.length=2933
outputs.1.checksums.sha512=ea059170bba44d3ecdcdcc2feee91be9fe7aa33de36ab03e0934d2455b0aa6c57c20db5e1e51f88da97007a5aa8100761d71cae83a28a34ee61f755653bf612f

Interoperability with other sbt plugins

sbt-osgi

As this plugin as well as the sbt-osgi plugin redefine the packageBin task, it is necessary to re-apply the plugin settings after the application of the osgi settings. You can find an example under src/sbt-test/sbt-reproducible-builds/osgi/build.sbt.

Describe your build as a 'buildinfo' certification

You can now generate a description of the build environment with the sbt task reproducibleBuildsCertification. This certification will also be included when publishing your project. If you want to disable this, you can set publishCertification := false.

To sign the certification, configure sbt-gpg and either simply publishLocal, or, for example if you have publishCertification := false, ReproducibleBuilds/publishLocal.

Sharing certifications

If you are a (3rd-party or 'official') rebuilder, you can use the ReproducibleBuilds/publish task to publish the buildinfo to a reproducible-builds-certification-repository instance.

Uploading certifications from Travis

Especially if you're already deploying from Travis, it can be a great start to publish certifications from Travis as well. For this, you should give Travis its own gpg key pair to sign those certifications.

An even better way might be to use the key generated by travis for this repository itself following https://docs.travis-ci.com/user/encryption-keys/

If you want to use your own key, however, start by generating a keypair with gpg --gen-key, naming it something like "Arnout Engelen (via Travis) [email protected]". Then export public and private key with gpg --export -a "Arnout Engelen (via Travis)" > public.key and gpg --export-secret-key -a "Arnout Engelen (via Travis)" > private.key. Now encrypt the private key so only Travis can read it with travis encrypt-file .travis/private.key and follow the instructions to unencrypt. Finally, gpg --import private.key public.key and sbt ReproducibleBuilds/publish to sign and upload the certification from Travis.

Checking certifications

You can check your certification against other uploaded certifications with reproducibleBuildsCheckCertification. This feature is still a work in progress.

Checking your certification with the 'official' published certification is currently not yet implemented.

Checking published artifacts

You can check your local artifacts against published ones with sbt clean reproducibleBuildsCheck. If you want to check against a different repository (such as a staging repository), you can set the reproducibleBuildsCheckResolver:

import net.bzzt.reproduciblebuilds.ReproducibleBuildsPlugin._
ThisBuild / reproducibleBuildsCheckResolver := "repository-apache-org-staging" at "https://repository.apache.org/content/groups/staging"

Drinking our own champagne

From version 0.3 onwards, sbt-reproducible-builds should itself be reproducible in the sense that building the same git tag should produce the exact same binary.

When this is not the case, this is to be considered a bug and a bug report with the binary, the buildinfo and any additional information about any peculiarities of the build system would be greatly appreciated!

Limitations

ivy.xml is not included

When using Ivy-style publishing (which is notably common for sbt plugins), the ivy.xml is not currently part of the published buildinfo. This is a problem because this file contains the transitive dependencies for the artifact, so a backdoor can be introduced by adding a rogue transitive dependency to this file. This issue is tracked under #84.

Further recommendations

Some further recommendations to make your builds more reproducible:

  • Specify scalaVersion (and if applicable crossScalaVersions) in your build configuration
  • Use sbt-strict-scala-versions to ensure always using those Scala versions (addSbtPlugin("net.bzzt" % "sbt-strict-scala-versions" % "0.0.1"))