CVE-2024-2700
Description
A vulnerability was found in the quarkus-core component. Quarkus captures local environment variables from the Quarkus namespace during the application's build, therefore, running the resulting application inherits the values captured at build time. Some local environment variables may have been set by the developer or CI environment for testing purposes, such as dropping the database during application startup or trusting all TLS certificates to accept self-signed certificates. If these properties are configured using environment variables or the .env facility, they are captured into the built application, which can lead to dangerous behavior if the application does not override these values. This behavior only happens for configuration properties from the quarkus.* namespace. Application-specific properties are not captured.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
io.quarkus:quarkus-coreMaven | >= 3.9.0.CR1, < 3.9.2 | 3.9.2 |
io.quarkus:quarkus-coreMaven | >= 3.3.0.CR1, < 3.8.4 | 3.8.4 |
io.quarkus:quarkus-coreMaven | < 3.2.12.Final | 3.2.12.Final |
Patches
32b24dc8dbc8fDo not record local sources in runtime config defaults
12 files changed · +141 −55
core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java+64 −23 modified@@ -8,6 +8,10 @@ import static io.quarkus.deployment.util.ReflectUtil.unwrapInvocationTargetException; import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix; import static io.smallrye.config.Expressions.withoutExpansion; +import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT; +import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES; import static java.util.stream.Collectors.toSet; import java.io.IOException; @@ -29,6 +33,7 @@ import java.util.SortedSet; import java.util.TreeMap; +import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.config.spi.ConfigSource; import org.eclipse.microprofile.config.spi.Converter; @@ -81,6 +86,7 @@ import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SysPropConfigSource; +import io.smallrye.config.common.AbstractConfigSource; import io.smallrye.config.common.utils.StringUtil; /** @@ -508,18 +514,19 @@ ReadResult run() { nameBuilder.setLength(0); } + SmallRyeConfig runtimeConfig = getConfigForRuntimeRecording(); + // Register defaults for Roots - allBuildTimeValues.putAll(getDefaults(buildTimePatternMap)); - buildTimeRunTimeValues.putAll(getDefaults(buildTimeRunTimePatternMap)); - runTimeDefaultValues.putAll(getDefaults(runTimePatternMap)); + allBuildTimeValues.putAll(getDefaults(config, buildTimePatternMap)); + buildTimeRunTimeValues.putAll(getDefaults(config, buildTimeRunTimePatternMap)); + runTimeDefaultValues.putAll(getDefaults(runtimeConfig, runTimePatternMap)); // Register defaults for Mappings // Runtime defaults are added in ConfigGenerationBuildStep.generateBuilders to include user mappings for (ConfigClassWithPrefix buildTimeRunTimeMapping : buildTimeRunTimeMappings) { buildTimeRunTimeValues.putAll(ConfigMappings.getDefaults(buildTimeRunTimeMapping)); } - SmallRyeConfig runtimeDefaultsConfig = getConfigForRuntimeDefaults(); Set<String> registeredRoots = allRoots.stream().map(RootDefinition::getName).collect(toSet()); registeredRoots.add("quarkus"); Set<String> allProperties = getAllProperties(registeredRoots); @@ -599,7 +606,7 @@ ReadResult run() { knownProperty = knownProperty || matched != null; if (matched != null) { // it's a run-time default (record for later) - ConfigValue configValue = withoutExpansion(() -> runtimeDefaultsConfig.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -610,7 +617,7 @@ ReadResult run() { } } else { // it's not managed by us; record it - ConfigValue configValue = withoutExpansion(() -> runtimeDefaultsConfig.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -637,7 +644,7 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + if (value.getRawValue() != null) { allBuildTimeValues.put(property, value.getRawValue()); } } @@ -649,7 +656,7 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + if (value.getRawValue() != null) { allBuildTimeValues.put(property, value.getRawValue()); buildTimeRunTimeValues.put(property, value.getRawValue()); } @@ -661,8 +668,8 @@ ReadResult run() { Set<String> mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties); for (String property : mappedProperties) { unknownBuildProperties.remove(property); - ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + ConfigValue value = runtimeConfig.getConfigValue(property); + if (value.getRawValue() != null) { runTimeValues.put(property, value.getRawValue()); } } @@ -1066,25 +1073,57 @@ private Set<String> getAllProperties(final Set<String> registeredRoots) { /** * Use this Config instance to record the runtime default values. We cannot use the main Config - * instance because it may record values coming from the EnvSource in build time. Environment variable values - * may be completely different between build and runtime, so it doesn't make sense to record these. - * <br> - * We do exclude the properties coming from the EnvSource, but a call to getValue may still provide a result - * coming from the EnvSource, so we need to exclude it from the sources when recording values for runtime. - * <br> - * We also do not want to completely exclude the EnvSource, because it may provide values for the build. This - * is only specific when recording the defaults. + * instance because it may record values coming from local development sources (Environment Variables, + * System Properties, etc.) in build time. Local config source values may be completely different between the + * build environment and the runtime environment, so it doesn't make sense to record these. * * @return a new SmallRye instance without the EnvSources. */ - private SmallRyeConfig getConfigForRuntimeDefaults() { + private SmallRyeConfig getConfigForRuntimeRecording() { SmallRyeConfigBuilder builder = ConfigUtils.emptyConfigBuilder(); + builder.getSources().clear(); + builder.getSourceProviders().clear(); + builder.setAddDefaultSources(false) + // Customizers may duplicate sources, but not much we can do about it, we need to run them + .addDiscoveredCustomizers() + // Readd microprofile-config.properties, because we disabled the default sources + .withSources(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)); + + // TODO - Should we reset quarkus.config.location to not record from these sources? for (ConfigSource configSource : config.getConfigSources()) { + if (configSource instanceof SysPropConfigSource) { + continue; + } if (configSource instanceof EnvConfigSource) { continue; } + if ("PropertiesConfigSource[source=Build system]".equals(configSource.getName())) { + continue; + } builder.withSources(configSource); } + builder.withSources(new AbstractConfigSource("Profiles", Integer.MAX_VALUE) { + private final Set<String> profiles = Set.of( + "quarkus.profile", + "quarkus.config.profile.parent", + "quarkus.test.profile", + SMALLRYE_CONFIG_PROFILE, + SMALLRYE_CONFIG_PROFILE_PARENT, + Config.PROFILE); + + @Override + public Set<String> getPropertyNames() { + return Collections.emptySet(); + } + + @Override + public String getValue(final String propertyName) { + if (profiles.contains(propertyName)) { + return config.getConfigValue(propertyName).getValue(); + } + return null; + }; + }); return builder.build(); } @@ -1102,13 +1141,15 @@ private Map<String, String> filterActiveProfileProperties(final Map<String, Stri return properties; } - private Map<String, String> getDefaults(final ConfigPatternMap<Container> patternMap) { + private static Map<String, String> getDefaults(final SmallRyeConfig config, + final ConfigPatternMap<Container> patternMap) { Map<String, String> defaultValues = new TreeMap<>(); - getDefaults(defaultValues, new StringBuilder(), patternMap); + getDefaults(config, defaultValues, new StringBuilder(), patternMap); return defaultValues; } - private void getDefaults( + private static void getDefaults( + final SmallRyeConfig config, final Map<String, String> defaultValues, final StringBuilder propertyName, final ConfigPatternMap<Container> patternMap) { @@ -1135,7 +1176,7 @@ private void getDefaults( } for (String childName : patternMap.childNames()) { - getDefaults(defaultValues, + getDefaults(config, defaultValues, new StringBuilder(propertyName).append(childName.equals(ConfigPatternMap.WILD_CARD) ? "*" : childName), patternMap.getChild(childName)); }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/java/org/acme/HelloService.java+1 −5 modified@@ -8,11 +8,7 @@ @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/java/org/acme/HelloService.java+1 −6 modified@@ -1,18 +1,13 @@ package org.acme; import io.quarkus.arc.profile.IfBuildProfile; -import org.eclipse.microprofile.config.inject.ConfigProperty; import jakarta.enterprise.context.ApplicationScoped; @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/test-extension/extension/deployment/src/main/resources/application.properties+2 −2 modified@@ -152,8 +152,8 @@ quarkus.arc.unremovable-types=foo # The YAML source may add an indexed property (depending on how the YAML is laid out). This is not supported by @ConfigRoot quarkus.arc.unremovable-types[0]=foo -### Do not record env values in build time -bt.do.not.record=properties +### recording +bt.ok.to.record=from-app %test.bt.profile.record=properties ### mappings
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java+14 −3 modified@@ -29,6 +29,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.extest.runtime.config.AnotherPrefixConfig; +import io.quarkus.extest.runtime.config.DoNotRecordEnvConfigSource; import io.quarkus.extest.runtime.config.MyEnum; import io.quarkus.extest.runtime.config.NestedConfig; import io.quarkus.extest.runtime.config.ObjectOfValue; @@ -52,9 +53,9 @@ public class ConfiguredBeanTest { static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ConfiguredBean.class) - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.OverrideBuildTimeConfigSource") + .addAsServiceProvider(ConfigSource.class, + OverrideBuildTimeConfigSource.class, + DoNotRecordEnvConfigSource.class) .addAsResource("application.properties")); @Inject @@ -363,6 +364,16 @@ public void testProfileDefaultValuesSource() { assertEquals("5678", defaultValues.getValue("%dev.my.prop")); assertEquals("1234", defaultValues.getValue("%test.my.prop")); assertEquals("1234", config.getValue("my.prop", String.class)); + + // runtime properties coming from env must not be recorded + assertNull(defaultValues.getValue("should.not.be.recorded")); + assertNull(defaultValues.getValue("SHOULD_NOT_BE_RECORDED")); + assertNull(defaultValues.getValue("quarkus.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.rt.do-not-record")); + assertNull(defaultValues.getValue("quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%prod.quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%dev.quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); } @Test
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/RuntimeDefaultsTest.java+21 −5 modified@@ -12,16 +12,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource; import io.quarkus.test.QuarkusUnitTest; import io.smallrye.config.SmallRyeConfig; public class RuntimeDefaultsTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource") + .addAsServiceProvider(ConfigSource.class, EnvBuildTimeConfigSource.class) .addAsResource("application.properties")); @Inject @@ -31,16 +30,33 @@ public class RuntimeDefaultsTest { void doNotRecordEnvRuntimeDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); assertTrue(defaultValues.isPresent()); - assertEquals("rtStringOptValue", defaultValues.get().getValue("quarkus.rt.rt-string-opt")); - assertEquals("properties", defaultValues.get().getValue("bt.do.not.record")); + // Do not record Env values for runtime + assertNull(defaultValues.get().getValue("quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); + // Property available in both Env and application.properties, ok to record application.properties value + assertEquals("from-app", defaultValues.get().getValue("bt.ok.to.record")); + // You still get the value from Env + assertEquals("from-env", config.getRawValue("bt.ok.to.record")); + // Do not record any of the other properties + assertNull(defaultValues.get().getValue(("do.not.record"))); + assertNull(defaultValues.get().getValue(("DO_NOT_RECORD"))); + assertEquals("value", config.getRawValue("do.not.record")); } @Test void doNotRecordActiveUnprofiledPropertiesDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); assertTrue(defaultValues.isPresent()); assertEquals("properties", config.getRawValue("bt.profile.record")); + // Property needs to be recorded as is, including the profile name assertEquals("properties", defaultValues.get().getValue("%test.bt.profile.record")); assertNull(defaultValues.get().getValue("bt.profile.record")); } + + @Test + void recordProfile() { + Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); + assertTrue(defaultValues.isPresent()); + assertEquals("record", config.getRawValue("quarkus.profile")); + } }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/DoNotRecordEnvConfigSource.java+19 −0 added@@ -0,0 +1,19 @@ +package io.quarkus.extest.runtime.config; + +import java.util.Map; + +import io.quarkus.runtime.annotations.StaticInitSafe; +import io.smallrye.config.EnvConfigSource; + +@StaticInitSafe +public class DoNotRecordEnvConfigSource extends EnvConfigSource { + public DoNotRecordEnvConfigSource() { + super(Map.of( + "SHOULD_NOT_BE_RECORDED", "value", + "should.not.be.recorded", "value", + "quarkus.rt.do-not-record", "value", + "quarkus.mapping.rt.do-not-record", "value", + "%dev.quarkus.mapping.rt.do-not-record", "dev", + "_PROD_QUARKUS_MAPPING_RT_DO_NOT_RECORD", "prod"), 300); + } +}
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/EnvBuildTimeConfigSource.java+7 −7 modified@@ -1,16 +1,16 @@ package io.quarkus.extest.runtime.config; -import java.util.HashMap; +import java.util.Map; import io.smallrye.config.EnvConfigSource; public class EnvBuildTimeConfigSource extends EnvConfigSource { public EnvBuildTimeConfigSource() { - super(new HashMap<>() { - { - put("QUARKUS_RT_RT_STRING_OPT", "changed"); - put("BT_DO_NOT_RECORD", "env-source"); - } - }, Integer.MAX_VALUE); + super(Map.of( + "QUARKUS_PROFILE", "record", + "QUARKUS_MAPPING_RT_DO_NOT_RECORD", "value", + "BT_OK_TO_RECORD", "from-env", + "BT_DO_NOT_RECORD", "value", + "DO_NOT_RECORD", "value"), Integer.MAX_VALUE); } }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java+8 −0 modified@@ -1,5 +1,7 @@ package io.quarkus.extest.runtime.config; +import java.util.Optional; + import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigMapping; @@ -17,6 +19,12 @@ public interface TestMappingRunTime { */ Group group(); + /** Record values from env test **/ + Optional<String> doNotRecord(); + + /** Record values with named profile **/ + Optional<String> recordProfiled(); + interface Group { /** * A Group value.
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestRunTimeConfig.java+4 −0 modified@@ -109,6 +109,10 @@ public class TestRunTimeConfig { public Map<String, Map<String, String>> mapMap; + /** Do not record **/ + @ConfigItem + public Optional<String> doNotRecord; + @Override public String toString() { return "TestRunTimeConfig{" +
990c3ee5dd5cDo not record local sources in runtime config defaults
12 files changed · +142 −56
core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java+65 −26 modified@@ -8,6 +8,10 @@ import static io.quarkus.deployment.util.ReflectUtil.unwrapInvocationTargetException; import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix; import static io.smallrye.config.Expressions.withoutExpansion; +import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE; +import static io.smallrye.config.SmallRyeConfig.SMALLRYE_CONFIG_PROFILE_PARENT; +import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES; import static java.util.stream.Collectors.toSet; import java.io.IOException; @@ -29,6 +33,7 @@ import java.util.SortedSet; import java.util.TreeMap; +import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.config.spi.ConfigSource; import org.eclipse.microprofile.config.spi.Converter; @@ -81,6 +86,7 @@ import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SysPropConfigSource; +import io.smallrye.config.common.AbstractConfigSource; /** * A configuration reader. @@ -517,10 +523,11 @@ ReadResult run() { nameBuilder.setLength(0); } - allBuildTimeValues.putAll(getDefaults(buildTimePatternMap)); - buildTimeRunTimeValues.putAll(getDefaults(buildTimeRunTimePatternMap)); + SmallRyeConfig runtimeConfig = getConfigForRuntimeRecording(); + + allBuildTimeValues.putAll(getDefaults(config, buildTimePatternMap)); + buildTimeRunTimeValues.putAll(getDefaults(config, buildTimeRunTimePatternMap)); - SmallRyeConfig runtimeDefaultsConfig = getConfigForRuntimeDefaults(); Set<String> registeredRoots = allRoots.stream().map(RootDefinition::getName).collect(toSet()); registeredRoots.add("quarkus"); Set<String> allProperties = getAllProperties(registeredRoots); @@ -600,7 +607,7 @@ ReadResult run() { knownProperty = knownProperty || matched != null; if (matched != null) { // it's a run-time default (record for later) - ConfigValue configValue = withoutExpansion(() -> runtimeDefaultsConfig.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeDefaultValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -611,7 +618,7 @@ ReadResult run() { knownProperty = knownProperty || matched != null; if (matched != null) { // it's a run-time default (record for later) - ConfigValue configValue = withoutExpansion(() -> runtimeDefaultsConfig.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeDefaultValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -622,7 +629,7 @@ ReadResult run() { } } else { // it's not managed by us; record it - ConfigValue configValue = withoutExpansion(() -> runtimeDefaultsConfig.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeDefaultValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -649,8 +656,8 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { - allBuildTimeValues.put(property, value.getRawValue()); + if (value.getRawValue() != null) { + allBuildTimeValues.put(value.getNameProfiled(), value.getRawValue()); } } } @@ -661,9 +668,9 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { - allBuildTimeValues.put(property, value.getRawValue()); - buildTimeRunTimeValues.put(property, value.getRawValue()); + if (value.getRawValue() != null) { + allBuildTimeValues.put(value.getNameProfiled(), value.getRawValue()); + buildTimeRunTimeValues.put(value.getNameProfiled(), value.getRawValue()); } } } @@ -673,9 +680,9 @@ ReadResult run() { Set<String> mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties); for (String property : mappedProperties) { unknownBuildProperties.remove(property); - ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { - runTimeDefaultValues.put(property, value.getRawValue()); + ConfigValue value = runtimeConfig.getConfigValue(property); + if (value.getRawValue() != null) { + runTimeDefaultValues.put(value.getNameProfiled(), value.getRawValue()); } } } @@ -1064,25 +1071,55 @@ private Set<String> getAllProperties(final Set<String> registeredRoots) { /** * Use this Config instance to record the runtime default values. We cannot use the main Config - * instance because it may record values coming from the EnvSource in build time. Environment variable values - * may be completely different between build and runtime, so it doesn't make sense to record these. - * <br> - * We do exclude the properties coming from the EnvSource, but a call to getValue may still provide a result - * coming from the EnvSource, so we need to exclude it from the sources when recording values for runtime. - * <br> - * We also do not want to completely exclude the EnvSource, because it may provide values for the build. This - * is only specific when recording the defaults. + * instance because it may record values coming from local development sources (Environment Variables, + * System Properties, etc.) in build time. Local config source values may be completely different between the + * build environment and the runtime environment, so it doesn't make sense to record these. * * @return a new SmallRye instance without the EnvSources. */ - private SmallRyeConfig getConfigForRuntimeDefaults() { + private SmallRyeConfig getConfigForRuntimeRecording() { SmallRyeConfigBuilder builder = ConfigUtils.emptyConfigBuilder(); + builder.getSources().clear(); + builder.getSourceProviders().clear(); + builder.setAddDefaultSources(false) + // Readd microprofile-config.properties, because we disabled the default sources + .withSources(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)); + + // TODO - Should we reset quarkus.config.location to not record from these sources? for (ConfigSource configSource : config.getConfigSources()) { + if (configSource instanceof SysPropConfigSource) { + continue; + } if (configSource instanceof EnvConfigSource) { continue; } + if ("PropertiesConfigSource[source=Build system]".equals(configSource.getName())) { + continue; + } builder.withSources(configSource); } + builder.withSources(new AbstractConfigSource("Profiles", Integer.MAX_VALUE) { + private final Set<String> profiles = Set.of( + "quarkus.profile", + "quarkus.config.profile.parent", + "quarkus.test.profile", + SMALLRYE_CONFIG_PROFILE, + SMALLRYE_CONFIG_PROFILE_PARENT, + Config.PROFILE); + + @Override + public Set<String> getPropertyNames() { + return Collections.emptySet(); + } + + @Override + public String getValue(final String propertyName) { + if (profiles.contains(propertyName)) { + return config.getConfigValue(propertyName).getValue(); + } + return null; + }; + }); return builder.build(); } @@ -1100,13 +1137,15 @@ private Map<String, String> filterActiveProfileProperties(final Map<String, Stri return properties; } - private Map<String, String> getDefaults(final ConfigPatternMap<Container> patternMap) { + private Map<String, String> getDefaults(final SmallRyeConfig config, + final ConfigPatternMap<Container> patternMap) { Map<String, String> defaultValues = new TreeMap<>(); - getDefaults(defaultValues, new StringBuilder(), patternMap); + getDefaults(config, defaultValues, new StringBuilder(), patternMap); return defaultValues; } private void getDefaults( + final SmallRyeConfig config, final Map<String, String> defaultValues, final StringBuilder propertyName, final ConfigPatternMap<Container> patternMap) { @@ -1133,7 +1172,7 @@ private void getDefaults( } for (String childName : patternMap.childNames()) { - getDefaults(defaultValues, + getDefaults(config, defaultValues, new StringBuilder(propertyName).append(childName.equals(ConfigPatternMap.WILD_CARD) ? "*" : childName), patternMap.getChild(childName)); }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/java/org/acme/HelloService.java+1 −5 modified@@ -8,11 +8,7 @@ @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/java/org/acme/HelloService.java+1 −6 modified@@ -1,18 +1,13 @@ package org.acme; import io.quarkus.arc.profile.IfBuildProfile; -import org.eclipse.microprofile.config.inject.ConfigProperty; import jakarta.enterprise.context.ApplicationScoped; @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/test-extension/extension/deployment/src/main/resources/application.properties+2 −2 modified@@ -152,8 +152,8 @@ quarkus.arc.unremovable-types=foo # The YAML source may add an indexed property (depending on how the YAML is laid out). This is not supported by @ConfigRoot quarkus.arc.unremovable-types[0]=foo -### Do not record env values in build time -bt.do.not.record=properties +### recording +bt.ok.to.record=from-app %test.bt.profile.record=properties ### mappings
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java+14 −3 modified@@ -29,6 +29,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.extest.runtime.config.AnotherPrefixConfig; +import io.quarkus.extest.runtime.config.DoNotRecordEnvConfigSource; import io.quarkus.extest.runtime.config.MyEnum; import io.quarkus.extest.runtime.config.NestedConfig; import io.quarkus.extest.runtime.config.ObjectOfValue; @@ -52,9 +53,9 @@ public class ConfiguredBeanTest { static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ConfiguredBean.class) - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.OverrideBuildTimeConfigSource") + .addAsServiceProvider(ConfigSource.class, + OverrideBuildTimeConfigSource.class, + DoNotRecordEnvConfigSource.class) .addAsResource("application.properties")); @Inject @@ -363,6 +364,16 @@ public void testProfileDefaultValuesSource() { assertEquals("5678", defaultValues.getValue("%dev.my.prop")); assertEquals("1234", defaultValues.getValue("%test.my.prop")); assertEquals("1234", config.getValue("my.prop", String.class)); + + // runtime properties coming from env must not be recorded + assertNull(defaultValues.getValue("should.not.be.recorded")); + assertNull(defaultValues.getValue("SHOULD_NOT_BE_RECORDED")); + assertNull(defaultValues.getValue("quarkus.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.rt.do-not-record")); + assertNull(defaultValues.getValue("quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%prod.quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%dev.quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); } @Test
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/RuntimeDefaultsTest.java+21 −4 modified@@ -12,16 +12,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource; import io.quarkus.test.QuarkusUnitTest; import io.smallrye.config.SmallRyeConfig; public class RuntimeDefaultsTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource") + .addAsServiceProvider(ConfigSource.class, EnvBuildTimeConfigSource.class) .addAsResource("application.properties")); @Inject @@ -31,15 +30,33 @@ public class RuntimeDefaultsTest { void doNotRecordEnvRuntimeDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("RunTime Defaults"); assertTrue(defaultValues.isPresent()); - assertEquals("properties", defaultValues.get().getValue("bt.do.not.record")); + // Do not record Env values for runtime + assertNull(defaultValues.get().getValue("quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); + // Property available in both Env and application.properties, ok to record application.properties value + assertEquals("from-app", defaultValues.get().getValue("bt.ok.to.record")); + // You still get the value from Env + assertEquals("from-env", config.getRawValue("bt.ok.to.record")); + // Do not record any of the other properties + assertNull(defaultValues.get().getValue(("do.not.record"))); + assertNull(defaultValues.get().getValue(("DO_NOT_RECORD"))); + assertEquals("value", config.getRawValue("do.not.record")); } @Test void doNotRecordActiveUnprofiledPropertiesDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("RunTime Defaults"); assertTrue(defaultValues.isPresent()); assertEquals("properties", config.getRawValue("bt.profile.record")); + // Property needs to be recorded as is, including the profile name assertEquals("properties", defaultValues.get().getValue("%test.bt.profile.record")); assertNull(defaultValues.get().getValue("bt.profile.record")); } + + @Test + void recordProfile() { + Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); + assertTrue(defaultValues.isPresent()); + assertEquals("record", config.getRawValue("quarkus.profile")); + } }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/DoNotRecordEnvConfigSource.java+19 −0 added@@ -0,0 +1,19 @@ +package io.quarkus.extest.runtime.config; + +import java.util.Map; + +import io.quarkus.runtime.annotations.StaticInitSafe; +import io.smallrye.config.EnvConfigSource; + +@StaticInitSafe +public class DoNotRecordEnvConfigSource extends EnvConfigSource { + public DoNotRecordEnvConfigSource() { + super(Map.of( + "SHOULD_NOT_BE_RECORDED", "value", + "should.not.be.recorded", "value", + "quarkus.rt.do-not-record", "value", + "quarkus.mapping.rt.do-not-record", "value", + "%dev.quarkus.mapping.rt.do-not-record", "dev", + "_PROD_QUARKUS_MAPPING_RT_DO_NOT_RECORD", "prod"), 300); + } +}
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/EnvBuildTimeConfigSource.java+7 −6 modified@@ -1,15 +1,16 @@ package io.quarkus.extest.runtime.config; -import java.util.HashMap; +import java.util.Map; import io.smallrye.config.EnvConfigSource; public class EnvBuildTimeConfigSource extends EnvConfigSource { public EnvBuildTimeConfigSource() { - super(new HashMap<String, String>() { - { - put("BT_DO_NOT_RECORD", "env-source"); - } - }, Integer.MAX_VALUE); + super(Map.of( + "QUARKUS_PROFILE", "record", + "QUARKUS_MAPPING_RT_DO_NOT_RECORD", "value", + "BT_OK_TO_RECORD", "from-env", + "BT_DO_NOT_RECORD", "value", + "DO_NOT_RECORD", "value"), Integer.MAX_VALUE); } }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java+8 −0 modified@@ -1,5 +1,7 @@ package io.quarkus.extest.runtime.config; +import java.util.Optional; + import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigMapping; @@ -17,6 +19,12 @@ public interface TestMappingRunTime { */ Group group(); + /** Record values from env test **/ + Optional<String> doNotRecord(); + + /** Record values with named profile **/ + Optional<String> recordProfiled(); + interface Group { /** * A Group value.
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestRunTimeConfig.java+4 −0 modified@@ -109,6 +109,10 @@ public class TestRunTimeConfig { public Map<String, Map<String, String>> mapMap; + /** Do not record **/ + @ConfigItem + public Optional<String> doNotRecord; + @Override public String toString() { return "TestRunTimeConfig{" +
91c3a58eaefeDo not record local sources in runtime config defaults
13 files changed · +110 −66
core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java+54 −13 modified@@ -9,6 +9,8 @@ import static io.quarkus.runtime.configuration.PropertiesUtil.filterPropertiesInRoots; import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix; import static io.smallrye.config.Expressions.withoutExpansion; +import static io.smallrye.config.PropertiesConfigSourceProvider.classPathSources; +import static io.smallrye.config.SmallRyeConfigBuilder.META_INF_MICROPROFILE_CONFIG_PROPERTIES; import static java.util.stream.Collectors.toSet; import java.io.IOException; @@ -512,10 +514,12 @@ ReadResult run() { nameBuilder.setLength(0); } + SmallRyeConfig runtimeConfig = getConfigForRuntimeRecording(); + // Register defaults for Roots - allBuildTimeValues.putAll(getDefaults(buildTimePatternMap)); - buildTimeRunTimeValues.putAll(getDefaults(buildTimeRunTimePatternMap)); - runTimeDefaultValues.putAll(getDefaults(runTimePatternMap)); + allBuildTimeValues.putAll(getDefaults(config, buildTimePatternMap)); + buildTimeRunTimeValues.putAll(getDefaults(config, buildTimeRunTimePatternMap)); + runTimeDefaultValues.putAll(getDefaults(runtimeConfig, runTimePatternMap)); // Register defaults for Mappings // Runtime defaults are added in ConfigGenerationBuildStep.generateBuilders to include user mappings @@ -602,7 +606,7 @@ ReadResult run() { knownProperty = knownProperty || matched != null; if (matched != null) { // it's a run-time default (record for later) - ConfigValue configValue = withoutExpansion(() -> config.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -613,7 +617,7 @@ ReadResult run() { } } else { // it's not managed by us; record it - ConfigValue configValue = withoutExpansion(() -> config.getConfigValue(propertyName)); + ConfigValue configValue = withoutExpansion(() -> runtimeConfig.getConfigValue(propertyName)); if (configValue.getValue() != null) { runTimeValues.put(configValue.getNameProfiled(), configValue.getValue()); } @@ -640,7 +644,7 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + if (value.getRawValue() != null) { allBuildTimeValues.put(value.getNameProfiled(), value.getRawValue()); } } @@ -652,7 +656,7 @@ ReadResult run() { for (String property : mappedProperties) { unknownBuildProperties.remove(property); ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + if (value.getRawValue() != null) { allBuildTimeValues.put(value.getNameProfiled(), value.getRawValue()); buildTimeRunTimeValues.put(value.getNameProfiled(), value.getRawValue()); } @@ -664,8 +668,8 @@ ReadResult run() { Set<String> mappedProperties = ConfigMappings.mappedProperties(mapping, allProperties); for (String property : mappedProperties) { unknownBuildProperties.remove(property); - ConfigValue value = config.getConfigValue(property); - if (value != null && value.getRawValue() != null) { + ConfigValue value = runtimeConfig.getConfigValue(property); + if (value.getRawValue() != null) { runTimeValues.put(value.getNameProfiled(), value.getRawValue()); } } @@ -1117,6 +1121,41 @@ public Set<String> getPropertyNames() { return properties; } + /** + * Use this Config instance to record the runtime default values. We cannot use the main Config + * instance because it may record values coming from local development sources (Environment Variables, + * System Properties, etc.) in at build time. Local config source values may be completely different between the + * build environment and the runtime environment, so it doesn't make sense to record these. + * + * @return a new {@link SmallRyeConfig} instance without the local sources, including SysPropConfigSource, + * EnvConfigSource, .env, and Build system sources. + */ + private SmallRyeConfig getConfigForRuntimeRecording() { + SmallRyeConfigBuilder builder = ConfigUtils.emptyConfigBuilder(); + builder.getSources().clear(); + builder.getSourceProviders().clear(); + builder.setAddDefaultSources(false) + // Customizers may duplicate sources, but not much we can do about it, we need to run them + .addDiscoveredCustomizers() + // Read microprofile-config.properties, because we disabled the default sources + .withSources(classPathSources(META_INF_MICROPROFILE_CONFIG_PROPERTIES, classLoader)); + + // TODO - Should we reset quarkus.config.location to not record from these sources? + for (ConfigSource configSource : config.getConfigSources()) { + if (configSource instanceof SysPropConfigSource) { + continue; + } + if (configSource instanceof EnvConfigSource) { + continue; + } + if ("PropertiesConfigSource[source=Build system]".equals(configSource.getName())) { + continue; + } + builder.withSources(configSource); + } + return builder.build(); + } + private Map<String, String> filterActiveProfileProperties(final Map<String, String> properties) { Set<String> propertiesToRemove = new HashSet<>(); for (String property : properties.keySet()) { @@ -1131,13 +1170,15 @@ private Map<String, String> filterActiveProfileProperties(final Map<String, Stri return properties; } - private Map<String, String> getDefaults(final ConfigPatternMap<Container> patternMap) { + private static Map<String, String> getDefaults(final SmallRyeConfig config, + final ConfigPatternMap<Container> patternMap) { Map<String, String> defaultValues = new TreeMap<>(); - getDefaults(defaultValues, new StringBuilder(), patternMap); + getDefaults(config, defaultValues, new StringBuilder(), patternMap); return defaultValues; } - private void getDefaults( + private static void getDefaults( + final SmallRyeConfig config, final Map<String, String> defaultValues, final StringBuilder propertyName, final ConfigPatternMap<Container> patternMap) { @@ -1164,7 +1205,7 @@ private void getDefaults( } for (String childName : patternMap.childNames()) { - getDefaults(defaultValues, + getDefaults(config, defaultValues, new StringBuilder(propertyName).append(childName.equals(ConfigPatternMap.WILD_CARD) ? "*" : childName), patternMap.getChild(childName)); }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/java/org/acme/HelloService.java+1 −5 modified@@ -8,11 +8,7 @@ @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-override/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/java/org/acme/HelloService.java+1 −6 modified@@ -1,18 +1,13 @@ package org.acme; import io.quarkus.arc.profile.IfBuildProfile; -import org.eclipse.microprofile.config.inject.ConfigProperty; import jakarta.enterprise.context.ApplicationScoped; @IfBuildProfile("foo") @ApplicationScoped public class HelloService { - - @ConfigProperty(name = "name") - String name; - public String name() { - return name; + return "from foo"; } }
integration-tests/maven/src/test/resources-filtered/projects/build-mode-quarkus-profile-property/src/main/resources/application.properties+0 −2 removed@@ -1,2 +0,0 @@ -name=from default -%foo.name=from foo
integration-tests/test-extension/extension/deployment/src/main/resources/application.properties+2 −2 modified@@ -152,8 +152,8 @@ quarkus.arc.unremovable-types=foo # The YAML source may add an indexed property (depending on how the YAML is laid out). This is not supported by @ConfigRoot quarkus.arc.unremovable-types[0]=foo -### Do not record env values in build time -bt.ok.to.record=properties +### recording +bt.ok.to.record=from-app %test.bt.profile.record=properties ### mappings
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java+12 −7 modified@@ -29,6 +29,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.extest.runtime.config.AnotherPrefixConfig; +import io.quarkus.extest.runtime.config.DoNotRecordEnvConfigSource; import io.quarkus.extest.runtime.config.MyEnum; import io.quarkus.extest.runtime.config.NestedConfig; import io.quarkus.extest.runtime.config.ObjectOfValue; @@ -52,10 +53,9 @@ public class ConfiguredBeanTest { static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ConfiguredBean.class) - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.OverrideBuildTimeConfigSource\n" + - "io.quarkus.extest.runtime.config.RecordQuarkusSystemPropertiesConfigSource") + .addAsServiceProvider(ConfigSource.class, + OverrideBuildTimeConfigSource.class, + DoNotRecordEnvConfigSource.class) .addAsResource("application.properties")); @Inject @@ -364,11 +364,16 @@ public void testProfileDefaultValuesSource() { assertEquals("5678", defaultValues.getValue("%dev.my.prop")); assertEquals("1234", defaultValues.getValue("%test.my.prop")); assertEquals("1234", config.getValue("my.prop", String.class)); + + // runtime properties coming from env must not be recorded assertNull(defaultValues.getValue("should.not.be.recorded")); assertNull(defaultValues.getValue("SHOULD_NOT_BE_RECORDED")); - assertEquals("value", defaultValues.getValue("quarkus.mapping.rt.record")); - assertEquals("prod", defaultValues.getValue("%prod.quarkus.mapping.rt.record")); - assertEquals("dev", defaultValues.getValue("%dev.quarkus.mapping.rt.record")); + assertNull(defaultValues.getValue("quarkus.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.rt.do-not-record")); + assertNull(defaultValues.getValue("quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%prod.quarkus.mapping.rt.do-not-record")); + assertNull(defaultValues.getValue("%dev.quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); } @Test
integration-tests/test-extension/extension/deployment/src/test/java/io/quarkus/extest/RuntimeDefaultsTest.java+11 −7 modified@@ -12,16 +12,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource; import io.quarkus.test.QuarkusUnitTest; import io.smallrye.config.SmallRyeConfig; public class RuntimeDefaultsTest { @RegisterExtension static final QuarkusUnitTest TEST = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar - // Don't change this to types, because of classloader class cast exception. - .addAsServiceProvider("org.eclipse.microprofile.config.spi.ConfigSource", - "io.quarkus.extest.runtime.config.EnvBuildTimeConfigSource") + .addAsServiceProvider(ConfigSource.class, EnvBuildTimeConfigSource.class) .addAsResource("application.properties")); @Inject @@ -31,20 +30,25 @@ public class RuntimeDefaultsTest { void doNotRecordEnvRuntimeDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); assertTrue(defaultValues.isPresent()); - // It's ok to record env properties for a Quarkus root - assertEquals("changed", defaultValues.get().getValue("quarkus.rt.rt-string-opt")); - // It's ok to record env properties for a property available in another source - assertEquals("env-source", defaultValues.get().getValue("bt.ok.to.record")); + // Do not record Env values for runtime + assertNull(defaultValues.get().getValue("quarkus.mapping.rt.do-not-record")); + assertEquals("value", config.getRawValue("quarkus.mapping.rt.do-not-record")); + // Property available in both Env and application.properties, ok to record application.properties value + assertEquals("from-app", defaultValues.get().getValue("bt.ok.to.record")); + // You still get the value from Env + assertEquals("from-env", config.getRawValue("bt.ok.to.record")); // Do not record any of the other properties assertNull(defaultValues.get().getValue(("do.not.record"))); assertNull(defaultValues.get().getValue(("DO_NOT_RECORD"))); + assertEquals("value", config.getRawValue("do.not.record")); } @Test void doNotRecordActiveUnprofiledPropertiesDefaults() { Optional<ConfigSource> defaultValues = config.getConfigSource("DefaultValuesConfigSource"); assertTrue(defaultValues.isPresent()); assertEquals("properties", config.getRawValue("bt.profile.record")); + // Property needs to be recorded as is, including the profile name assertEquals("properties", defaultValues.get().getValue("%test.bt.profile.record")); assertNull(defaultValues.get().getValue("bt.profile.record")); }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/DoNotRecordEnvConfigSource.java+19 −0 added@@ -0,0 +1,19 @@ +package io.quarkus.extest.runtime.config; + +import java.util.Map; + +import io.quarkus.runtime.annotations.StaticInitSafe; +import io.smallrye.config.EnvConfigSource; + +@StaticInitSafe +public class DoNotRecordEnvConfigSource extends EnvConfigSource { + public DoNotRecordEnvConfigSource() { + super(Map.of( + "SHOULD_NOT_BE_RECORDED", "value", + "should.not.be.recorded", "value", + "quarkus.rt.do-not-record", "value", + "quarkus.mapping.rt.do-not-record", "value", + "%dev.quarkus.mapping.rt.do-not-record", "dev", + "_PROD_QUARKUS_MAPPING_RT_DO_NOT_RECORD", "prod"), 300); + } +}
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/EnvBuildTimeConfigSource.java+5 −3 modified@@ -6,8 +6,10 @@ public class EnvBuildTimeConfigSource extends EnvConfigSource { public EnvBuildTimeConfigSource() { - super(Map.of("QUARKUS_RT_RT_STRING_OPT", "changed", - "BT_OK_TO_RECORD", "env-source", - "DO_NOT_RECORD", "record"), Integer.MAX_VALUE); + super(Map.of( + "QUARKUS_MAPPING_RT_DO_NOT_RECORD", "value", + "BT_OK_TO_RECORD", "from-env", + "BT_DO_NOT_RECORD", "value", + "DO_NOT_RECORD", "value"), Integer.MAX_VALUE); } }
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/RecordQuarkusSystemPropertiesConfigSource.java+0 −18 removed@@ -1,18 +0,0 @@ -package io.quarkus.extest.runtime.config; - -import java.util.Map; - -import io.quarkus.runtime.annotations.StaticInitSafe; -import io.smallrye.config.EnvConfigSource; - -@StaticInitSafe -public class RecordQuarkusSystemPropertiesConfigSource extends EnvConfigSource { - public RecordQuarkusSystemPropertiesConfigSource() { - super(Map.of( - "SHOULD_NOT_BE_RECORDED", "value", - "should.not.be.recorded", "value", - "quarkus.mapping.rt.record", "value", - "%dev.quarkus.mapping.rt.record", "dev", - "_PROD_QUARKUS_MAPPING_RT_RECORD", "prod"), 0); - } -}
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestMappingRunTime.java+1 −1 modified@@ -20,7 +20,7 @@ public interface TestMappingRunTime { Group group(); /** Record values from env test **/ - Optional<String> record(); + Optional<String> doNotRecord(); /** Record values with named profile **/ Optional<String> recordProfiled();
integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/config/TestRunTimeConfig.java+4 −0 modified@@ -109,6 +109,10 @@ public class TestRunTimeConfig { public Map<String, Map<String, String>> mapMap; + /** Do not record **/ + @ConfigItem + public Optional<String> doNotRecord; + @Override public String toString() { return "TestRunTimeConfig{" +
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
16- github.com/advisories/GHSA-f8h5-v2vg-46rrghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-2700ghsaADVISORY
- access.redhat.com/errata/RHSA-2024:11023nvdWEB
- access.redhat.com/errata/RHSA-2024:2106nvdWEB
- access.redhat.com/errata/RHSA-2024:2705nvdWEB
- access.redhat.com/errata/RHSA-2024:3527nvdWEB
- access.redhat.com/errata/RHSA-2024:4028nvdWEB
- access.redhat.com/errata/RHSA-2024:4873nvdWEB
- access.redhat.com/security/cve/CVE-2024-2700nvdWEB
- bugzilla.redhat.com/show_bug.cginvdWEB
- github.com/quarkusio/quarkus/commit/2b24dc8dbc8f390c97428783d67614418676fc2eghsaWEB
- github.com/quarkusio/quarkus/commit/91c3a58eaefe59e0afd430653d1636d664bd593fghsaWEB
- github.com/quarkusio/quarkus/commit/990c3ee5dd5c689f514e5e87c221bce6d5dff267ghsaWEB
- github.com/quarkusio/quarkus/issues/39927ghsaWEB
- quarkus.io/blog/quarkus-3-2-12-final-releasedghsaWEB
- quarkus.io/blog/quarkus-3-8-4-releasedghsaWEB
News mentions
0No linked articles in our index yet.