fix: adding a check for truncated last modified timestamps (#39340)

closes: #38893

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2025-04-30 03:10:41 -04:00 committed by GitHub
parent 24910d9e1c
commit 0ff4cce318
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 2 deletions

View File

@ -65,7 +65,6 @@ import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.quarkus.runtime.configuration.DisabledMappersInterceptor;
import org.keycloak.quarkus.runtime.configuration.KcUnmatchedArgumentException;
import org.keycloak.quarkus.runtime.configuration.KeycloakPropertiesConfigSource;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
import org.keycloak.quarkus.runtime.configuration.PropertyMappingInterceptor;
import org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource;
@ -354,7 +353,9 @@ public class Picocli {
// we have to ignore things like the profile properties because the commands set them at runtime
checkChangesInBuildOptions((key, oldValue, newValue) -> {
if (key.startsWith(KC_PROVIDER_FILE_PREFIX)) {
throw new PropertyException("A provider JAR was updated since the last build, please rebuild for this to be fully utilized.");
if (timestampChanged(oldValue, newValue)) {
throw new PropertyException("A provider JAR was updated since the last build, please rebuild for this to be fully utilized.");
}
} else if (newValue != null && !isIgnoredPersistedOption(key)
&& isUserModifiable(Configuration.getConfigValue(key))) {
ignoredBuildTime.add(key);
@ -461,6 +462,16 @@ public class Picocli {
}
}
static boolean timestampChanged(String oldValue, String newValue) {
if (newValue != null && oldValue != null) {
long longNewValue = Long.valueOf(newValue);
long longOldValue = Long.valueOf(oldValue);
// docker commonly truncates to the second at runtime, so we'll allow that special case
return ((longNewValue / 1000) * 1000) != longNewValue || ((longOldValue / 1000) * 1000) != longNewValue;
}
return true;
}
private void validateProperty(AbstractCommand abstractCommand, IncludeOptions options,
final List<String> ignoredRunTime, final Set<String> disabledBuildTime, final Set<String> disabledRunTime,
final Set<String> deprecatedInUse, final Set<String> missingOption,

View File

@ -675,6 +675,15 @@ public class PicocliTest extends AbstractConfigurationTest {
assertLogAsyncHandlerInvalidValues(LoggingOptions.Handler.syslog);
}
@Test
public void timestampChanged() {
assertTrue(Picocli.timestampChanged("12345", null));
assertTrue(Picocli.timestampChanged("12345", "12346"));
assertTrue(Picocli.timestampChanged("12000", "12346"));
// new is truncated - should not be a change
assertFalse(Picocli.timestampChanged("12345", "12000"));
}
protected void assertLogAsyncHandlerInvalidValues(LoggingOptions.Handler handler) {
var handlerName = handler.toString();