$ cd HelloWorld
$ mvn clean install
...
[INFO] Downloading the Internet...
[INFO] Running tons of plugins...
...
[INFO] BUILD SUCCESS
$ sha256sum target/hello-1.0-SNAPSHOT.jar
87de0b[...]7ca9 target/hello-1.0-SNAPSHOT.jar
Thomas Lorblanchès
21/04/2016
Toutes les versions des plugins spécifiées dans le pom
Aucune dépendance SNAPSHOT
Utilisation de maven-enforcer-plugin (règles requirePluginVersions et requireReleaseVersion)
Et pourtant…
$ cd HelloWorld
$ mvn clean install
...
[INFO] Downloading the Internet...
[INFO] Running tons of plugins...
...
[INFO] BUILD SUCCESS
$ sha256sum target/hello-1.0-SNAPSHOT.jar
87de0b[...]7ca9 target/hello-1.0-SNAPSHOT.jar
$ mvn clean install
...
[INFO] BUILD SUCCESS
$ sha256sum target/hello-1.0-SNAPSHOT.jar
2f3167[...]86ab target/hello-1.0-SNAPSHOT.jar
Prouver qu’un binaire donné et bien issu de la compilation de sources données.
Qualité logicielle (erreur humaine)
Sécurité informatique (corruption intentionnelle)
S’assurer de la cohérence entre paquet source et paquet binaire
Maven Central : mylib-1.0.0.jar et mylib-1.0.0-sources.jar
Distributions Linux : openjdk-8-jdk_8u72-b05_amd64.deb et openjdk-8_8u72-b05[.orig.tar.gz/.dsc/.diff.gz]
It should be possible to reproduce, byte for byte, every build of every package in Debian. — https://wiki.debian.org/ReproducibleBuilds |
2007 : Discussions sur debian-devel
2011 : Compilation déterministe de Bitcoin
2013 : Affaire Snowden
2013 : Compilation déterministe de Tor Browser
2013 : Démarrage du projet "Debian reproducible builds"
A l’intérieur de l’archive
hello-1.0-SNAPSHOT/
├── Main.class
└── META-INF
├── MANIFEST.MF # Non reproductible
└── maven
└── prez
└── hello
├── pom.properties # Non reproductible
└── pom.xml
Dans le format de l’archive (ZIP)
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: thomas # Non reproductible
Created-By: Apache Maven 3.0.5 # "Peu" reproductible
Build-Jdk: 1.8.0_72-internal # "Peu" reproductible
#Generated by Apache Maven
#Tue Feb 23 18:02:52 CET 2016 # Non reproductible
version=1.0-SNAPSHOT
groupId=prez
artifactId=hello
File / Central directory file headers
File last modification time
File last modification date
Extra field : X5455_ExtendedTimestamp
Ordre d’insertion des fichiers
Bug JAXB-598 pour les versions antérieures à JAXB 2.2.11
Ordre des méthodes du fichier ObjectFactory.java généré par xjc non reproductible
⇒ Fichier ObjectFactory.class non reproductible !
Java 8 inclut JAXB 2.2.8
3 lignes non reproductibles.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="fr">
<head>
<!-- Generated by javadoc (1.8.0_72-internal) on Thu Feb 25 17:37:57 CET 2016 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Main (hello 1.0-SNAPSHOT API)</title>
<meta name="date" content="2016-02-25">
[...]
<!-- ======== END OF BOTTOM NAVBAR ======= -->
<p class="legalCopy"><small>Copyright © 2016. All rights reserved.</small></p>
</body>
</html>
Avec option "-notimestamp" de javadoc :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- NewPage -->
<html lang="fr">
<head>
<!-- Generated by javadoc -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Main (hello 1.0-SNAPSHOT API)</title>
[...]
<!-- ======== END OF BOTTOM NAVBAR ======= -->
<p class="legalCopy"><small>Copyright © 2016. All rights reserved.</small></p>
</body>
</html>
println "Hello World!"
Compilation puis décompilation :
groovyc hello.groovy
java -jar procyon-decompiler-0.5.30.jar hello.class
public class hello extends Script
{
public static /* synthetic */ long __timeStamp;
public static /* synthetic */ long __timeStamp__239_neverHappen1442922905877;
private static /* synthetic */ SoftReference $callSiteArray;
[...]
static {
__$swapInit();
test.__timeStamp__239_neverHappen1442922905877 = 0L;
test.__timeStamp = 1442922905877L;
}
[...]
}
Classe groovy.lang.GroovyClassLoader :
protected void addTimeStamp(ClassNode node) {
if (node.getDeclaredField(Verifier.__TIMESTAMP) == null)
FieldNode timeTagField = new FieldNode(Verifier.__TIMESTAMP,
ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.long_TYPE, node,
new ConstantExpression(System.currentTimeMillis()));
timeTagField.setSynthetic(true);
node.addField(timeTagField);
timeTagField = new FieldNode(
Verifier.__TIMESTAMP__ + System.currentTimeMillis(),
ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.long_TYPE, node,
new ConstantExpression((long) 0));
timeTagField.setSynthetic(true);
node.addField(timeTagField);
}
}
<plugin>
<groupId>io.github.zlika</groupId>
<artifactId>reproducible-build-maven-plugin</artifactId>
<version>0.2</version>
</plugin>
Goals : strip-jar, strip-jaxb