Allow system property override to be switched off

The default behaviour is the same as before, so a config client
adds the remote property sources "first" (i.e. ahead of system
properties). If the user sets up a  remote config repo with
spring.cloud.config.overrideSystemProperties=false they can
change this behaviour and insert the new property source after
systemEnvironment (i.e. before local config files but after the
other local sources). Of course using an `application.yml` on
the server you can change the default  for all applications.

There is also a new feature in the config server where the operator
can add a map of override properties in
spring.cloud.config.server.overrides.* and have them added with
highest priority in the Environment returned from the server.
Using that the operator can prevent config repositories from
changing the override behaviour by setting
spring.cloud.config.allowOverride=false.

Fixes gh-57
This commit is contained in:
Dave Syer
2015-01-16 16:24:41 +00:00
parent 1a2c21a081
commit a0c9ae3ff0
17 changed files with 256 additions and 58 deletions

View File

@@ -24,6 +24,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.bootstrap.BootstrapApplicationListener;
import org.springframework.cloud.config.client.ConfigClientProperties;
@@ -38,13 +40,14 @@ import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
/**
* @author Dave Syer
*
*/
@Configuration
@EnableConfigurationProperties
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@@ -56,8 +59,8 @@ public class PropertySourceBootstrapConfiguration implements
@Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
@Autowired(required = false)
private ConfigClientProperties configClientProperties;
@Autowired
private PropertySourceBootstrapProperties properties;
public void setPropertySourceLocators(
Collection<PropertySourceLocator> propertySourceLocators) {
@@ -72,15 +75,7 @@ public class PropertySourceBootstrapConfiguration implements
boolean empty = true;
for (PropertySourceLocator locator : propertySourceLocators) {
PropertySource<?> source = null;
try {
source = locator.locate(applicationContext.getEnvironment());
}
catch (Exception e) {
if (configClientProperties != null && configClientProperties.isFailFast()) {
throw new IllegalStateException("Could not locate PropertySource. The fail fast property is set, failing", e);
}
logger.error("Could not locate PropertySource: " + e.getMessage());
}
source = locator.locate(applicationContext.getEnvironment());
if (source == null) {
continue;
}
@@ -92,11 +87,32 @@ public class PropertySourceBootstrapConfiguration implements
MutablePropertySources propertySources = applicationContext.getEnvironment()
.getPropertySources();
if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.replace(BOOTSTRAP_PROPERTY_SOURCE_NAME, composite);
}
else {
propertySources.addFirst(composite);
propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
}
insertPropertySources(propertySources, composite);
}
}
private void insertPropertySources(MutablePropertySources propertySources,
CompositePropertySource composite) {
MutablePropertySources incoming = new MutablePropertySources();
incoming.addFirst(composite);
PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();
new RelaxedDataBinder(remoteProperties, "spring.cloud.config").bind(new PropertySourcesPropertyValues(
incoming));
if (!remoteProperties.isAllowOverride()
|| remoteProperties.isSystemPropertiesOverride()) {
propertySources.addFirst(composite);
return;
}
if (propertySources
.contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
propertySources.addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
composite);
}
else {
propertySources.addLast(composite);
}
}

View File

@@ -0,0 +1,37 @@
package org.springframework.cloud.bootstrap.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.cloud.config")
public class PropertySourceBootstrapProperties {
/**
* Flag to indicate that the external properties should override system properties.
* Default true.
*/
private boolean systemPropertiesOverride = true;
/**
* Flag to indicate that {@link #isSystemPropertiesOverride()
* systemPropertiesOverride} can be used. Set to false to prevent users from changing
* the default accidentally. Default true.
*/
private boolean allowOverride = true;
public boolean isSystemPropertiesOverride() {
return systemPropertiesOverride;
}
public void setSystemPropertiesOverride(boolean systemPropertiesOverride) {
this.systemPropertiesOverride = systemPropertiesOverride;
}
public boolean isAllowOverride() {
return allowOverride;
}
public void setAllowOverride(boolean allowOverride) {
this.allowOverride = allowOverride;
}
}

View File

