fix: improve handling when expressions are disabled (#42189) (#42240)

closes: #42158


(cherry picked from commit f52421fe44)

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins
2025-09-02 11:02:22 -04:00
committed by GitHub
parent 4254f16b6a
commit 7ef44e5f93
7 changed files with 23 additions and 10 deletions

View File

@@ -265,4 +265,8 @@ public final class Environment {
public static void removeHomeDir() {
System.getProperties().remove(KC_HOME_DIR);
}
public static void setRebuild() {
System.setProperty("quarkus.launch.rebuild", "true");
}
}

View File

@@ -80,7 +80,7 @@ public final class Build extends AbstractCommand implements Runnable {
validateConfig();
return null;
});
System.setProperty("quarkus.launch.rebuild", "true");
Environment.setRebuild();
println(spec.commandLine(), "Updating the configuration and installing your custom providers, if any. Please wait.");

View File

@@ -35,7 +35,6 @@ import java.util.stream.Stream;
import org.keycloak.config.DeprecatedMetadata;
import org.keycloak.config.Option;
import org.keycloak.config.OptionCategory;
import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.cli.PropertyException;
import org.keycloak.quarkus.runtime.cli.ShortErrorMessageHandler;
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
@@ -261,7 +260,8 @@ public class PropertyMapper<T> {
boolean mapped = false;
// fall back to the transformer when no mapper is explicitly specified in .mapFrom()
var theMapper = parentValue && parentMapper != null ? this.parentMapper : this.mapper;
if (theMapper != null && (!name.equals(getFrom()) || parentValue)) {
// since our mapping logic assumes fully resolved values, we cannot reliably map if Expressions are disabled
if (Expressions.isEnabled() && theMapper != null && (!name.equals(getFrom()) || parentValue)) {
mappedValue = theMapper.map(getNamedProperty().orElse(null), value, context);
mapped = true;
}
@@ -281,10 +281,6 @@ public class PropertyMapper<T> {
return configValue;
}
if (!isBuildTime() && Environment.isRebuild()) {
value = null; // prevent quarkus from recording these raw values as runtime defaults
}
// by unsetting the ordinal this will not be seen as directly modified by the user
return configValue.from().withName(name).withValue(mappedValue).withRawValue(value).withConfigSourceOrdinal(0).build();
}

View File

@@ -2,6 +2,7 @@ package org.keycloak.quarkus.runtime.configuration.mappers;
import io.smallrye.config.ConfigSourceInterceptorContext;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.Expressions;
import jakarta.ws.rs.core.MultivaluedHashMap;
import org.jboss.logging.Logger;
import org.keycloak.common.util.CollectionUtil;
@@ -84,9 +85,10 @@ public final class PropertyMappers {
//
// The special handling of log properties is because some logging runtime properties are requested during build time
// and we need to resolve them. That should be fine as they are generally not considered security sensitive.
// If however expressions are not enabled that means quarkus is specifically looking for runtime defaults, and we should not provide a value
// See https://github.com/quarkusio/quarkus/pull/42157
if (isRebuild() && isKeycloakRuntime(name, mapper)
&& !NestedPropertyMappingInterceptor.getResolvingRoot().orElse(name).startsWith("quarkus.log.")) {
&& (!NestedPropertyMappingInterceptor.getResolvingRoot().orElse(name).startsWith("quarkus.log.") || !Expressions.isEnabled())) {
return ConfigValue.builder().withName(name).build();
}

View File

@@ -82,8 +82,11 @@ public class ConfigurationTest extends AbstractConfigurationTest {
@Test
public void testKeycloakConfPlaceholder() {
assertEquals("info", createConfig().getRawValue("kc.log-level"));
assertTrue(Configuration.getConfig().isPropertyPresent("quarkus.log.category.\"io.k8s\".level"));
putEnvVar("SOME_LOG_LEVEL", "debug");
assertEquals("debug", createConfig().getRawValue("kc.log-level"));
Environment.setRebuild();
assertNull(Expressions.withoutExpansion(() -> Configuration.getConfigValue("kc.log-level")).getValue());
}
@Test
@@ -250,7 +253,7 @@ public class ConfigurationTest extends AbstractConfigurationTest {
ConfigArgsConfigSource.setCliArgs("--db=mysql");
SmallRyeConfig config = createConfig();
String value = Expressions.withoutExpansion(() -> config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals("jdbc:mysql://${kc.db-url-host:localhost}:${kc.db-url-port:3306}/${kc.db-url-database:keycloak}${kc.db-url-properties:}", value);
assertEquals("mysql", value);
}
@Test

View File

@@ -85,7 +85,7 @@ public class DatasourcesConfigurationTest extends AbstractConfigurationTest {
ConfigArgsConfigSource.setCliArgs("--db-kind-store=mysql");
SmallRyeConfig config = createConfig();
String value = Expressions.withoutExpansion(() -> config.getConfigValue("quarkus.datasource.\"store\".jdbc.url").getValue());
assertEquals("jdbc:mysql://${kc.db-url-host-store:localhost}:${kc.db-url-port-store:3306}/${kc.db-url-database-store:keycloak}${kc.db-url-properties-store:}", value);
assertEquals("mysql", value);
assertExternalConfig("quarkus.datasource.\"store\".jdbc.url", "jdbc:mysql://localhost:3306/keycloak");
}

View File

@@ -102,4 +102,12 @@ class BuildCommandDistTest {
cliResult.assertError(String.format("ERROR: Unable to find the JDBC driver (%s). You need to install it.", dbDriver));
cliResult.assertNoBuild();
}
@Test
@RawDistOnly(reason = "Containers are immutable")
@WithEnvVars({"KC_LOG_LEVEL", "${KEYCLOAK_LOG_LEVEL:INFO},org.keycloak.events:DEBUG"})
@Launch({"build", "--db=dev-file"})
void logLevelExpressionWithDefault(CLIResult cliResult) {
cliResult.assertBuild();
}
}