Skip to content

Commit 4ca869b

Browse files
l46kokcopybara-github
authored andcommitted
Add CelOptions to disable comprehension
Fixes #484 PiperOrigin-RevId: 700440718
1 parent e104ba7 commit 4ca869b

File tree

5 files changed

+127
-3
lines changed

5 files changed

+127
-3
lines changed

bundle/src/test/java/dev/cel/bundle/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ java_library(
1818
"//checker:proto_type_mask",
1919
"//common",
2020
"//common:compiler_common",
21+
"//common:error_codes",
2122
"//common:options",
2223
"//common:proto_ast",
2324
"//common/ast",

bundle/src/test/java/dev/cel/bundle/CelImplTest.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import dev.cel.checker.ProtoTypeMask;
6464
import dev.cel.checker.TypeProvider;
6565
import dev.cel.common.CelAbstractSyntaxTree;
66+
import dev.cel.common.CelErrorCode;
6667
import dev.cel.common.CelIssue;
6768
import dev.cel.common.CelOptions;
6869
import dev.cel.common.CelProtoAbstractSyntaxTree;
@@ -1961,6 +1962,73 @@ public void program_nativeTypeUnknownsEnabled_asCallArguments() throws Exception
19611962
assertThat(result.attributes()).isEmpty();
19621963
}
19631964

1965+
@Test
1966+
@TestParameters("{expression: 'string(123)'}")
1967+
@TestParameters("{expression: 'string(123u)'}")
1968+
@TestParameters("{expression: 'string(1.5)'}")
1969+
@TestParameters("{expression: 'string(\"foo\")'}")
1970+
@TestParameters("{expression: 'string(b\"foo\")'}")
1971+
@TestParameters("{expression: 'string(timestamp(100))'}")
1972+
@TestParameters("{expression: 'string(duration(\"1h\"))'}")
1973+
public void program_stringConversionDisabled_throws(String expression) throws Exception {
1974+
Cel cel =
1975+
CelFactory.standardCelBuilder()
1976+
.setOptions(
1977+
CelOptions.current()
1978+
.enableTimestampEpoch(true)
1979+
.enableStringConversion(false)
1980+
.build())
1981+
.build();
1982+
CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
1983+
1984+
CelEvaluationException e =
1985+
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
1986+
assertThat(e).hasMessageThat().contains("No matching overload for function 'string'");
1987+
assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND);
1988+
}
1989+
1990+
@Test
1991+
public void program_stringConcatenationDisabled_throws() throws Exception {
1992+
Cel cel =
1993+
CelFactory.standardCelBuilder()
1994+
.setOptions(CelOptions.current().enableStringConcatenation(false).build())
1995+
.build();
1996+
CelAbstractSyntaxTree ast = cel.compile("'foo' + 'bar'").getAst();
1997+
1998+
CelEvaluationException e =
1999+
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
2000+
assertThat(e).hasMessageThat().contains("No matching overload for function '_+_'");
2001+
assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND);
2002+
}
2003+
2004+
@Test
2005+
public void program_listConcatenationDisabled_throws() throws Exception {
2006+
Cel cel =
2007+
CelFactory.standardCelBuilder()
2008+
.setOptions(CelOptions.current().enableListConcatenation(false).build())
2009+
.build();
2010+
CelAbstractSyntaxTree ast = cel.compile("[1] + [2]").getAst();
2011+
2012+
CelEvaluationException e =
2013+
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
2014+
assertThat(e).hasMessageThat().contains("No matching overload for function '_+_'");
2015+
assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND);
2016+
}
2017+
2018+
@Test
2019+
public void program_comprehensionDisabled_throws() throws Exception {
2020+
Cel cel =
2021+
standardCelBuilderWithMacros()
2022+
.setOptions(CelOptions.current().enableComprehension(false).build())
2023+
.build();
2024+
CelAbstractSyntaxTree ast = cel.compile("['foo', 'bar'].map(x, x)").getAst();
2025+
2026+
CelEvaluationException e =
2027+
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
2028+
assertThat(e).hasMessageThat().contains("Iteration budget exceeded: 0");
2029+
assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.ITERATION_BUDGET_EXCEEDED);
2030+
}
2031+
19642032
@Test
19652033
public void toBuilder_isImmutable() {
19662034
CelBuilder celBuilder = CelFactory.standardCelBuilder();

common/src/main/java/dev/cel/common/CelOptions.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ public enum ProtoUnsetFieldOptions {
109109

110110
public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption();
111111

112+
public abstract boolean enableStringConversion();
113+
114+
public abstract boolean enableStringConcatenation();
115+
116+
public abstract boolean enableListConcatenation();
117+
118+
public abstract boolean enableComprehension();
119+
112120
public abstract Builder toBuilder();
113121

114122
public ImmutableSet<ExprFeatures> toExprFeatures() {
@@ -200,7 +208,11 @@ public static Builder newBuilder() {
200208
.enableCelValue(false)
201209
.comprehensionMaxIterations(-1)
202210
.unwrapWellKnownTypesOnFunctionDispatch(true)
203-
.fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT);
211+
.fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT)
212+
.enableStringConversion(true)
213+
.enableStringConcatenation(true)
214+
.enableListConcatenation(true)
215+
.enableComprehension(true);
204216
}
205217

206218
/**
@@ -504,6 +516,31 @@ public abstract static class Builder {
504516
*/
505517
public abstract Builder fromProtoUnsetFieldOption(ProtoUnsetFieldOptions value);
506518

519+
/**
520+
* Enables string() overloads for the runtime. This option exists to maintain parity with
521+
* cel-cpp interpreter options.
522+
*/
523+
public abstract Builder enableStringConversion(boolean value);
524+
525+
/**
526+
* Enables string concatenation overload for the runtime. This option exists to maintain parity
527+
* with cel-cpp interpreter options.
528+
*/
529+
public abstract Builder enableStringConcatenation(boolean value);
530+
531+
/**
532+
* Enables list concatenation overload for the runtime. This option exists to maintain parity
533+
* with cel-cpp interpreter options.
534+
*/
535+
public abstract Builder enableListConcatenation(boolean value);
536+
537+
/**
538+
* Enables comprehension (macros) for the runtime. Setting false has the same effect with
539+
* assigning 0 for {@link #comprehensionMaxIterations()}. This option exists to maintain parity
540+
* with cel-cpp interpreter options.
541+
*/
542+
public abstract Builder enableComprehension(boolean value);
543+
507544
public abstract CelOptions build();
508545
}
509546
}

runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import dev.cel.common.types.CelTypes;
4444
import dev.cel.common.values.CelValueProvider;
4545
import dev.cel.common.values.ProtoMessageValueProvider;
46+
import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Arithmetic;
4647
import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Comparison;
4748
import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Conversions;
4849
import java.util.Arrays;
@@ -317,6 +318,22 @@ private ImmutableSet<CelFunctionBinding> newStandardFunctionBindings(
317318
return options.enableTimestampEpoch();
318319
}
319320
break;
321+
case STRING:
322+
if (!options.enableStringConversion()) {
323+
return false;
324+
}
325+
break;
326+
case ADD:
327+
Arithmetic arithmetic = (Arithmetic) standardOverload;
328+
if (!options.enableStringConcatenation()
329+
&& arithmetic.equals(Arithmetic.ADD_STRING)) {
330+
return false;
331+
}
332+
if (!options.enableListConcatenation()
333+
&& arithmetic.equals(Arithmetic.ADD_LIST)) {
334+
return false;
335+
}
336+
break;
320337
default:
321338
if (standardOverload instanceof Comparison
322339
&& !options.enableHeterogeneousNumericComparisons()) {

runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,10 @@ public Object evalTrackingUnknowns(
179179
Optional<? extends FunctionResolver> functionResolver,
180180
CelEvaluationListener listener)
181181
throws InterpreterException {
182+
int comprehensionMaxIterations =
183+
celOptions.enableComprehension() ? celOptions.comprehensionMaxIterations() : 0;
182184
ExecutionFrame frame =
183-
new ExecutionFrame(
184-
listener, resolver, functionResolver, celOptions.comprehensionMaxIterations());
185+
new ExecutionFrame(listener, resolver, functionResolver, comprehensionMaxIterations);
185186
IntermediateResult internalResult = evalInternal(frame, ast.getExpr());
186187
return internalResult.value();
187188
}

0 commit comments

Comments
 (0)