Skip to content

Commit e927da9

Browse files
committed
fix(openfeature): return PARSE_ERROR for invalid regex in flag condition
1 parent ace934e commit e927da9

2 files changed

Lines changed: 30 additions & 7 deletions

File tree

products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.concurrent.TimeUnit;
3939
import java.util.concurrent.atomic.AtomicReference;
4040
import java.util.regex.Pattern;
41+
import java.util.regex.PatternSyntaxException;
4142

4243
class DDEvaluator implements Evaluator, FeatureFlaggingGateway.ConfigListener {
4344

@@ -147,6 +148,8 @@ public <T> ProviderEvaluation<T> evaluate(
147148
.value(defaultValue)
148149
.reason(Reason.DEFAULT.name())
149150
.build();
151+
} catch (final PatternSyntaxException e) {
152+
return error(defaultValue, ErrorCode.PARSE_ERROR, e);
150153
} catch (final NumberFormatException e) {
151154
return error(defaultValue, ErrorCode.TYPE_MISMATCH, e);
152155
} catch (final Exception e) {
@@ -250,12 +253,10 @@ private static boolean evaluateCondition(
250253
}
251254

252255
private static boolean matchesRegex(final Object attributeValue, final Object conditionValue) {
253-
try {
254-
final Pattern pattern = Pattern.compile(String.valueOf(conditionValue));
255-
return pattern.matcher(String.valueOf(attributeValue)).find();
256-
} catch (Exception e) {
257-
return false;
258-
}
256+
// PatternSyntaxException is intentionally not caught here so it propagates to evaluate(),
257+
// which maps it to ErrorCode.PARSE_ERROR.
258+
final Pattern pattern = Pattern.compile(String.valueOf(conditionValue));
259+
return pattern.matcher(String.valueOf(attributeValue)).find();
259260
}
260261

261262
private static boolean isOneOf(final Object attributeValue, final Object conditionValue) {

products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,12 @@ private static List<TestCase<?>> evaluateTestCases() {
462462
.result(
463463
new Result<>("null-handled")
464464
.reason(TARGETING_MATCH.name())
465-
.variant("null-variant")));
465+
.variant("null-variant")),
466+
new TestCase<>("default")
467+
.flag("invalid-regex-flag")
468+
.targetingKey("user-123")
469+
.context("email", "user@example.com")
470+
.result(new Result<>("default").reason(ERROR.name()).errorCode(ErrorCode.PARSE_ERROR)));
466471
}
467472

468473
@MethodSource("evaluateTestCases")
@@ -551,6 +556,7 @@ private ServerConfiguration createTestConfiguration() {
551556
flags.put("not-one-of-false-flag", createNotOneOfFalseFlag());
552557
flags.put("null-context-values-flag", createNullContextValuesFlag());
553558
flags.put("country-rule-flag", createCountryRuleFlag());
559+
flags.put("invalid-regex-flag", createInvalidRegexFlag());
554560
return new ServerConfiguration(null, null, null, flags);
555561
}
556562

@@ -1236,6 +1242,22 @@ private Flag createCountryRuleFlag() {
12361242
asList(usAllocation, globalAllocation));
12371243
}
12381244

1245+
private Flag createInvalidRegexFlag() {
1246+
final Map<String, Variant> variants = new HashMap<>();
1247+
variants.put("matched", new Variant("matched", "matched-value"));
1248+
1249+
// Condition with an intentionally invalid regex pattern (unclosed bracket)
1250+
final List<ConditionConfiguration> conditions =
1251+
singletonList(new ConditionConfiguration(ConditionOperator.MATCHES, "email", "[invalid"));
1252+
final List<Rule> rules = singletonList(new Rule(conditions));
1253+
final List<Split> splits = singletonList(new Split(emptyList(), "matched", null));
1254+
final Allocation allocation =
1255+
new Allocation("invalid-regex-alloc", rules, null, null, splits, false);
1256+
1257+
return new Flag(
1258+
"invalid-regex-flag", true, ValueType.STRING, variants, singletonList(allocation));
1259+
}
1260+
12391261
private static Map<String, Object> mapOf(final Object... props) {
12401262
final Map<String, Object> result = new HashMap<>(props.length << 1);
12411263
int index = 0;

0 commit comments

Comments
 (0)