@@ -46,6 +46,10 @@ public class Environment {
this.propertySources.add(propertySource);
}
public void addFirst(PropertySource propertySource) {
this.propertySources.add(0, propertySource);
}
public List<PropertySource> getPropertySources() {
return propertySources;
}

View File

@@ -35,9 +35,15 @@ public class ConfigClientProperties {
public static final String PREFIX = "spring.cloud.config";
/**
* Flag to say that remote configuration is enabled. Default true;
*/
private boolean enabled = true;
private String env = "default";
/**
* The default profile to use when fetching remote configuration (comma-separated). Default is "default".
*/
private String profile = "default";
@Value("${spring.application.name:'application'}")
private String name;
@@ -53,7 +59,7 @@ public class ConfigClientProperties {
private Discovery discovery = new Discovery();
private boolean failFast = false;
private ConfigClientProperties() {
}
@@ -62,7 +68,7 @@ public class ConfigClientProperties {
if (profiles.length == 0) {
profiles = environment.getDefaultProfiles();
}
this.setEnv(StringUtils.arrayToCommaDelimitedString(profiles));
this.setProfile(StringUtils.arrayToCommaDelimitedString(profiles));
}
public boolean isEnabled() {
@@ -89,12 +95,12 @@ public class ConfigClientProperties {
this.name = name;
}
public String getEnv() {
return env;
public String getProfile() {
return profile;
}
public void setEnv(String env) {
this.env = env;
public void setProfile(String env) {
this.profile = env;
}
public String getLabel() {
@@ -214,8 +220,8 @@ public class ConfigClientProperties {
override.setName(environment.resolvePlaceholders("${"
+ ConfigClientProperties.PREFIX
+ ".name:${spring.application.name:'application'}}"));
if (environment.containsProperty(ConfigClientProperties.PREFIX + ".env")) {
override.setEnv(environment.getProperty(ConfigClientProperties.PREFIX + ".env"));
if (environment.containsProperty(ConfigClientProperties.PREFIX + ".profile")) {
override.setProfile(environment.getProperty(ConfigClientProperties.PREFIX + ".profile"));
}
if (environment.containsProperty(ConfigClientProperties.PREFIX + ".label")) {
override.setLabel(environment.getProperty(ConfigClientProperties.PREFIX + ".label"));
@@ -225,7 +231,7 @@ public class ConfigClientProperties {
@Override
public String toString() {
return "ConfigClientProperties [name=" + name + ", env=" + env + ", label="
return "ConfigClientProperties [name=" + name + ", env=" + profile + ", label="
+ label + ", uri=" + uri + ", discovery.enabled=" + discovery.enabled
+ ", failFast="+ failFast + "]";
}

View File

@@ -20,6 +20,8 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.config.Environment;
import org.springframework.cloud.config.PropertySource;
import org.springframework.core.annotation.Order;
@@ -41,6 +43,9 @@ import org.springframework.web.client.RestTemplate;
@Order(0)
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {
private static Log logger = LogFactory
.getLog(ConfigServicePropertySourceLocator.class);
private RestTemplate restTemplate;
private ConfigClientProperties defaults;
@@ -55,16 +60,28 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
CompositePropertySource composite = new CompositePropertySource("configService");
RestTemplate restTemplate = this.restTemplate == null ? getSecureRestTemplate(client)
: this.restTemplate;
Environment result = restTemplate.exchange(
client.getUri() + "/{name}/{env}/{label}", HttpMethod.GET,
new HttpEntity<Void>((Void) null), Environment.class, client.getName(),
client.getEnv(), client.getLabel()).getBody();
for (PropertySource source : result.getPropertySources()) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) source.getSource();
composite.addPropertySource(new MapPropertySource(source.getName(), map));
try {
Environment result = restTemplate.exchange(
client.getUri() + "/{name}/{profile}/{label}", HttpMethod.GET,
new HttpEntity<Void>((Void) null), Environment.class,
client.getName(), client.getProfile(), client.getLabel()).getBody();
for (PropertySource source : result.getPropertySources()) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) source.getSource();
composite.addPropertySource(new MapPropertySource(source.getName(), map));
}
return composite;
}
return composite;
catch (Exception e) {
if (client != null && client.isFailFast()) {
throw new IllegalStateException(
"Could not locate PropertySource. The fail fast property is set, failing",
e);
}
logger.error("Could not locate PropertySource: " + e.getMessage());
return null;
}
}
public void setRestTemplate(RestTemplate restTemplate) {

View File

@@ -18,13 +18,22 @@ package org.springframework.cloud.config.client;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
/**
* Strategy for locating (possibly remote) property sources for the Environment.
* Implementations should not fail unless they intend to prevent the application from
* starting.
*
* @author Dave Syer
*
*/
public interface PropertySourceLocator {
/**
* @param environment the current Environment
* @return a PropertySource or null if there is none
*
* @throws IllegalStateException if there is a fail fast condition
*/
PropertySource<?> locate(Environment environment);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.bootstrap;
package org.springframework.cloud.bootstrap.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -24,6 +24,8 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.After;
import org.junit.Test;
@@ -51,7 +53,11 @@ public class BootstrapConfigurationTests {
@After
public void close() {
// Expected.* is bound to the PropertySourceConfiguration below
System.clearProperty("expected.name");
// Used to test system properties override
System.clearProperty("bootstrap.foo");
PropertySourceConfiguration.MAP.clear();
if (context != null) {
context.close();
}
@@ -61,26 +67,32 @@ public class BootstrapConfigurationTests {
public void pickupExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties();
System.setProperty("spring.cloud.bootstrap.location", externalPropertiesPath);
context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("externalPropertiesInfoName", context.getEnvironment().getProperty("info.name"));
.sources(BareConfiguration.class)
.properties("spring.cloud.bootstrap.location:" + externalPropertiesPath)
.run();
assertEquals("externalPropertiesInfoName",
context.getEnvironment().getProperty("info.name"));
assertTrue(context.getEnvironment().getPropertySources().contains("bootstrap"));
assertNotNull(context.getBean(ConfigClientProperties.class));
}
/**
* Running the test from maven will start from a different directory then starting it from intellij
* Running the test from maven will start from a different directory then starting it
* from intellij
*
* @return
*/
private String getExternalProperties() {
String externalPropertiesPath = "";
File externalProperties = new File("src/test/external-properties/bootstrap.properties");
File externalProperties = new File(
"src/test/resources/external-properties/bootstrap.properties");
if (externalProperties.exists()) {
externalPropertiesPath = externalProperties.getAbsolutePath();
} else {
externalProperties = new File("spring-cloud-config-client/src/test/external-properties/bootstrap.properties");
}
else {
externalProperties = new File(
"spring-cloud-config-client/src/test/resources/external-properties/bootstrap.properties");
externalPropertiesPath = externalProperties.getAbsolutePath();
}
return externalPropertiesPath;
@@ -88,6 +100,7 @@ public class BootstrapConfigurationTests {
@Test
public void picksUpAdditionalPropertySource() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("expected.name", "bootstrap");
context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
@@ -96,6 +109,41 @@ public class BootstrapConfigurationTests {
assertNotNull(context.getBean(ConfigClientProperties.class));
}
@Test
public void overrideSystemPropertySourceByDefault() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void systemPropertyOverrideFalse() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put(
"spring.cloud.config.systemPropertiesOverride", "false");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("system", context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void systemPropertyOverrideWhenOverrideDisallowed() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put(
"spring.cloud.config.systemPropertiesOverride", "false");
// If spring.cloud.config.allowOverride=false is in the remote property sources
// with sufficiently high priority it always wins. Admins can enforce it by adding
// their own remote property source.
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false");
System.setProperty("bootstrap.foo", "system");
context = new SpringApplicationBuilder().web(false)
.sources(BareConfiguration.class).run();
assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo"));
}
@Test
public void applicationNameInBootstrapAndMain() {
System.setProperty("expected.name", "main");
@@ -158,6 +206,7 @@ public class BootstrapConfigurationTests {
@Test
public void environmentEnrichedOnceWhenSharedWithChildContext() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.environment(new StandardEnvironment()).child(BareConfiguration.class)
.web(false).run();
@@ -171,6 +220,7 @@ public class BootstrapConfigurationTests {
@Test
public void environmentEnrichedInParentContext() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.child(BareConfiguration.class).web(false).run();
assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo"));
@@ -182,6 +232,7 @@ public class BootstrapConfigurationTests {
@Test
public void differentProfileInChild() {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
// Profiles are always merged with the child
ConfigurableApplicationContext parent = new SpringApplicationBuilder()
.sources(BareConfiguration.class).profiles("parent").web(false).run();
@@ -217,6 +268,9 @@ public class BootstrapConfigurationTests {
// This is added to bootstrap context as a source in bootstrap.properties
protected static class PropertySourceConfiguration implements PropertySourceLocator {
public static Map<String, Object> MAP = new HashMap<String, Object>(
Collections.<String, Object> singletonMap("bootstrap.foo", "bar"));
private String name;
@Override
@@ -224,8 +278,7 @@ public class BootstrapConfigurationTests {
if (name != null) {
assertEquals(name, environment.getProperty("spring.application.name"));
}
return new MapPropertySource("testBootstrap",
Collections.<String, Object> singletonMap("bootstrap.foo", "bar"));
return new MapPropertySource("testBootstrap", MAP);
}
public String getName() {

View File

@@ -1,2 +1,2 @@
spring.main.sources: org.springframework.cloud.bootstrap.BootstrapConfigurationTests.PropertySourceConfiguration
spring.main.sources: org.springframework.cloud.bootstrap.config.BootstrapConfigurationTests.PropertySourceConfiguration
info.name: child

View File

@@ -46,7 +46,7 @@ public class ConfigServerBootstrapConfiguration {
@Bean
public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() {
return new EnvironmentRepositoryPropertySourceLocator(repository,
client.getName(), client.getEnv(), client.getLabel());
client.getName(), client.getProfile(), client.getLabel());
}
}

View File

@@ -42,6 +42,7 @@ public class ConfigServerMvcConfiguration {
public EnvironmentController environmentController() {
EnvironmentController controller = new EnvironmentController(repository, encryptionController());
controller.setDefaultLabel(server.getDefaultLabel());
controller.setOverrides(server.getOverrides());
return controller;
}

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.cloud.config.server;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@@ -28,7 +31,15 @@ public class ConfigServerProperties {
private boolean bootstrap;
private String prefix;
/**
* Default repository label (defaults to "master") when incoming requests do not have
* a specific label.
*/
private String defaultLabel = ConfigServerProperties.MASTER;
/**
* Extra map for a property source to be sent to all clients.
*/
private Map<String, String> overrides = new LinkedHashMap<String, String>();
public String getDefaultLabel() {
return defaultLabel;
}
@@ -47,5 +58,11 @@ public class ConfigServerProperties {
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public Map<String, String> getOverrides() {
return overrides;
}
public void setOverrides(Map<String, String> overrides) {
this.overrides = overrides;
}
}

View File

@@ -36,6 +36,8 @@ public class EnvironmentController {
private String defaultLabel = ConfigServerProperties.MASTER;
private Map<String, String> overrides = new LinkedHashMap<String, String>();
@Autowired
public EnvironmentController(EnvironmentRepository repository,
EncryptionController encryption) {
@@ -52,7 +54,12 @@ public class EnvironmentController {
@RequestMapping("/{name}/{profiles}/{label}")
public Environment labelled(@PathVariable String name, @PathVariable String profiles,
@PathVariable String label) {
return encryption.decrypt(repository.findOne(name, profiles, label));
Environment environment = encryption.decrypt(repository.findOne(name, profiles,
label));
if (!overrides.isEmpty()) {
environment.addFirst(new PropertySource("overrides", overrides));
}
return environment;
}
@RequestMapping("/{name}-{profiles}.properties")
@@ -65,7 +72,8 @@ public class EnvironmentController {
public ResponseEntity<String> labelledProperties(@PathVariable String name,
@PathVariable String profiles, @PathVariable String label) throws IOException {
if (name.contains("-") || profiles.contains("-")) {
throw new IllegalArgumentException("Properties output not supported for name or profiles containing hyphens");
throw new IllegalArgumentException(
"Properties output not supported for name or profiles containing hyphens");
}
Properties properties = convertToProperties(labelled(name, profiles, label));
return getSuccess(sortLines(properties));
@@ -92,8 +100,8 @@ public class EnvironmentController {
}
@RequestMapping({ "/{name}-{profiles}.yml", "/{name}-{profiles}.yaml" })
public ResponseEntity<String> yaml(@PathVariable String name, @PathVariable String profiles)
throws Exception {
public ResponseEntity<String> yaml(@PathVariable String name,
@PathVariable String profiles) throws Exception {
return labelledYaml(name, profiles, defaultLabel);
}
@@ -101,7 +109,8 @@ public class EnvironmentController {
public ResponseEntity<String> labelledYaml(@PathVariable String name,
@PathVariable String profiles, @PathVariable String label) throws Exception {
if (name.contains("-") || profiles.contains("-")) {
throw new IllegalArgumentException("YAML output not supported for name or profiles containing hyphens");
throw new IllegalArgumentException(
"YAML output not supported for name or profiles containing hyphens");
}
LinkedHashMap<String, Object> target = new LinkedHashMap<String, Object>();
PropertiesConfigurationFactory<Map<String, Object>> factory = new PropertiesConfigurationFactory<Map<String, Object>>(
@@ -113,7 +122,7 @@ public class EnvironmentController {
Map<String, Object> input = factory.getObject();
return getSuccess(new Yaml().dumpAsMap(input));
}
@ExceptionHandler(IllegalArgumentException.class)
public void illegalArgument(HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value());
@@ -186,7 +195,14 @@ public class EnvironmentController {
* @param defaultLabel
*/
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
this.defaultLabel = defaultLabel;
}
/**
* @param overrides the overrides to set
*/
public void setOverrides(Map<String, String> overrides) {
this.overrides = overrides;
}
}

View File

@@ -24,6 +24,6 @@ import org.springframework.cloud.config.Environment;
*/
public interface EnvironmentRepository {
Environment findOne(String application, String name, String label);
Environment findOne(String application, String profile, String label);
}

View File

@@ -1,5 +1,6 @@
package org.springframework.cloud.config.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.io.IOException;
@@ -35,6 +36,8 @@ public class ApplicationTests {
public void contextLoads() {
Environment environment = new TestRestTemplate().getForObject("http://localhost:" + port + "/foo/development/", Environment.class);
assertFalse(environment.getPropertySources().isEmpty());
assertEquals("overrides", environment.getPropertySources().get(0).getName());
assertEquals("{spring.cloud.config.enabled=true}", environment.getPropertySources().get(0).getSource().toString());
}
}

View File

@@ -17,6 +17,7 @@ package org.springframework.cloud.config.server;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -38,7 +39,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
*
*/
public class EnvironmentControllerTests {
@Rule
public ExpectedException expected = ExpectedException.none();
@@ -120,9 +121,22 @@ public class EnvironmentControllerTests {
@Test
public void mappingForLabelledYamlWithHyphen() throws Exception {
Mockito.when(repository.findOne("foo", "bar-spam", "other")).thenReturn(environment);
Mockito.when(repository.findOne("foo", "bar-spam", "other")).thenReturn(
environment);
MockMvc mvc = MockMvcBuilders.standaloneSetup(controller).build();
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-spam.yml")).andExpect(
MockMvcResultMatchers.status().isBadRequest());
}
@Test
public void allowOverrideFalse() throws Exception {
controller.setOverrides(Collections.singletonMap("foo", "bar"));
Map<String, Object> map = new HashMap<String, Object>();
map.put("a.b.c", "d");
environment.add(new PropertySource("one", map));
Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment);
assertEquals("{foo=bar}", controller.master("foo", "bar").getPropertySources()
.get(0).getSource().toString());
}
}

View File

@@ -4,3 +4,8 @@ spring:
server:
git:
basedir: target/config
overrides:
spring:
cloud:
config:
enabled: true