Skip to content

Application JAR created by extract command is not reproductible #48664

@schroeder-ma

Description

@schroeder-ma

I am trying to build reproducible Docker images using spring-boot-jarmode-tools. However, the extracted application JAR file is not created reproducibly because the META-INF/MANIFEST.MF file has the current time as its last modification time. This affects the reproducibility of the Docker image as well. I have set a timestamp in Maven, so all the other files in the application JAR file have the correct last modification time. Ideally, I would like spring-boot-jarmode-tools to respect the environment variable SOURCE_DATE_EPOCH when extracting the application JAR file.

Steps to Reproduce

  1. Set the SOURCE_DATE_EPOCH environment variable.
  2. Extract the same uber JAR file twice, at different times, to different locations, using spring-boot-jarmode-tools.
  3. Compare the timestamps of the extracted files using a tool like zipinfo.
  4. Observe that the timestamps in the META-INF/MANIFEST.MF file vary.

This is the example output from a simple application:

Zip file size: 3705 bytes, number of entries: 12
-rw----     2.0 fat      930 bX defN 26-Jan-02 23:50 META-INF/MANIFEST.MF
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 META-INF/services/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 example/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 example/org/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 example/org/springframework/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 example/org/springframework/boot/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 META-INF/maven/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 META-INF/maven/example.org.springframework.boot/
-rw----     2.0 fat        0 bX defN 23-Jan-01 00:00 META-INF/maven/example.org.springframework.boot/spring-boot-example/
-rw----     2.0 fat      804 bX defN 23-Jan-01 00:00 example/org/springframework/boot/SpringBootExampleApplication.class
-rw----     2.0 fat     1071 bX defN 23-Jan-01 00:00 META-INF/maven/example.org.springframework.boot/spring-boot-example/pom.xml
-rw----     2.0 fat       86 bX defN 23-Jan-01 00:00 META-INF/maven/example.org.springframework.boot/spring-boot-example/pom.properties

All files except META-INF/MANIFEST.MF have a fixed timestamp that I defined in Maven (2023-01-01T00:00:00Z).

This was tested with Spring Boot 4.0.1.

Expected Behavior

The JAR file should be created reproducibly, meaning all file modification times should be fixed and not based on the current time.

Actual Behavior

The META-INF/MANIFEST.MF file in the resulting JAR has the current time as its last modification time, making the JAR file non-reproducible.

Relevant Code

The issue is in the class org.springframework.boot.jarmode.tools.ExtractCommand. The class uses a standard JarOutputStream for the application JAR file, which writes the MANIFEST.MF file in its constructor and does not set an explicit timestamp.

Proposed Solution

I have a working solution that contains a new subclass of JarOutputStream which overrides JarOutputStream#putNextEntry to set a fixed timestamp (the value of SOURCE_DATE_EPOCH). I'd be happy to submit that, or any other solution, as a PR.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions