Skip to content

Commit 43cbd9d

Browse files
committed
Correct Sbom-Location for wars, add integration tests
Closes gh-47407 Fixes gh-47408
1 parent 97ff64d commit 43cbd9d

File tree

6 files changed

+145
-6
lines changed

6 files changed

+145
-6
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ dependencies {
5353

5454
optional("org.graalvm.buildtools:native-gradle-plugin")
5555
optional("org.cyclonedx:cyclonedx-gradle-plugin") {
56-
exclude(group: "org.apache.maven", module: "maven-core")
56+
exclude(group: "javax.annotation", module: "javax.annotation-api")
57+
exclude(group: "javax.inject", module: "javax.inject")
5758
}
5859
optional("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") {
5960
exclude(group: "commons-logging", module: "commons-logging")

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CycloneDxPluginAction.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,21 @@ private void configureBootWarTask(Project project, TaskProvider<CycloneDxTask> c
9595
}
9696

9797
private void configureBootJarTask(BootJar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
98-
configureJarTask(task, cycloneDxTaskProvider);
98+
configureJarTask(task, cycloneDxTaskProvider, "");
9999
}
100100

101101
private void configureBootWarTask(BootWar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
102-
configureJarTask(task, cycloneDxTaskProvider);
102+
configureJarTask(task, cycloneDxTaskProvider, "WEB-INF/classes/");
103103
}
104104

105-
private void configureJarTask(Jar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
105+
private void configureJarTask(Jar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider,
106+
String sbomLocationPrefix) {
106107
Provider<String> sbomFileName = cycloneDxTaskProvider.map((cycloneDxTask) -> "META-INF/sbom/"
107108
+ cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask));
108109
task.manifest((manifest) -> {
109110
manifest.getAttributes().put("Sbom-Format", "CycloneDX");
110-
manifest.getAttributes().put("Sbom-Location", sbomFileName);
111+
manifest.getAttributes()
112+
.put("Sbom-Location", sbomFileName.map((fileName) -> sbomLocationPrefix + fileName));
111113
});
112114
}
113115

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.gradle.plugin;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.util.jar.JarFile;
22+
23+
import org.gradle.testkit.runner.BuildResult;
24+
import org.gradle.testkit.runner.TaskOutcome;
25+
import org.junit.jupiter.api.TestTemplate;
26+
27+
import org.springframework.boot.gradle.junit.GradleCompatibility;
28+
import org.springframework.boot.testsupport.gradle.testkit.GradleBuild;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Integration tests for {@link CycloneDxPluginAction}.
34+
*
35+
* @author Andy Wilkinson
36+
*/
37+
@GradleCompatibility
38+
class CycloneDxPluginActionIntegrationTests {
39+
40+
GradleBuild gradleBuild;
41+
42+
@TestTemplate
43+
void sbomIsIncludedInUberJar() throws IOException {
44+
sbomIsIncludedInUberArchive("bootJar", "");
45+
}
46+
47+
@TestTemplate
48+
void sbomIsIncludedInUberWar() throws IOException {
49+
sbomIsIncludedInUberArchive("bootWar", "WEB-INF/classes/");
50+
}
51+
52+
private void sbomIsIncludedInUberArchive(String taskName, String sbomLocationPrefix) throws IOException {
53+
BuildResult result = this.gradleBuild.expectDeprecationWarningsWithAtLeastVersion("7.6.6").build(taskName);
54+
assertThat(result.task(":cyclonedxBom").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
55+
File[] libs = new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles();
56+
assertThat(libs).hasSize(1);
57+
try (JarFile jar = new JarFile(libs[0])) {
58+
assertThat(jar.getManifest().getMainAttributes().getValue("Sbom-Format")).isEqualTo("CycloneDX");
59+
String sbomLocation = jar.getManifest().getMainAttributes().getValue("Sbom-Location");
60+
assertThat(sbomLocation).isEqualTo(sbomLocationPrefix + "META-INF/sbom/application.cdx.json");
61+
assertThat(jar.getEntry(sbomLocation)).isNotNull();
62+
}
63+
}
64+
65+
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/PluginClasspathGradleBuild.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
3333
import org.apache.hc.core5.http.HttpRequest;
3434
import org.apache.hc.core5.http2.HttpVersionPolicy;
35+
import org.cyclonedx.gradle.CycloneDxPlugin;
3536
import org.gradle.testkit.runner.GradleRunner;
3637
import org.jetbrains.kotlin.gradle.model.KotlinProject;
3738
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin;
@@ -92,7 +93,19 @@ private List<File> pluginClasspath() {
9293
new File(pathOfJarContaining(Toml.class)), new File(pathOfJarContaining(Lexer.class)),
9394
new File(pathOfJarContaining("org.graalvm.buildtools.gradle.NativeImagePlugin")),
9495
new File(pathOfJarContaining("org.graalvm.reachability.GraalVMReachabilityMetadataRepository")),
95-
new File(pathOfJarContaining("org.graalvm.buildtools.utils.SharedConstants")));
96+
new File(pathOfJarContaining("org.graalvm.buildtools.utils.SharedConstants")),
97+
// CycloneDx dependencies
98+
new File(pathOfJarContaining(CycloneDxPlugin.class)),
99+
new File(pathOfJarContaining("com.github.packageurl.MalformedPackageURLException")),
100+
new File(pathOfJarContaining("org.cyclonedx.parsers.Parser")),
101+
new File(pathOfJarContaining("org.apache.maven.project.MavenProject")),
102+
new File(pathOfJarContaining("org.apache.maven.model.building.ModelBuildingException")),
103+
new File(pathOfJarContaining("org.codehaus.plexus.util.xml.pull.XmlPullParserException")),
104+
new File(pathOfJarContaining("org.apache.commons.lang3.StringUtils")),
105+
new File(pathOfJarContaining("com.networknt.schema.resource.SchemaMapper")),
106+
new File(pathOfJarContaining("com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator")),
107+
new File(pathOfJarContaining("org.apache.commons.collections4.CollectionUtils")),
108+
new File(pathOfJarContaining("org.apache.commons.io.FileUtils")));
96109
}
97110

98111
private String pathOfJarContaining(String className) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the License);
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
id 'org.springframework.boot' version '{version}'
19+
id 'java'
20+
}
21+
22+
apply plugin: 'org.cyclonedx.bom'
23+
24+
group = 'com.example'
25+
version = '0.0.1'
26+
27+
tasks.named("bootJar") {
28+
mainClass = 'com.example.ExampleApplication'
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the License);
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
id 'org.springframework.boot' version '{version}'
19+
id 'war'
20+
}
21+
22+
apply plugin: 'org.cyclonedx.bom'
23+
24+
group = 'com.example'
25+
version = '0.0.1'
26+
27+
tasks.named("bootWar") {
28+
mainClass = 'com.example.ExampleApplication'
29+
}

0 commit comments

Comments
 (0)