Skip to content

Commit

Permalink
Fail on recursive references in profile groups
Browse files Browse the repository at this point in the history
Update `Profiles` group expansion logic to fail if recursive
references are found.

See gh-24327
  • Loading branch information
dreis2211 authored and philwebb committed Dec 9, 2020
1 parent 2ab7301 commit 5b74f77
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
Expand Down Expand Up @@ -117,18 +118,30 @@ private List<String> expandProfiles(List<String> profiles) {
while (!stack.isEmpty()) {
String current = stack.pop();
expandedProfiles.add(current);
asReversedList(this.groups.get(current)).forEach(stack::push);
List<String> groupProfiles = asReversedList(this.groups.get(current));
Set<String> profileConflicts = getProfileConflicts(groupProfiles, expandedProfiles);
if (!profileConflicts.isEmpty()) {
String message = String.format("Profiles could not be resolved. Remove profiles %s from group: %s",
profileConflicts, current);
throw new IllegalStateException(message);

}
groupProfiles.forEach(stack::push);
}
return asUniqueItemList(StringUtils.toStringArray(expandedProfiles));
}

private Set<String> getProfileConflicts(List<String> groupProfiles, Set<String> expandedProfiles) {
return groupProfiles.stream().filter(expandedProfiles::contains).collect(Collectors.toSet());
}

private List<String> asReversedList(List<String> list) {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
}
List<String> reversed = new ArrayList<>(list);
Collections.reverse(reversed);
return Collections.unmodifiableList(reversed);
return reversed;
}

private List<String> asUniqueItemList(String[] array) {
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.springframework.mock.env.MockEnvironment;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for {@link Profiles}.
Expand Down Expand Up @@ -359,4 +360,25 @@ void isAcceptedWhenNoActiveAndDefaultWithGroupsContainsProfileReturnsTrue() {
assertThat(profiles.isAccepted("x")).isTrue();
}

@Test
void simpleRecursiveReferenceInProfileGroupThrowsException() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("spring.profiles.active", "a,b,c");
environment.setProperty("spring.profiles.group.a", "a,e,f");
Binder binder = Binder.get(environment);
assertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, null))
.withMessageContaining("Profiles could not be resolved. Remove profiles [a] from group: a");
}

@Test
void complexRecursiveReferenceInProfileGroupThrowsException() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("spring.profiles.active", "a,b,c");
environment.setProperty("spring.profiles.group.a", "e,f");
environment.setProperty("spring.profiles.group.e", "a,x,y");
Binder binder = Binder.get(environment);
assertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, null))
.withMessageContaining("Profiles could not be resolved. Remove profiles [a] from group: e");
}

}

0 comments on commit 5b74f77

Please sign in to comment.