Configuring for Reproducible Builds

What are Reproducible Builds?

Reproducible builds are a set of software development practices that create an independently-verifiable path from source to binary code. A build is reproducible if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.

Reproducible Central lists projects releases that have been checked as reproducible by rebuilding independently from the reference build published in Central Repository.

How do I configure my Maven build?

There is no Maven version prerequisite. Everything happens at plugin level:

  1. Upgrade your plugins to reproducible versions: to easily detect required upgrades, run
    mvn artifact:check-buildplan
  2. Enable Reproducible Builds mode for plugins, by adding project.build.outputTimestamp property to the project's pom.xml:
       <properties>
         <project.build.outputTimestamp>2023-01-01T00:00:00Z</project.build.outputTimestamp>
       </properties>

You have the basics configured. The output should be mostly reproducible now.

How to test my Maven build reproducibility?

Using maven-artifact-plugin's compare goal, you can easily check that the second build of your project produce the same output than an initial build:

  1. build and install your project (don't hesitate to customize arguments to better match your project):
    mvn clean install 
  2. rebuild (verify only, without installing) and check against the previous install:
    mvn clean verify artifact:compare

Notice that this does NOT really prove that your build is yet reproducible, because your build may still suffer from environment leaks (username, current directory, ...). But it is easy to do, and prevents basic non-reproducible issues like timestamps. Really checking reproducibility requires to rebuild from a completely different setup: this is harder to do, even if containers may ease the task.

How to fix my Maven build reproducibility?

If something is still not reproducible after initial setup and automatic check from artifact:check-buildplan:

  1. Use diffoscope to find the unstable output between builds. The artifact:buildinfo goal proposes a command with path to files: just copy/paste to launch.
  2. Find the plugin that generated this output.
  3. Check if a reproducible version of the plugin is available. If not, please open an issue to help plugin maintainers improving Reproducible Builds support at every plugin level.

More Details

Reproducible Builds for Maven:

  • Require no version ranges in dependencies,
  • Generally give different results on Windows and Unix because of different newlines. (carriage return linefeed on Windows, linefeed on Unixes)
  • Generally depend on the major version of the JDK used to compile. (Even with source/target defined, each major JDK version changes the generated bytecode)

For detailed explanations, see Maven "Reproducible/Verifiable Builds" Wiki page.

FAQ

  • Q. Can the project.build.outputTimestamp property in pom.xml be updated automatically at release time?

    A. Yes.

    Details depend on your release process tooling:

    • if you use maven-release-plugin, you'll need version 3.0.0-M1 or later: it will automatically update the timestamp value in pom.xml during the release in the same commit that updates version,
    • if you have a custom release process tooling, you'll need to add the feature to your release tooling. Notice that if you're using versions-maven-plugin in custom release scripts, starting with release 2.9.0, versions:set goal updates the property.
    • instead of explicitely writing a timestamp in their pom.xml, some people tend to prefer using last Git commit timestamp, like ${git.commit.time} from git-commit-id-maven-plugin (with <dateFormatTimeZone>UTC</dateFormatTimeZone> to be independent from user's timezone).

Don't hesitate to share your questions or solutions on user mailing-list.