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


OpenSSF Best Practices

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.


Stripping nondeterminism from artifacts

Then add to your project/plugins.sbt:

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

And to build.sbt:


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:


Interoperability with other sbt plugins


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!


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.

External interfaces

This plugin fetches artifacts and attestations to compare against the built artifacts from the configured repositories.

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"))


If you find a security issue in this project, please email [email protected] . Those reports will be treated confidentially.