Skip to content

Commit b7589a1

Browse files
committed
Raise the minimum supported version of the CycloneDX plugin to 3.0.0
Closes gh-47250
1 parent 2a9ad4b commit b7589a1

File tree

7 files changed

+55
-50
lines changed

7 files changed

+55
-50
lines changed

build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ When the {url-native-build-tools-docs-gradle-plugin}[GraalVM Native Image plugin
9797

9898
When the {url-cyclonedx-docs-gradle-plugin}[CycloneDX plugin] is applied to a project, the Spring Boot plugin:
9999

100-
. Configures the `cyclonedxBom` task to use the `application` project type and output the SBOM to the `application.cdx` file in JSON format without full license texts.
100+
. Configures the `cyclonedxBom` task to:
101+
.. Use the `application` project type.
102+
.. Output a JSON-format SBOM to the `application.cdx.json` file.
103+
.. Disable the XML-format SBOM.
104+
.. Disable full license texts.
101105
. Adds the SBOM under `META-INF/sbom` in the generated jar or war file.
102106
. Adds the `Sbom-Format` and `Sbom-Location` to the manifest of the jar or war file.
Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616

1717
package org.springframework.boot.gradle.plugin;
1818

19-
import org.cyclonedx.gradle.CycloneDxPlugin;
20-
import org.cyclonedx.gradle.CycloneDxTask;
19+
import org.cyclonedx.gradle.CyclonedxAggregateTask;
20+
import org.cyclonedx.gradle.CyclonedxPlugin;
21+
import org.cyclonedx.model.Component;
2122
import org.gradle.api.Action;
2223
import org.gradle.api.Plugin;
2324
import org.gradle.api.Project;
@@ -34,93 +35,90 @@
3435
import org.springframework.boot.gradle.tasks.bundling.BootWar;
3536

3637
/**
37-
* {@link Action} that is executed in response to the {@link CycloneDxPlugin} being
38+
* {@link Action} that is executed in response to the {@link CyclonedxPlugin} being
3839
* applied.
3940
*
4041
* @author Moritz Halbritter
42+
* @author Andy Wilkinson
4143
*/
42-
final class CycloneDxPluginAction implements PluginApplicationAction {
44+
final class CyclonedxPluginAction implements PluginApplicationAction {
4345

4446
@Override
4547
public Class<? extends Plugin<? extends Project>> getPluginClass() {
46-
return CycloneDxPlugin.class;
48+
return CyclonedxPlugin.class;
4749
}
4850

4951
@Override
5052
public void execute(Project project) {
51-
TaskProvider<CycloneDxTask> cycloneDxTaskProvider = project.getTasks()
52-
.named("cyclonedxBom", CycloneDxTask.class);
53-
configureCycloneDxTask(cycloneDxTaskProvider);
53+
TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider = project.getTasks()
54+
.named("cyclonedxBom", CyclonedxAggregateTask.class);
55+
configureCycloneDxTask(cycloneDxTaskProvider, project);
5456
configureJavaPlugin(project, cycloneDxTaskProvider);
5557
configureSpringBootPlugin(project, cycloneDxTaskProvider);
5658
}
5759

58-
private void configureCycloneDxTask(TaskProvider<CycloneDxTask> taskProvider) {
60+
private void configureCycloneDxTask(TaskProvider<CyclonedxAggregateTask> taskProvider, Project project) {
5961
taskProvider.configure((task) -> {
60-
task.getProjectType().convention("application");
61-
task.getOutputFormat().convention("json");
62-
task.getOutputName().convention("application.cdx");
62+
task.getProjectType().convention(Component.Type.APPLICATION);
63+
task.getXmlOutput().unsetConvention();
64+
task.getJsonOutput()
65+
.convention(project.getLayout().getBuildDirectory().file("reports/cyclonedx/application.cdx.json"));
6366
task.getIncludeLicenseText().convention(false);
6467
});
6568
}
6669

67-
private void configureJavaPlugin(Project project, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
70+
private void configureJavaPlugin(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
6871
configurePlugin(project, JavaPlugin.class, (javaPlugin) -> {
6972
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
7073
SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
7174
configureTask(project, main.getProcessResourcesTaskName(), Copy.class, (copy) -> {
7275
copy.dependsOn(cycloneDxTaskProvider);
73-
Provider<String> sbomFileName = cycloneDxTaskProvider
74-
.map((cycloneDxTask) -> cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask));
75-
copy.from(cycloneDxTaskProvider, (spec) -> spec.include(sbomFileName.get()).into("META-INF/sbom"));
76+
Provider<String> sbomFileName = cycloneDxTaskProvider.flatMap(
77+
(cycloneDxTask) -> cycloneDxTask.getJsonOutput().map((file) -> file.getAsFile().getName()));
78+
copy.from(cycloneDxTaskProvider,
79+
(spec) -> spec.include((element) -> element.getName().equals(sbomFileName.get()))
80+
.into("META-INF/sbom"));
7681
});
7782
});
7883
}
7984

80-
private void configureSpringBootPlugin(Project project, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
85+
private void configureSpringBootPlugin(Project project,
86+
TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
8187
configurePlugin(project, SpringBootPlugin.class, (springBootPlugin) -> {
8288
configureBootJarTask(project, cycloneDxTaskProvider);
8389
configureBootWarTask(project, cycloneDxTaskProvider);
8490
});
8591
}
8692

87-
private void configureBootJarTask(Project project, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
93+
private void configureBootJarTask(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
8894
configureTask(project, SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class,
8995
(bootJar) -> configureBootJarTask(bootJar, cycloneDxTaskProvider));
9096
}
9197

92-
private void configureBootWarTask(Project project, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
98+
private void configureBootWarTask(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
9399
configureTask(project, SpringBootPlugin.BOOT_WAR_TASK_NAME, BootWar.class,
94100
(bootWar) -> configureBootWarTask(bootWar, cycloneDxTaskProvider));
95101
}
96102

97-
private void configureBootJarTask(BootJar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
103+
private void configureBootJarTask(BootJar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
98104
configureJarTask(task, cycloneDxTaskProvider, "");
99105
}
100106

101-
private void configureBootWarTask(BootWar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider) {
107+
private void configureBootWarTask(BootWar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {
102108
configureJarTask(task, cycloneDxTaskProvider, "WEB-INF/classes/");
103109
}
104110

105-
private void configureJarTask(Jar task, TaskProvider<CycloneDxTask> cycloneDxTaskProvider,
111+
private void configureJarTask(Jar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider,
106112
String sbomLocationPrefix) {
107-
Provider<String> sbomFileName = cycloneDxTaskProvider.map((cycloneDxTask) -> "META-INF/sbom/"
108-
+ cycloneDxTask.getOutputName().get() + getSbomExtension(cycloneDxTask));
113+
Provider<String> sbomFileName = cycloneDxTaskProvider
114+
.map((cycloneDxTask) -> "META-INF/sbom/" + cycloneDxTask.getJsonOutput().get().getAsFile().getName());
109115
task.manifest((manifest) -> {
110116
manifest.getAttributes().put("Sbom-Format", "CycloneDX");
111117
manifest.getAttributes()
112118
.put("Sbom-Location", sbomFileName.map((fileName) -> sbomLocationPrefix + fileName));
113119
});
114120
}
115121

116-
private String getSbomExtension(CycloneDxTask task) {
117-
String format = task.getOutputFormat().get();
118-
if ("all".equals(format)) {
119-
return ".json";
120-
}
121-
return "." + format;
122-
}
123-
124122
private <T extends Task> void configureTask(Project project, String name, Class<T> type, Action<T> action) {
125123
project.getTasks().withType(type).configureEach((task) -> {
126124
if (task.getName().equals(name)) {

build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private void registerPluginActions(Project project, Configuration bootArchives)
148148
List<PluginApplicationAction> actions = Arrays.asList(new JavaPluginAction(singlePublishedArtifact),
149149
new WarPluginAction(singlePublishedArtifact), new DependencyManagementPluginAction(),
150150
new ApplicationPluginAction(), new KotlinPluginAction(), new NativeImagePluginAction(),
151-
new CycloneDxPluginAction());
151+
new CyclonedxPluginAction());
152152
for (PluginApplicationAction action : actions) {
153153
withPluginClassOfAction(action,
154154
(pluginClass) -> project.getPlugins().withType(pluginClass, (plugin) -> action.execute(project)));
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.util.List;
22+
import java.util.jar.JarEntry;
2123
import java.util.jar.JarFile;
2224

2325
import org.gradle.testkit.runner.BuildResult;
@@ -31,12 +33,12 @@
3133
import static org.assertj.core.api.Assertions.assertThat;
3234

3335
/**
34-
* Integration tests for {@link CycloneDxPluginAction}.
36+
* Integration tests for {@link CyclonedxPluginAction}.
3537
*
3638
* @author Andy Wilkinson
3739
*/
3840
@GradleCompatibility
39-
class CycloneDxPluginActionIntegrationTests {
41+
class CyclonedxPluginActionIntegrationTests {
4042

4143
@SuppressWarnings("NullAway.Init")
4244
GradleBuild gradleBuild;
@@ -61,7 +63,8 @@ private void sbomIsIncludedInUberArchive(String taskName, String sbomLocationPre
6163
assertThat(jar.getManifest().getMainAttributes().getValue("Sbom-Format")).isEqualTo("CycloneDX");
6264
String sbomLocation = jar.getManifest().getMainAttributes().getValue("Sbom-Location");
6365
assertThat(sbomLocation).isEqualTo(sbomLocationPrefix + "META-INF/sbom/application.cdx.json");
64-
assertThat(jar.getEntry(sbomLocation)).isNotNull();
66+
List<String> entryNames = jar.stream().map(JarEntry::getName).toList();
67+
assertThat(entryNames).contains(sbomLocation);
6568
}
6669
}
6770

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
3030
import org.apache.hc.core5.http.HttpRequest;
3131
import org.apache.hc.core5.http2.HttpVersionPolicy;
32-
import org.cyclonedx.gradle.CycloneDxPlugin;
32+
import org.cyclonedx.gradle.CyclonedxPlugin;
3333
import org.gradle.testkit.runner.GradleRunner;
3434
import org.jetbrains.kotlin.gradle.fus.BuildUidService;
3535
import org.jetbrains.kotlin.gradle.model.KotlinProject;
@@ -113,20 +113,20 @@ private List<File> pluginClasspath() {
113113
classpath.add(new File(pathOfJarContaining("org.graalvm.buildtools.gradle.NativeImagePlugin")));
114114
classpath.add(new File(pathOfJarContaining("org.graalvm.reachability.GraalVMReachabilityMetadataRepository")));
115115
classpath.add(new File(pathOfJarContaining("org.graalvm.buildtools.utils.SharedConstants")));
116-
// CycloneDx dependencies
117-
classpath.add(new File(pathOfJarContaining(CycloneDxPlugin.class)));
118-
classpath.add(new File(pathOfJarContaining("com.github.packageurl.MalformedPackageURLException")));
119-
classpath.add(new File(pathOfJarContaining("org.cyclonedx.parsers.Parser")));
120-
classpath.add(new File(pathOfJarContaining("org.apache.maven.project.MavenProject")));
121-
classpath.add(new File(pathOfJarContaining("org.apache.maven.model.building.ModelBuildingException")));
122-
classpath.add(new File(pathOfJarContaining("org.codehaus.plexus.util.xml.pull.XmlPullParserException")));
123-
classpath.add(new File(pathOfJarContaining("org.apache.commons.lang3.StringUtils")));
124-
classpath.add(new File(pathOfJarContaining("com.networknt.schema.resource.SchemaMapper")));
116+
// Cyclonedx dependencies
117+
classpath.add(new File(pathOfJarContaining(CyclonedxPlugin.class)));
118+
classpath.add(new File(pathOfJarContaining("com.ctc.wstx.api.WriterConfig")));
125119
classpath.add(new File(pathOfJarContaining("com.fasterxml.jackson.core.Versioned")));
126120
classpath.add(new File(pathOfJarContaining("com.fasterxml.jackson.databind.JsonSerializer")));
127121
classpath.add(new File(pathOfJarContaining("com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator")));
122+
classpath.add(new File(pathOfJarContaining("com.github.packageurl.MalformedPackageURLException")));
123+
classpath.add(new File(pathOfJarContaining("com.google.common.collect.ImmutableMap")));
124+
classpath.add(new File(pathOfJarContaining("com.networknt.schema.resource.SchemaMappers")));
128125
classpath.add(new File(pathOfJarContaining("org.apache.commons.collections4.CollectionUtils")));
129-
classpath.add(new File(pathOfJarContaining("org.apache.commons.io.FileUtils")));
126+
classpath.add(new File(pathOfJarContaining("org.apache.maven.model.building.ModelBuildingException")));
127+
classpath.add(new File(pathOfJarContaining("org.codehaus.plexus.util.xml.pull.XmlPullParserException")));
128+
classpath.add(new File(pathOfJarContaining("org.codehaus.stax2.ri.Stax2WriterAdapter")));
129+
classpath.add(new File(pathOfJarContaining("org.cyclonedx.model.ExternalReference")));
130130
return classpath;
131131
}
132132

documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/build.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Gradle users can achieve the same result by using the {url-cyclonedx-docs-gradle
112112
[source,gradle]
113113
----
114114
plugins {
115-
id 'org.cyclonedx.bom' version '2.3.0'
115+
id 'org.cyclonedx.bom' version '3.0.0'
116116
}
117117
----
118118

platform/spring-boot-internal-dependencies/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ bom {
7777
]
7878
}
7979
}
80-
library("CycloneDX Gradle Plugin", "2.3.0") {
80+
library("CycloneDX Gradle Plugin", "3.0.1") {
8181
group("org.cyclonedx") {
8282
modules = [
8383
"cyclonedx-gradle-plugin"

0 commit comments

Comments
 (0)