Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output jar includes timestamps, not hermetic (want singlejar) #19

Closed
joeljeske opened this issue Mar 6, 2020 · 6 comments
Closed

Output jar includes timestamps, not hermetic (want singlejar) #19

joeljeske opened this issue Mar 6, 2020 · 6 comments

Comments

@joeljeske
Copy link

The packaging step uses jar. That creates an archive with time stamps, yielding the artifact not hermetic. Bazel internally uses singlejar to package up jars which sets timestamps to a fixed value.

Have you considered using singlejar for its packaging (or another packaging tool), or somehow create a jar that has fixed timestamps and other varying bytes removed.

@plaird
Copy link
Contributor

plaird commented Mar 7, 2020

Good suggestion. I think singlejar is the right way.

That being said, I remember trying this in the prehistoric days of this rule but it didn't work. My notes are below. In short, the Spring Boot launcher couldn't handle a 0 timestamp on the internal files.

The intent was to circle back on this issue later on (and maybe file a bug against Spring Boot), but we ended up closing it during a backlog cleanup. The reason is for our internal use cases we care a lot more about the inputs being hermetic (see buildstamp docs) so remote cache would work, less about the output being hermetic since nothing ever depends on our springboot output in our build.

But, now that springboot rule is a public repo, we should do the right thing. singlejar is the right way, so this is a good issue.

====

This seems to be unique to Spring Boot 2.x. I suspect there is a bug in the spring boot loader infra, possibly introduced by this change:
spring-projects/spring-boot@6081db5

I think this is aggravated by something not handling TZ correctly. Bazel generates artifacts with timestamps of 0 and the Spring Boot loader assumes Jar epoch is Jan 1 1980. When the GMT offset is applied (e.g. -7 for Colorado) that becomes an invalid date/time for Spring Boot. When Simon generates the same artifact on his computer in Japan TZ, everything works and the timestamp of BOOT-INF/lib artifacts is Jan 1 1980 at 9am.

Full stack trace:
Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 0
at java.time.temporal.ValueRange.checkValidValue(ValueRange.java:311)
at java.time.temporal.ChronoField.checkValidValue(ChronoField.java:703)
at java.time.LocalDate.of(LocalDate.java:267)
at java.time.LocalDateTime.of(LocalDateTime.java:336)
at org.springframework.boot.loader.jar.CentralDirectoryFileHeader.decodeMsDosFormatDateTime(CentralDirectoryFileHeader.java:130)
at org.springframework.boot.loader.jar.CentralDirectoryFileHeader.getTime(CentralDirectoryFileHeader.java:119)
at org.springframework.boot.loader.jar.JarEntry.(JarEntry.java:55)
at org.springframework.boot.loader.jar.JarFileEntries.getEntry(JarFileEntries.java:252)
at org.springframework.boot.loader.jar.JarFileEntries.access$400(JarFileEntries.java:45)
at org.springframework.boot.loader.jar.JarFileEntries$EntryIterator.next(JarFileEntries.java:302)
at org.springframework.boot.loader.jar.JarFileEntries$EntryIterator.next(JarFileEntries.java:286)
at org.springframework.boot.loader.jar.JarFile$2.nextElement(JarFile.java:196)
at org.springframework.boot.loader.jar.JarFile$2.nextElement(JarFile.java:187)
at org.springframework.boot.loader.archive.JarFileArchive$EntryIterator.next(JarFileArchive.java:186)
at org.springframework.boot.loader.archive.JarFileArchive$EntryIterator.next(JarFileArchive.java:171)
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:84)
at org.springframework.boot.loader.ExecutableArchiveLauncher.getClassPathArchives(ExecutableArchiveLauncher.java:70)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:49)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)

@joeljeske
Copy link
Author

Interesting. Well, this may have been fixed for you if you still have the code to invoke single jar lying around.

I believe they changed the default date to Jan 1 2010, and could be confirmed by extracting any of the other jars in your output base.

https://github.com/bazelbuild/bazel/blob/46b285a8044d8c2dcf292f40b6b74bd99d66b430/src/tools/singlejar/output_jar.cc#L320

@joeljeske
Copy link
Author

Do you still have the code for packaging with singlejar. I had some difficulty figuring out how to setup that dep pipeline properly to get singlejar and invoke it.

@plaird
Copy link
Contributor

plaird commented Mar 19, 2020

I think so. This was done in the Bazel 0.5.2 era, and we have moved the rule around a few times internally in Git repos. But I think I should be able to find it. I have it on my list, I will try to get to it today.

@plaird
Copy link
Contributor

plaird commented Mar 20, 2020

@joeljeske
So the bad news is I don't think I ever had singlejar hooked up to the springboot rule. I also can't remember what I changed in the rule that worked around the timestamp problem above. Normally I put such details in bug reports, but I didn't in this case.

The good news is I implemented singlejar this evening, and it is now available as a branch. Since it is a big change, I am hoping you can verify it. I tested manually both by invoking the jar directly, and also with bazel run.

java -jar bazel-bin/samples/helloworld/helloworld.jar
bazel run samples/helloworld

I have also hooked it up to our build internally, and all of our services passed tests with the change. I think it is good to go.

Branch: https://github.com/salesforce/bazel-springboot-rule/tree/plaird/singlejar

WORKSPACE import:
git_repository(
    name = "bazel_springboot_rule",
    remote = "https://github.com/salesforce/bazel-springboot-rule.git",
    commit = "b4e065f1e706e6762cad022413b089789cd4a666"
)

@plaird plaird changed the title Packaging with jar includes timestamps in resulting in non-determinism Output jar includes timestamps, not hermetic (want singlejar) Mar 25, 2020
@plaird
Copy link
Contributor

plaird commented Mar 25, 2020

This ran for 5 days in our internal CI and we did some actual deployments with it. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

No branches or pull requests

2 participants