diff options
author | Bjørn Christian Seime <bjorncs@vespa.ai> | 2024-06-06 11:33:21 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@vespa.ai> | 2024-06-06 11:40:41 +0200 |
commit | 64678270e5ac9ab3a9f2b6523b4c2fc80999c4d9 (patch) | |
tree | ba021fc81560692b7860b877ddce0007182e3536 | |
parent | cf00a65940560c8fbfe32a015f4ef50942e997d8 (diff) |
Validate flag content with a stricter regex
4 files changed, 32 insertions, 3 deletions
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index df307b581f1..c207fd63dbd 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -12,6 +12,7 @@ import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; import java.util.TreeMap; +import java.util.function.Consumer; import java.util.function.Predicate; import static com.yahoo.vespa.flags.Dimension.APPLICATION; @@ -528,6 +529,15 @@ public class Flags { flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions); } + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ + public static <T> UnboundListFlag<T> defineListFlag(String flagId, List<T> defaultValue, Class<T> elementClass, + List<String> owners, String createdAt, String expiresAt, + String description, String modificationEffect, + Predicate<List<T>> validator, Dimension... dimensions) { + return define((fid, dval, fvec) -> new UnboundListFlag<>(fid, dval, elementClass, fvec, validator), + flagId, defaultValue, owners, createdAt, expiresAt, description, modificationEffect, dimensions); + } + @FunctionalInterface private interface TypedUnboundFlagFactory<T, U extends UnboundFlag<?, ?, ?>> { U create(FlagId id, T defaultValue, FetchVector defaultFetchVector); diff --git a/flags/src/main/java/com/yahoo/vespa/flags/JacksonArraySerializer.java b/flags/src/main/java/com/yahoo/vespa/flags/JacksonArraySerializer.java index 8f7b7d71734..38e3b57d28b 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/JacksonArraySerializer.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/JacksonArraySerializer.java @@ -4,20 +4,27 @@ package com.yahoo.vespa.flags; import com.fasterxml.jackson.databind.JavaType; import java.util.List; +import java.util.function.Predicate; /** * @author freva */ public class JacksonArraySerializer<T> implements FlagSerializer<List<T>> { private final JavaType type; + private final Predicate<List<T>> validator; - public JacksonArraySerializer(Class<T> clazz) { + public JacksonArraySerializer(Class<T> clazz, Predicate<List<T>> validator) { type = JsonNodeRawFlag.constructCollectionType(List.class, clazz); + this.validator = validator; } @Override public List<T> deserialize(RawFlag rawFlag) { - return JsonNodeRawFlag.fromJsonNode(rawFlag.asJsonNode()).toJacksonClass(type); + var list = JsonNodeRawFlag.fromJsonNode(rawFlag.asJsonNode()).<List<T>>toJacksonClass(type); + if (!validator.test(list)) { + throw new IllegalArgumentException("Invalid value: " + list); + } + return list; } @Override diff --git a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java index fb807d186eb..19888ec362d 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/PermanentFlags.java @@ -459,6 +459,7 @@ public class PermanentFlags { "log-request-content", List.of(), String.class, "Include request content in access log for paths starting with any of these prefixes", "Takes effect on next redeployment", + list -> list.stream().allMatch(s -> s.matches("^[a-zA-Z/\\.0-9]+:(0(\\.\\d+)?|1(\\.0+)?):\\d+(B|kB|MB|GB)?$")), INSTANCE_ID); private PermanentFlags() {} @@ -503,5 +504,10 @@ public class PermanentFlags { return Flags.defineListFlag(flagId, defaultValue, elementClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, dimensions); } + private static <T> UnboundListFlag<T> defineListFlag( + String flagId, List<T> defaultValue, Class<T> elementClass, String description, String modificationEffect, Predicate<List<T>> validator, Dimension... dimensions) { + return Flags.defineListFlag(flagId, defaultValue, elementClass, OWNERS, toString(CREATED_AT), toString(EXPIRES_AT), description, modificationEffect, validator, dimensions); + } + private static String toString(Instant instant) { return DateTimeFormatter.ISO_DATE.withZone(ZoneOffset.UTC).format(instant); } } diff --git a/flags/src/main/java/com/yahoo/vespa/flags/UnboundListFlag.java b/flags/src/main/java/com/yahoo/vespa/flags/UnboundListFlag.java index f88a0648021..8411a286d54 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/UnboundListFlag.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/UnboundListFlag.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.flags; import java.util.List; +import java.util.function.Predicate; /** * @author freva @@ -12,8 +13,13 @@ public class UnboundListFlag<T> extends UnboundFlagImpl<List<T>, ListFlag<T>, Un } public UnboundListFlag(FlagId id, List<T> defaultValue, Class<T> clazz, FetchVector defaultFetchVector) { + this(id, defaultValue, clazz, defaultFetchVector, __ -> true); + } + + public UnboundListFlag(FlagId id, List<T> defaultValue, Class<T> clazz, FetchVector defaultFetchVector, + Predicate<List<T>> validator) { super(id, defaultValue, defaultFetchVector, - new JacksonArraySerializer<T>(clazz), + new JacksonArraySerializer<T>(clazz, validator), (flagId, defVal, fetchVector) -> new UnboundListFlag<>(flagId, defVal, clazz, fetchVector), ListFlag::new); } |