From 43d91aee384e83b6e4d3a2195141547d8c1f315e Mon Sep 17 00:00:00 2001 From: Dmitrii Karagodin <4319788@gmail.com> Date: Fri, 19 Sep 2025 21:59:00 +0300 Subject: [PATCH] Write signature files to uber wars for Oracle Java 17 verification Extend commit 33c5e126 to include uber Wars. See gh-47284 Signed-off-by: Dmitrii Karagodin <4319788@gmail.com> --- .../tasks/bundling/BootArchiveSupport.java | 10 ++- .../boot/gradle/tasks/bundling/BootJar.java | 2 +- .../boot/gradle/tasks/bundling/BootWar.java | 4 +- .../tasks/bundling/BootZipCopyAction.java | 7 +-- .../AbstractBootArchiveIntegrationTests.java | 12 ++++ .../bundling/BootJarIntegrationTests.java | 12 ---- .../BootWarIntegrationTests-signed.gradle | 36 +++++++++++ .../boot/loader/tools/Repackager.java | 3 +- .../boot/maven/WarIntegrationTests.java | 8 +++ .../src/intTest/projects/war-signed/pom.xml | 63 +++++++++++++++++++ .../main/java/org/test/SampleApplication.java | 24 +++++++ 11 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-signed.gradle create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/src/main/java/org/test/SampleApplication.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java index 241eb571260..396c46faa9b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java @@ -122,13 +122,12 @@ class BootArchiveSupport { } CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies, - LoaderImplementation loaderImplementation, boolean supportsSignatureFile) { - return createCopyAction(jar, resolvedDependencies, loaderImplementation, supportsSignatureFile, null, null); + LoaderImplementation loaderImplementation) { + return createCopyAction(jar, resolvedDependencies, loaderImplementation, null, null); } CopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies, - LoaderImplementation loaderImplementation, boolean supportsSignatureFile, LayerResolver layerResolver, - String jarmodeToolsLocation) { + LoaderImplementation loaderImplementation, LayerResolver layerResolver, String jarmodeToolsLocation) { File output = jar.getArchiveFile().get().getAsFile(); Manifest manifest = jar.getManifest(); boolean preserveFileTimestamps = jar.isPreserveFileTimestamps(); @@ -143,8 +142,7 @@ class BootArchiveSupport { String encoding = jar.getMetadataCharset(); CopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, dirPermissions, filePermissions, includeDefaultLoader, jarmodeToolsLocation, requiresUnpack, exclusions, launchScript, - librarySpec, compressionResolver, encoding, resolvedDependencies, supportsSignatureFile, layerResolver, - loaderImplementation); + librarySpec, compressionResolver, encoding, resolvedDependencies, layerResolver, loaderImplementation); return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java index c5b3514e9b3..ff58b32eec3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -150,7 +150,7 @@ public abstract class BootJar extends Jar implements BootArchive { layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary); } String jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null; - return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, true, layerResolver, + return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, layerResolver, jarmodeToolsLocation); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java index 0b401734cfd..4979a235c16 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java @@ -124,8 +124,8 @@ public abstract class BootWar extends War implements BootArchive { layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary); } String jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null; - return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, false, - layerResolver, jarmodeToolsLocation); + return this.support.createCopyAction(this, this.resolvedDependencies, loaderImplementation, layerResolver, + jarmodeToolsLocation); } @SuppressWarnings("removal") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java index e891fea3fa3..0eb16258fb7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java @@ -114,8 +114,6 @@ class BootZipCopyAction implements CopyAction { private final ResolvedDependencies resolvedDependencies; - private final boolean supportsSignatureFile; - private final LayerResolver layerResolver; private final LoaderImplementation loaderImplementation; @@ -124,7 +122,7 @@ class BootZipCopyAction implements CopyAction { boolean includeDefaultLoader, String jarmodeToolsLocation, Spec requiresUnpack, Spec exclusions, LaunchScriptConfiguration launchScript, Spec librarySpec, Function compressionResolver, String encoding, - ResolvedDependencies resolvedDependencies, boolean supportsSignatureFile, LayerResolver layerResolver, + ResolvedDependencies resolvedDependencies, LayerResolver layerResolver, LoaderImplementation loaderImplementation) { this.output = output; this.manifest = manifest; @@ -140,7 +138,6 @@ class BootZipCopyAction implements CopyAction { this.compressionResolver = compressionResolver; this.encoding = encoding; this.resolvedDependencies = resolvedDependencies; - this.supportsSignatureFile = supportsSignatureFile; this.layerResolver = layerResolver; this.loaderImplementation = loaderImplementation; } @@ -363,7 +360,7 @@ class BootZipCopyAction implements CopyAction { } private void writeSignatureFileIfNecessary() throws IOException { - if (BootZipCopyAction.this.supportsSignatureFile && hasSignedLibrary()) { + if (hasSignedLibrary()) { writeEntry("META-INF/BOOT.SF", (out) -> { }, false); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java index e6cc7b41c4d..266b935e220 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java @@ -49,6 +49,7 @@ import org.apache.commons.compress.archivers.zip.UnixStat; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.BuildTask; import org.gradle.testkit.runner.TaskOutcome; import org.junit.jupiter.api.TestTemplate; @@ -647,6 +648,17 @@ abstract class AbstractBootArchiveIntegrationTests { } } + @TestTemplate + void signed() throws IOException { + BuildTask task = this.gradleBuild.build(this.taskName).task(":" + this.taskName); + assertThat(task).isNotNull(); + assertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + File jar = new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0]; + try (JarFile jarFile = new JarFile(jar)) { + assertThat(jarFile.getEntry("META-INF/BOOT.SF")).isNotNull(); + } + } + private void copyMainClassApplication() throws IOException { copyApplication("main"); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java index 4f7135c9234..9f4d3979448 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java @@ -16,15 +16,12 @@ package org.springframework.boot.gradle.tasks.bundling; -import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Set; import java.util.TreeSet; -import java.util.jar.JarFile; import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.TaskOutcome; import org.junit.jupiter.api.TestTemplate; import org.springframework.boot.gradle.junit.GradleCompatibility; @@ -45,15 +42,6 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests { super("bootJar", "BOOT-INF/lib/", "BOOT-INF/classes/", "BOOT-INF/"); } - @TestTemplate - void signed() throws Exception { - assertThat(this.gradleBuild.build("bootJar").task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); - File jar = new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0]; - try (JarFile jarFile = new JarFile(jar)) { - assertThat(jarFile.getEntry("META-INF/BOOT.SF")).isNotNull(); - } - } - @TestTemplate void whenAResolvableCopyOfAnUnresolvableConfigurationIsResolvedThenResolutionSucceeds() { this.gradleBuild.expectDeprecationWarningsWithAtLeastVersion("8.0").build("build"); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-signed.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-signed.gradle new file mode 100644 index 00000000000..c1c9216e0d5 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-signed.gradle @@ -0,0 +1,36 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id 'war' + id 'java' + id 'org.springframework.boot' version '{version}' +} + +bootWar { + mainClass = 'com.example.Application' +} + +repositories { + mavenCentral() + maven { + url = 'repository' + } +} + +dependencies { + implementation("org.bouncycastle:bcprov-jdk18on:1.78.1") +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java index bd12f6fe060..49cb0d365c6 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java @@ -51,7 +51,8 @@ public class Repackager extends Packager { @Override protected void writeSignatureFileIfNecessary(Map writtenLibraries, AbstractJarWriter writer) throws IOException { - if (getSource().getName().toLowerCase(Locale.ROOT).endsWith(".jar") && hasSignedLibrary(writtenLibraries)) { + String sourceName = getSource().getName().toLowerCase(Locale.ROOT); + if ((sourceName.endsWith(".jar") || sourceName.endsWith(".war")) && hasSignedLibrary(writtenLibraries)) { writer.writeEntry("META-INF/BOOT.SF", (entryWriter) -> { }); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java index 8415f348c54..f2e3c8fb728 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java @@ -253,4 +253,12 @@ class WarIntegrationTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenSigned(MavenBuild mavenBuild) { + mavenBuild.project("war-signed").execute((project) -> { + File repackaged = new File(project, "target/war-signed-0.0.1.BUILD-SNAPSHOT.war"); + assertThat(jar(repackaged)).hasEntryWithName("META-INF/BOOT.SF"); + }); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/pom.xml new file mode 100644 index 00000000000..551c164846d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + org.springframework.boot.maven.it + war-signed + 0.0.1.BUILD-SNAPSHOT + war + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + some.random.Main + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + org.bouncycastle + bcprov-jdk18on + 1.78.1 + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..547d0cf0171 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-signed/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +}