diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java index 932c112c2..1b61b9080 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/api/Module_contains_Test.java @@ -30,7 +30,7 @@ class Module_contains_Test { @Test void singleModuleProject() { String rootPom = PomBuilder - .buiildPom("com.example:parent:1.0") + .buildPom("com.example:parent:1.0") .type("jar") .withModules("module1", "module2") .build(); @@ -66,19 +66,19 @@ public class SomeClassTest {} @Test void multiModuleProject() { String rootPom = PomBuilder - .buiildPom("com.example:parent:1.0") + .buildPom("com.example:parent:1.0") .type("pom") .withModules("module1", "module2") .build(); String module1Pom = PomBuilder - .buiildPom("com.example:parent:1.0", "module1") + .buildPom("com.example:parent:1.0", "module1") .unscopedDependencies("com.example:module2:1.0") .build(); - String module2Pom = PomBuilder.buiildPom("com.example:parent:1.0", "module2").build(); + String module2Pom = PomBuilder.buildPom("com.example:parent:1.0", "module2").build(); - String moduleInModule1Pom = PomBuilder.buiildPom("com.example:parent:1.0", "module-in-module1").build(); + String moduleInModule1Pom = PomBuilder.buildPom("com.example:parent:1.0", "module-in-module1").build(); String javaClass = """ diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/RewriteMavenParserTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/RewriteMavenParserTest.java index e35ae5d63..1d04c9607 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/RewriteMavenParserTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/impl/RewriteMavenParserTest.java @@ -46,7 +46,7 @@ void noExecutionContextGiven() { @Test void customExecutionContextGiven() { - String pom = PomBuilder.buiildPom("com.example:project:1.0").build(); + String pom = PomBuilder.buildPom("com.example:project:1.0").build(); ExecutionContext ctx = new RewriteExecutionContext(); sut.parse(ctx, pom); // first time when initializing the parser diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java b/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java index 553f69542..00bd96714 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/build/util/PomBuilder.java @@ -17,7 +17,6 @@ package org.springframework.sbm.build.util; import org.openrewrite.maven.tree.Scope; -import org.springframework.sbm.build.api.Dependency; import org.springframework.sbm.project.parser.DependencyHelper; import java.util.*; @@ -34,20 +33,39 @@ public class PomBuilder { private Map dependencies = new LinkedHashMap(); private DependencyHelper dependencyHelper = new DependencyHelper(); + private String parentPom; - public static PomBuilder buiildPom(String coordinate) { + public static PomBuilder buildPom(String coordinate) { PomBuilder pomBuilder = new PomBuilder(); pomBuilder.coordinate = coordinate; return pomBuilder; } - public static PomBuilder buiildPom(String parent, String artifactId) { + public static PomBuilder buildPom(String parentCoordinate, String artifactId) { PomBuilder pomBuilder = new PomBuilder(); - pomBuilder.parent = parent; + pomBuilder.parent = parentCoordinate; pomBuilder.artifactId = artifactId; return pomBuilder; } + /** + * Build a parent pom file with a parent, e.g. spring-boot-starter-parent + * + * @param parentCoordinate + * @param coordinate + */ + public static PomBuilder buildParentPom(String parentCoordinate, String coordinate) { + PomBuilder pomBuilder = new PomBuilder(); + pomBuilder.parentPom = parentCoordinate; + pomBuilder.coordinate = coordinate; + return pomBuilder; + } + + /** + * Add modules to a pom. + * + * @param moduleArtifactNames one or more module artifactIds + */ public PomBuilder withModules(String... moduleArtifactNames) { this.modules = Arrays.asList(moduleArtifactNames); if(this.modules.stream().anyMatch(m -> m.contains(":"))) throw new RuntimeException("Found ':' in artifact name but artifact names of modules must not be provided as coordinate."); @@ -62,6 +80,10 @@ public String build() { 4.0.0 """); + if(parentPom != null && parent != null) { + throw new IllegalStateException("parentPom and parent were set."); + } + if (parent != null) { String[] coord = parent.split(":"); sb.append(" ").append("\n"); @@ -70,7 +92,14 @@ public String build() { sb.append(" ").append(coord[2]).append("").append("\n"); sb.append(" ").append("\n"); sb.append(" ").append(artifactId).append("").append("\n"); - } else { + } else if (parentPom != null) { + String[] coord = parentPom.split(":"); + sb.append(" ").append("\n"); + sb.append(" ").append(coord[0]).append("").append("\n"); + sb.append(" ").append(coord[1]).append("").append("\n"); + sb.append(" ").append(coord[2]).append("").append("\n"); + sb.append(" ").append("\n"); + } if (parent == null){ String[] coord = coordinate.split(":"); sb.append(" ").append(coord[0]).append("").append("\n"); sb.append(" ").append(coord[1]).append("").append("\n"); @@ -139,14 +168,16 @@ private void renderDependency(StringBuilder dependenciesSection, Scope scope, or .append(dependency.getArtifactId()) .append("") .append("\n"); - dependenciesSection - .append(" ") - .append(" ") - .append(" ") - .append("") - .append(dependency.getVersion()) - .append("") - .append("\n"); + if(dependency.getVersion() != null) { + dependenciesSection + .append(" ") + .append(" ") + .append(" ") + .append("") + .append(dependency.getVersion()) + .append("") + .append("\n"); + } if(scope != Scope.None) { dependenciesSection .append(" ") @@ -176,6 +207,13 @@ public PomBuilder unscopedDependencies(String... coordinates) { return this; } + public PomBuilder compileScopeDependencies(String... coordinates) { + dependencyHelper.mapCoordinatesToDependencies(Arrays.asList(coordinates)) + .stream() + .forEach(c -> this.dependencies.put(Scope.Compile, c)); + return this; + } + public PomBuilder testScopeDependencies(String... coordinates) { dependencyHelper.mapCoordinatesToDependencies(Arrays.asList(coordinates)) .stream() diff --git a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java index d4c9d8be9..d5c41a0d9 100644 --- a/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java +++ b/components/sbm-core/src/test/java/org/springframework/sbm/project/buildfile/OpenRewriteMavenBuildFileTest.java @@ -18,14 +18,12 @@ import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.*; -import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.context.ApplicationEventPublisher; import org.springframework.sbm.build.api.BuildFile; import org.springframework.sbm.build.api.DependenciesChangedEvent; import org.springframework.sbm.build.api.Dependency; -import org.springframework.sbm.build.api.Module; import org.springframework.sbm.build.api.Plugin; import org.springframework.sbm.build.util.PomBuilder; import org.springframework.sbm.engine.context.ProjectContext; @@ -907,7 +905,7 @@ private BuildFile getBuildFileByPackagingType(ProjectContext context, String ear @Nested class GetDependenciesMultiModuleTest { String parentPom = PomBuilder - .buiildPom("com.example:parent:1.0") + .buildPom("com.example:parent:1.0") .withProperties(Map.of( "jakarta.version", "3.0.2", "validation.groupId", "jakarta.validation", @@ -918,13 +916,13 @@ class GetDependenciesMultiModuleTest { .build(); String module1Pom = PomBuilder - .buiildPom("com.example:parent:1.0", "module1") + .buildPom("com.example:parent:1.0", "module1") .unscopedDependencies("com.example:module2:${project.version}") .testScopeDependencies("javax.annotation:${annotationApi.artifactId}:1.3.2") .build(); String module2Pom = PomBuilder - .buiildPom("com.example:parent:1.0", "module2") + .buildPom("com.example:parent:1.0", "module2") .unscopedDependencies("${validation.groupId}:jakarta.validation-api:${jakarta.version}") .build(); diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java index b1714563f..e99b0dac5 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportDataProvider.java @@ -53,6 +53,7 @@ public Map getData(ProjectContext context, @Valid List s.shouldRender(context)).count()); // FIXME: Retrieve Boot version from Finder diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java index e7457ad9e..0299606b2 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java @@ -24,9 +24,9 @@ import lombok.Setter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.sbm.build.api.BuildFile; import org.springframework.sbm.engine.context.ProjectContext; import org.springframework.sbm.engine.recipe.Condition; -import org.stringtemplate.v4.ST; import javax.validation.constraints.NotEmpty; import java.io.IOException; @@ -51,7 +51,9 @@ public class SpringBootUpgradeReportSection { /** * Helper acting as {@link Condition} and data provide for a {@link SpringBootUpgradeReportSection}. + * @deprecated Use {@link AbstractHelper} instead */ + @Deprecated(forRemoval = true) public interface Helper extends Condition { /** * @return {@code Map} the model data for the template. @@ -59,6 +61,14 @@ public interface Helper extends Condition { Map getData(); } + public static abstract class AbstractHelper implements Helper { + + @Override + public String getDescription() { + return ""; + } + } + public static final String CHANGE_HEADER = "What Changed"; public static final String AFFECTED = "Why is the application affected"; public static final String REMEDIATION = "Remediation"; @@ -99,7 +109,7 @@ public boolean shouldRender(ProjectContext context) { private Set contributors; @JsonIgnore - private Helper helper; + private Helper helper; @JsonIgnore @Autowired private SpringBootUpgradeReportFreemarkerSupport freemarkerSupport; @@ -199,7 +209,7 @@ private void renderLineBreak(StringBuilder sb) { private void renderGitHubInfo(StringBuilder sb) { if(gitHubIssue != null) { - sb.append("Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/").append(gitHubIssue).append("[#").append(gitHubIssue).append("]"); + sb.append("Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/").append(gitHubIssue).append("[#").append(gitHubIssue).append("^, role=\"ext-link\"]"); } if(contributors != null && gitHubIssue != null) { sb.append(", "); @@ -235,7 +245,10 @@ public List getAuthors() { private String renderRemediation() { StringBuilder sb = new StringBuilder(); - sb.append(remediation.getDescription()).append(ls).append(ls); + if(remediation.getDescription() != null) { + sb.append(remediation.getDescription()).append(ls); + } + sb.append(ls); if(remediation.getPossibilities().isEmpty()) { renderResourcesList(sb, remediation); renderRecipeButton(sb, remediation.getRecipe()); diff --git a/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelper.java b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelper.java new file mode 100644 index 000000000..fb68e0d91 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelper.java @@ -0,0 +1,63 @@ +/* + * Copyright 2021 - 2022 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.springframework.sbm.boot.upgrade_27_30.report.helper; +import org.springframework.sbm.boot.common.conditions.IsSpringBootProject; +import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportSection; +import org.springframework.sbm.build.api.BuildFile; +import org.springframework.sbm.build.api.Module; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.ProjectResource; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Fabian Krüger + */ +public class ActuatorEndpointsSanitizationHelper extends SpringBootUpgradeReportSection.AbstractHelper> { + + private static final String ACTUATOR_GROUP_ID = "org.springframework.boot"; + private static final String ACTUATOR_ARTIFACT_ID = "spring-boot-actuator"; + public static final String VERSION_PATTERN = "(2\\.7\\..*)|(3\\.0\\..*)"; + private List buildFilesWithActuatorOnClasspath; + + @Override + public boolean evaluate(ProjectContext context) { + IsSpringBootProject isSpringBootProjectCondition = new IsSpringBootProject(); + isSpringBootProjectCondition.setVersionPattern(VERSION_PATTERN); + boolean isSpringBoot3Application = isSpringBootProjectCondition.evaluate(context); + if(! isSpringBoot3Application) { + return false; + } + buildFilesWithActuatorOnClasspath = getActuatorDependency(context); + return ! buildFilesWithActuatorOnClasspath.isEmpty(); + } + + private List getActuatorDependency(ProjectContext context) { + return context.getApplicationModules().stream() + .map(Module::getBuildFile) + .filter(b -> b.getEffectiveDependencies().stream().anyMatch(d -> d.getGroupId().equals(ACTUATOR_GROUP_ID) && d.getArtifactId().equals(ACTUATOR_ARTIFACT_ID))) + .sorted(Comparator.comparing(ProjectResource::getSourcePath)) + .collect(Collectors.toList()); + } + + @Override + public Map> getData() { + return Map.of("matchingBuildFiles", buildFilesWithActuatorOnClasspath); + } +} diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/migration/sbu30-upgrade-boot-version.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/migration/sbu30-upgrade-boot-version.yaml index fbf8f7c10..281135008 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/migration/sbu30-upgrade-boot-version.yaml +++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/migration/sbu30-upgrade-boot-version.yaml @@ -8,7 +8,7 @@ condition: type: org.springframework.sbm.boot.common.conditions.IsSpringBootProject versionPattern: "2\\.7\\..*" - description: Bump Spring Boot to 3.0.0-RC2 + description: Bump Spring Boot to 3.0.0 openRewriteRecipe: |- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.spring.boot3.data.UpgradeSpringData30 @@ -17,12 +17,12 @@ recipeList: - org.openrewrite.maven.spring.UpgradeUnmanagedSpringProject: versionPattern: "2\\.7\\..*" - newVersion: 3.0.0-RC2 + newVersion: 3.0.0 - org.openrewrite.maven.UpgradeParentVersion: groupId: org.springframework.boot artifactId: spring-boot-starter-parent - newVersion: 3.0.0-RC2 + newVersion: 3.0.0 - org.openrewrite.maven.UpgradeDependencyVersion: groupId: org.springframework.boot artifactId: spring-boot-dependencies - newVersion: 3.0.0-RC2 \ No newline at end of file + newVersion: 3.0.0 \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml index 1aaa97bee..adc5292b9 100644 --- a/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml +++ b/components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml @@ -87,19 +87,20 @@ sections: - - title: Add Spring Boot dependency and plugin milestone repository - helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.AddSpringBootRepositoriesHelper - change: |- - As currently only milestone releases exist these are required - affected: |- - You want to update to 3.0 so you're affected - remediation: - description: |- - Add Spring Boot milestone repositories. - recipe: sbu30-add-milestone-repositories - gitHubIssue: 441 - contributors: - - "Fabian Krüger[@fabapp2]" +# Note re required anymore now that 3.0 is released. Kept for reference +# - title: Add Spring Boot dependency and plugin milestone repository +# helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.AddSpringBootRepositoriesHelper +# change: |- +# As currently only milestone releases exist these are required +# affected: |- +# You want to update to 3.0 so you're affected +# remediation: +# description: |- +# Add Spring Boot milestone repositories. +# recipe: sbu30-add-milestone-repositories +# gitHubIssue: 441 +# contributors: +# - "Fabian Krüger[@fabapp2]" - title: Upgrade Dependencies helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.UpgradeDependenciesHelper @@ -132,6 +133,58 @@ - "Fabian Krüger[@fabapp2]" + - title: Actuator Endpoints Sanitization + helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ActuatorEndpointsSanitizationHelper + change: |- + Since, the `/env` and `/configprops` endpoints can contains sensitive values, all values are always masked by default. + This used to be case only for keys considered to be sensitive. + + Instead, this release opts for a more secure default. + The keys-based approach has been removed in favor of a role based approach, similar to the health endpoint details. + Whether unsanitized values are shown or not can be configured using a property which can have the following values: + + - `NEVER` - All values are sanitized. + - `ALWAYS` - All values are present in the output (sanitizing functions will apply). + - `WHEN_AUTHORIZED` - Values are present in the output only if a user is authorized (sanitizing functions will apply). + + For JMX, users are always considered to be authorized. For HTTP, users are considered to be authorized if they are authenticated and have the specified roles. + + Sanitization for the QuartzEndpoint is also configurable in the same way. + affected: |- + The scan found a dependency to actuator on the classpath. + + <#list matchingBuildFiles as match> + * file://${match.absolutePath}[`${match.sourcePath}`]<#lt> + + remediation: + possibilities: + - title: Verify the new sanitization fulfills your requirements + description: |- + Please verify that none of the sanitized values must be plain text to meet your requirements. + If some sanitized values are required in plain text a custom `SanitizingFunction` must be provided. + Please see the documentation about https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"] + for further information on how to do this. + resources: + - https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values[Sanitize Sensitive Values^, role="ext-link"] + - https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"] +# Not available until upgrade to the latest rewrite version which is currently blocked +# +# - title: Reset behavior to prior 3.0 +# description: |- +# Because Spring Boot Migrator can't tell if the now sanitized properties are required in plain-text, +# the only automated change we can do is setting `management.endpoint.configprops.show-values`, +# `management.endpoint.env.show-values` and `management.endpoint.quartz.show-values` to `ALWAYS`. +# This means the application does not benefit from the new and more secure configuration in Spring Boot 3.0.0. +# We strongly recommend you adjust this configuration to your needs. +# +# WARNING: This would result in some values not being sanitized when in 2.7 they would have been. +# recipe: sbu30-225-actuator-endpoint-sanitization + projects: + - spring-boot + gitHubIssue: 445 + contributors: + - "Fabian Krüger[@fabapp2]" + - title: Changes to Data Properties helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ChangesToDataPropertiesHelper change: |- @@ -226,8 +279,8 @@ `@Autowired` annotation. sources: - https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0.0-M2-Release-Notes#constructingbinding-no-longer-needed-at-the-type-level[Spring Boot Release Notes] - - https://docs.spring.io/spring-boot/docs/3.0.0-M4/api/org/springframework/boot/context/properties/ConstructorBinding.html[@ConstructorBinding API] - - https://docs.spring.io/spring-boot/docs/3.0.0-M4/api/org/springframework/boot/context/properties/ConfigurationProperties.html[@ConfigurationProperties API] + - https://docs.spring.io/spring-boot/docs/3.0.0/api/org/springframework/boot/context/properties/ConstructorBinding.html[@ConstructorBinding API] + - https://docs.spring.io/spring-boot/docs/3.0.0/api/org/springframework/boot/context/properties/ConfigurationProperties.html[@ConfigurationProperties API] affected: |- We found usage of `@ConstructorBinding` in following files: diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/RemoveImageBannerTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/RemoveImageBannerTest.java index 5a8945536..08e281f56 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/RemoveImageBannerTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/RemoveImageBannerTest.java @@ -17,10 +17,8 @@ import org.junit.jupiter.api.Test; import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportActionDeserializer; -import org.springframework.sbm.build.impl.MavenBuildFileUtil; import org.springframework.sbm.build.util.PomBuilder; import org.springframework.sbm.engine.context.ProjectContext; -import org.springframework.sbm.engine.recipe.OpenRewriteDeclarativeRecipeAdapterTest; import org.springframework.sbm.engine.recipe.Recipe; import org.springframework.sbm.project.resource.TestProjectContext; import org.springframework.sbm.test.RecipeTestSupport; @@ -45,12 +43,12 @@ void testGlobExpression() { @Test void applyRemoveImageBannerRecipeShouldRemoveAllImageBannerAtDefaultLocation() { String parentPom = PomBuilder - .buiildPom("com.example:parent:1.0") + .buildPom("com.example:parent:1.0") .withModules("moduleA", "moduleB", "moduleC") .build(); - String moduleA = PomBuilder.buiildPom("com.example:parent:1.0", "moduleA").build(); - String moduleB = PomBuilder.buiildPom("com.example:parent:1.0", "moduleB").build(); - String moduleC = PomBuilder.buiildPom("com.example:parent:1.0", "moduleC").build(); + String moduleA = PomBuilder.buildPom("com.example:parent:1.0", "moduleA").build(); + String moduleB = PomBuilder.buildPom("com.example:parent:1.0", "moduleB").build(); + String moduleC = PomBuilder.buildPom("com.example:parent:1.0", "moduleC").build(); ProjectContext context = TestProjectContext.buildProjectContext() .withMavenBuildFileSource("pom.xml", parentPom) diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelperTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelperTest.java new file mode 100644 index 000000000..0c856ad42 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationHelperTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2021 - 2022 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.springframework.sbm.boot.upgrade_27_30.report.helper; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.build.util.PomBuilder; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Fabian Krüger + */ +class ActuatorEndpointsSanitizationHelperTest { + + @Test + void withSingleModuleApplication() { + ProjectContext context = TestProjectContext + .buildProjectContext() + .withSpringBootParentOf("3.0.0") + .withBuildFileHavingDependencies("org.springframework.boot:spring-boot-actuator") + .build(); + + ActuatorEndpointsSanitizationHelper sut = new ActuatorEndpointsSanitizationHelper(); + assertThat(sut.evaluate(context)).isTrue(); + assertThat(sut.getData()).hasSize(1); + assertThat(sut.getData().get("matchingBuildFiles")).containsExactly(context.getApplicationModules().getRootModule().getBuildFile()); + } + + @Test + void withMultiModuleApplication() { + String parentPom = PomBuilder + .buildParentPom("org.springframework.boot:spring-boot-starter-parent:3.0.0", "com.example:parent:1.0") + .withModules("moduleA", "moduleB", "moduleC") + .build(); + String moduleA = PomBuilder + .buildPom("com.example:parent:1.0", "moduleA") + .compileScopeDependencies("com.example:moduleC:1.0") + .build(); + String moduleB = PomBuilder + .buildPom("com.example:parent:1.0", "moduleB") + .compileScopeDependencies("com.example:moduleC:1.0") + .build(); + String moduleC = PomBuilder + .buildPom("com.example:parent:1.0", "moduleC") + .compileScopeDependencies("org.springframework.boot:spring-boot-starter-actuator") + .build(); + + ProjectContext context = TestProjectContext + .buildProjectContext() + .withMavenRootBuildFileSource(parentPom) + .withMavenBuildFileSource("moduleA", moduleA) + .withMavenBuildFileSource("moduleB", moduleB) + .withMavenBuildFileSource("moduleC", moduleC) + .build(); + + ActuatorEndpointsSanitizationHelper sut = new ActuatorEndpointsSanitizationHelper(); + assertThat(sut.evaluate(context)).isTrue(); + assertThat(sut.getData().get("matchingBuildFiles")).hasSize(3); + assertThat(sut.getData().get("matchingBuildFiles")).containsExactly( + context.getApplicationModules().getModule("moduleA").getBuildFile(), + context.getApplicationModules().getModule("moduleB").getBuildFile(), + context.getApplicationModules().getModule("moduleC").getBuildFile() + ); + } + +} \ No newline at end of file diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationReportSectionTest.java new file mode 100644 index 000000000..5186bbf62 --- /dev/null +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ActuatorEndpointsSanitizationReportSectionTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2021 - 2022 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.springframework.sbm.boot.upgrade_27_30.report.helper; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportTestSupport; +import org.springframework.sbm.build.util.PomBuilder; +import org.springframework.sbm.engine.context.ProjectContext; +import org.springframework.sbm.project.resource.TestProjectContext; + +/** + * @author Fabian Krüger + */ +public class ActuatorEndpointsSanitizationReportSectionTest { + + @Test + @DisplayName("Actuator Endpoints SanitizationReport should render") + void shouldRender() { + String parentPom = PomBuilder + .buildParentPom("org.springframework.boot:spring-boot-starter-parent:3.0.0", "com.example:parent:1.0") + .withModules("moduleA", "moduleB", "moduleC") + .build(); + String moduleA = PomBuilder + .buildPom("com.example:parent:1.0", "moduleA") + .compileScopeDependencies("com.example:moduleC:1.0") + .build(); + String moduleB = PomBuilder + .buildPom("com.example:parent:1.0", "moduleB") + .compileScopeDependencies("com.example:moduleC:1.0") + .build(); + String moduleC = PomBuilder + .buildPom("com.example:parent:1.0", "moduleC") + .compileScopeDependencies("org.springframework.boot:spring-boot-starter-actuator") + .build(); + + ProjectContext context = TestProjectContext + .buildProjectContext() + .withMavenRootBuildFileSource(parentPom) + .withMavenBuildFileSource("moduleA", moduleA) + .withMavenBuildFileSource("moduleB", moduleB) + .withMavenBuildFileSource("moduleC", moduleC) + .build(); + + SpringBootUpgradeReportTestSupport.generatedSection("Actuator Endpoints Sanitization") + .fromProjectContext(context) + .shouldRenderAs(""" + === Actuator Endpoints Sanitization + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/445[#445^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + + ==== What Changed + Since, the `/env` and `/configprops` endpoints can contains sensitive values, all values are always masked by default. + This used to be case only for keys considered to be sensitive. + + Instead, this release opts for a more secure default. + The keys-based approach has been removed in favor of a role based approach, similar to the health endpoint details. + Whether unsanitized values are shown or not can be configured using a property which can have the following values: + + - `NEVER` - All values are sanitized. + - `ALWAYS` - All values are present in the output (sanitizing functions will apply). + - `WHEN_AUTHORIZED` - Values are present in the output only if a user is authorized (sanitizing functions will apply). + + For JMX, users are always considered to be authorized. For HTTP, users are considered to be authorized if they are authenticated and have the specified roles. + + Sanitization for the QuartzEndpoint is also configurable in the same way. + + ==== Why is the application affected + The scan found a dependency to actuator on the classpath. + + * file:///moduleA/pom.xml[`moduleA/pom.xml`] + * file:///moduleB/pom.xml[`moduleB/pom.xml`] + * file:///moduleC/pom.xml[`moduleC/pom.xml`] + + ==== Remediation + + ===== Verify the new sanitization fulfills your requirements + Please verify that none of the sanitized values must be plain text to meet your requirements. + If some sanitized values are required in plain text a custom `SanitizingFunction` must be provided. + Please see the documentation about https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"]\s + for further information on how to do this. + + * https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values[Sanitize Sensitive Values^, role="ext-link"] + * https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"] + + + """); + } + +} diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportReportSectionTest.java index 2b8b8f1d3..0219b1c24 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportReportSectionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/BannerSupportReportSectionTest.java @@ -38,7 +38,7 @@ public void rendersBannerSupportInformation() { .shouldRenderAs( """ === Banner support - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/150[#150], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"], https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/150[#150^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"], https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Support for image-based application banners has been removed. banner.gif, banner.jpg, and banner.png diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesReportSectionTest.java index 701bd4907..070bf40cf 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesReportSectionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ChangesToDataPropertiesReportSectionTest.java @@ -43,7 +43,7 @@ void changesToDataPropertiesSection_renders() { .shouldRenderAs( """ === Changes to Data Properties - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/441[#441], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/441[#441^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] ==== What Changed The data prefix has been reserved for Spring Data and any properties under the `spring.data` prefix imply that Spring diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/CommonsMultipartResolverHelperTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/CommonsMultipartResolverHelperTest.java index 03278ee50..507104dfc 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/CommonsMultipartResolverHelperTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/CommonsMultipartResolverHelperTest.java @@ -55,7 +55,7 @@ public CommonsMultipartResolver commonsMultipartResolver() { .shouldRenderAs( """ === Commons Multipart Upload - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/541[#541], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/541[#541^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Support for Spring Framework’s `CommonsMultipartResolver` has been removed following its removal in Spring Framework 6 @@ -121,7 +121,7 @@ public CommonsMultipartResolver songMultiPartUploader() { .shouldRenderAs( """ === Commons Multipart Upload - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/541[#541], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/541[#541^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Support for Spring Framework’s `CommonsMultipartResolver` has been removed following its removal in Spring Framework 6 diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingReportSectionTest.java index 1147600d1..b136cde17 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingReportSectionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/ConstructorBindingReportSectionTest.java @@ -72,7 +72,7 @@ public String getFrom() { .shouldRenderAs( """ === Constructor Binding - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/166[#166], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/166[#166^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed When using constructor bound @ConfigurationProperties the @ConstructorBinding annotation diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatReportSectionTest.java index b41e5a7f4..96aa5a4aa 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatReportSectionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/LoggingDateFormatReportSectionTest.java @@ -41,7 +41,7 @@ void shouldRenderSectionWhenNoPropertiesExist() { .shouldRenderAs( """ === Logging Date Format - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/489[#489], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/489[#489^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] ==== What Changed The default format for the date and time component of log messages for Logback and Log4j2 has changed to @@ -73,7 +73,7 @@ void shouldRenderSectionWhenPropertyNotDefined() { .shouldRenderAs( """ === Logging Date Format - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/489[#489], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/489[#489^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] ==== What Changed The default format for the date and time component of log messages for Logback and Log4j2 has changed to diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/PagingAndSortingHelperTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/PagingAndSortingHelperTest.java index d8d69ad16..33939e7f6 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/PagingAndSortingHelperTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/PagingAndSortingHelperTest.java @@ -58,7 +58,7 @@ public class A {} .shouldRenderAs( """ === Paging and sorting repository - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Sorting repositories no longer extend their respective CRUD repository. @@ -119,7 +119,7 @@ public class A {} .shouldRenderAs( """ === Paging and sorting repository - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Sorting repositories no longer extend their respective CRUD repository. @@ -180,7 +180,7 @@ public class A {} .shouldRenderAs( """ === Paging and sorting repository - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Sorting repositories no longer extend their respective CRUD repository. @@ -268,7 +268,7 @@ public class A {} .shouldRenderAs( """ === Paging and sorting repository - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/518[#518^, role="ext-link"], Contributors: https://github.com/sanagaraj-pivotal[@sanagaraj-pivotal^, role="ext-link"] ==== What Changed Sorting repositories no longer extend their respective CRUD repository. diff --git a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/SpringMVCAndWebFluxUrlMatchingChangesReportSectionTest.java b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/SpringMVCAndWebFluxUrlMatchingChangesReportSectionTest.java index e6b46aab6..c16f8a872 100644 --- a/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/SpringMVCAndWebFluxUrlMatchingChangesReportSectionTest.java +++ b/components/sbm-recipes-boot-upgrade/src/test/java/org/springframework/sbm/boot/upgrade_27_30/report/helper/SpringMVCAndWebFluxUrlMatchingChangesReportSectionTest.java @@ -66,7 +66,7 @@ public class AnotherClass {}; String expectedOutput = """ === Spring MVC and WebFlux URL matching changes - Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/522[#522], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] + Issue: https://github.com/spring-projects-experimental/spring-boot-migrator/issues/522[#522^, role="ext-link"], Contributors: https://github.com/fabapp2[@fabapp2^, role="ext-link"] ==== What Changed As of Spring Framework 6.0, the trailing slash matching configuration option has been deprecated and its default value set to `false`.