If you set spring.profiles.active to a value that contains a * the app will fail to start.
Steps to reproduce
Spring Boot 3.0.2 simplest application from start.spring.io:
@SpringBootApplication
public class WackyProfileApplication {
public static void main(String[] args) {
SpringApplication.run(WackyProfileApplication.class, args);
}
}
Start it w/ spring.profiles.active set to foo*bar via any normal means such as:
- sysprop
- envvar
- property in application.yml
- profile property in maven/gradle plugin
App fails to start and reports the following in the log:
com.example.wackyprofile.WackyprofileApplication
23:14:37.244 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Location 'file:./application-foo*bar.yaml' must end with '*/'
at org.springframework.util.Assert.state(Assert.java:97)
at org.springframework.boot.context.config.LocationResourceLoader.validatePattern(LocationResourceLoader.java:134)
at org.springframework.boot.context.config.LocationResourceLoader.getResources(LocationResourceLoader.java:95)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolvePattern(StandardConfigDataLocationResolver.java:313)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolve(StandardConfigDataLocationResolver.java:299)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolve(StandardConfigDataLocationResolver.java:251)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolveProfileSpecific(StandardConfigDataLocationResolver.java:150)
at org.springframework.boot.context.config.ConfigDataLocationResolvers.lambda$resolve$2(ConfigDataLocationResolvers.java:107)
at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:113)
at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:106)
at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:94)
at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:105)
at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:97)
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:85)
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:115)
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:313)
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:234)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
Cause
The * qualifies it to be processed as a pattern in StandardConfigDataLocationResolver#resolve(StandardConfigDataReference)
Comment From: onobc
This is an edge-casey situation and arguably a terrible choice to include a wildcard in your profile name. However, there is no place in the Spring Boot nor Spring Framework docs (that I could find) that guide the user to the rules for a profile name. Maybe just adding a small section to the docs would suffice.
Comment From: onobc
Another interesting point, there is a validateProfile in Environment whose only requirement is that the profile has text and does not begin w a !. Different consumers of the profile probably have different validation requirements than others.
Comment From: philwebb
I think we should tighten the rules for Spring Boot applications. The application-<profile> file is one example of something that will break but I suspect there are others. For example , will probably break the list parsing and !, &, | will break Profiles.of.
Comment From: wilkinsona
We've had an issue related to , in the past: https://github.com/spring-projects/spring-boot/issues/19537
Comment From: bbulgarelli
I started working on this issue and I added the following code in the beginning of SpringBootContextLoader.setActiveProfiles:
private void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles, boolean applicationEnvironment){
***
for (String profile : profiles) {
if (containsProhibitedCharacters(profile)) {
throw new IllegalArgumentException("Invalid profile: '" + profile + "'. Profile names can't contain '*', '&', '!' or '|'.");
}
}
***
}
And I also created the following method:
private boolean containsProhibitedCharacters(String str){
String regex = ".*[*&!|].*";
return str.matches(regex);
}
I didn't include , in the regex expression, because it would break the following unit test that already exists:
@Test
void activeProfileWithComma() {
assertThat(getActiveProfiles(ActiveProfileWithComma.class)).containsExactly("profile1,2");
}
I would like to know if the changes I made solve the issue correctly. If they do, what should I do about the comma problem?
P.s.: I also made the unit tests that verify the changes I made.
Comment From: philwebb
Thanks for looking at this @bbulgarelli. Looking at commit https://github.com/spring-projects/spring-boot/commit/7ab2bca3766a8e5c67b4ffbbc7e019b391f29e2d it seems like we added the profile test when fixing #19537. I think we added the comma test for completeness, but I think it's fine to remove it. A better exception would have actually helped the reporter of #19537.
Feel free to submit a pull-request if you have something you'd like us to review.
Comment From: mhalbritter
Superseded by #43176.