Skip to content

Commit 72c07f8

Browse files
l46kokcopybara-github
authored andcommitted
Evaluate CEL's null and bytes to their native equivalent types
PiperOrigin-RevId: 793812620
1 parent 5b06cc0 commit 72c07f8

70 files changed

Lines changed: 490 additions & 226 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ java_library(
4141
"//common/types:cel_proto_types",
4242
"//common/types:message_type_provider",
4343
"//common/types:type_providers",
44+
"//common/values",
45+
"//common/values:cel_byte_string",
4446
"//compiler",
4547
"//compiler:compiler_builder",
4648
"//extensions",
@@ -64,7 +66,6 @@ java_library(
6466
"@maven//:com_google_truth_extensions_truth_proto_extension",
6567
"@maven//:junit_junit",
6668
"@maven//:org_jspecify_jspecify",
67-
"@maven_android//:com_google_protobuf_protobuf_javalite",
6869
],
6970
)
7071

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,13 @@
4040
import com.google.common.collect.ImmutableSet;
4141
import com.google.common.util.concurrent.MoreExecutors;
4242
import com.google.protobuf.Any;
43-
import com.google.protobuf.ByteString;
4443
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
4544
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
4645
import com.google.protobuf.Descriptors.FileDescriptor;
4746
import com.google.protobuf.Duration;
4847
import com.google.protobuf.Empty;
4948
import com.google.protobuf.FieldMask;
5049
import com.google.protobuf.Message;
51-
import com.google.protobuf.NullValue;
5250
import com.google.protobuf.Struct;
5351
import com.google.protobuf.TextFormat;
5452
import com.google.protobuf.Timestamp;
@@ -86,6 +84,8 @@
8684
import dev.cel.common.types.ProtoMessageTypeProvider;
8785
import dev.cel.common.types.SimpleType;
8886
import dev.cel.common.types.StructTypeReference;
87+
import dev.cel.common.values.CelByteString;
88+
import dev.cel.common.values.NullValue;
8989
import dev.cel.compiler.CelCompiler;
9090
import dev.cel.compiler.CelCompilerFactory;
9191
import dev.cel.compiler.CelCompilerImpl;
@@ -1019,7 +1019,10 @@ public void program_enumTypeReferenceResolution(boolean resolveTypeDependencies)
10191019
Cel cel =
10201020
standardCelBuilderWithMacros()
10211021
.setOptions(
1022-
CelOptions.current().resolveTypeDependencies(resolveTypeDependencies).build())
1022+
CelOptions.current()
1023+
.evaluateCanonicalTypesToNativeValues(true)
1024+
.resolveTypeDependencies(resolveTypeDependencies)
1025+
.build())
10231026
.addMessageTypes(Struct.getDescriptor())
10241027
.setResultType(StructTypeReference.create("google.protobuf.NullValue"))
10251028
.setContainer(CelContainer.ofName("google.protobuf"))
@@ -1037,7 +1040,11 @@ public void program_enumTypeReferenceResolution(boolean resolveTypeDependencies)
10371040
public void program_enumTypeTransitiveResolution() throws Exception {
10381041
Cel cel =
10391042
standardCelBuilderWithMacros()
1040-
.setOptions(CelOptions.current().resolveTypeDependencies(true).build())
1043+
.setOptions(
1044+
CelOptions.current()
1045+
.evaluateCanonicalTypesToNativeValues(true)
1046+
.resolveTypeDependencies(true)
1047+
.build())
10411048
.addMessageTypes(Proto2ExtensionScopedMessage.getDescriptor())
10421049
.setResultType(StructTypeReference.create("google.protobuf.NullValue"))
10431050
.setContainer(CelContainer.ofName("google.protobuf"))
@@ -1654,7 +1661,7 @@ public void programAdvanceEvaluation_unsupportedIndexIgnored() throws Exception
16541661
UnknownContext.create(
16551662
fromMap(
16561663
ImmutableMap.of(
1657-
"unk", ImmutableMap.of(ByteString.copyFromUtf8("a"), false))),
1664+
"unk", ImmutableMap.of(CelByteString.copyFromUtf8("a"), false))),
16581665
ImmutableList.of())))
16591666
.isEqualTo(false);
16601667
}

common/src/main/java/dev/cel/common/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ java_library(
206206
],
207207
deps = [
208208
"//common/internal:proto_time_utils",
209+
"//common/values",
210+
"//common/values:cel_byte_string",
209211
"@maven//:com_google_errorprone_error_prone_annotations",
210212
"@maven//:com_google_guava_guava",
211213
"@maven//:com_google_protobuf_protobuf_java",

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ public enum ProtoUnsetFieldOptions {
109109

110110
public abstract int comprehensionMaxIterations();
111111

112+
public abstract boolean evaluateCanonicalTypesToNativeValues();
113+
112114
public abstract boolean unwrapWellKnownTypesOnFunctionDispatch();
113115

114116
public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption();
@@ -150,6 +152,7 @@ public static Builder newBuilder() {
150152
.enableNamespacedDeclarations(true)
151153
// Evaluation options
152154
.disableCelStandardEquality(true)
155+
.evaluateCanonicalTypesToNativeValues(false)
153156
.enableShortCircuiting(true)
154157
.enableRegexPartialMatch(false)
155158
.enableUnsignedComparisonAndArithmeticIsUnsigned(false)
@@ -450,6 +453,19 @@ public abstract static class Builder {
450453
*/
451454
public abstract Builder comprehensionMaxIterations(int value);
452455

456+
/**
457+
* If set, canonical CEL types such as bytes and CEL null will return their native value
458+
* equivalents instead of protobuf based values. Specifically:
459+
*
460+
* <ul>
461+
* <li>Bytes: {@code dev.cel.common.values.CelByteString} instead of {@code
462+
* com.google.protobuf.ByteString}.
463+
* <li>CEL null: {@code dev.cel.common.values.NullValue} instead of {@code
464+
* com.google.protobuf.NullValue}.
465+
* </ul>
466+
*/
467+
public abstract Builder evaluateCanonicalTypesToNativeValues(boolean value);
468+
453469
/**
454470
* If disabled, CEL runtime will no longer adapt the function dispatch results for protobuf's
455471
* well known types to other types. This option is enabled by default.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.common.base.Joiner;
1919
import com.google.common.primitives.UnsignedLong;
2020
import com.google.errorprone.annotations.Immutable;
21-
import com.google.protobuf.ByteString;
2221
import com.google.protobuf.Duration;
2322
import com.google.protobuf.Empty;
2423
import com.google.protobuf.FieldMask;
@@ -28,6 +27,7 @@
2827
import com.google.protobuf.Timestamp;
2928
import com.google.protobuf.Value;
3029
import dev.cel.common.internal.ProtoTimeUtils;
30+
import dev.cel.common.values.CelByteString;
3131
import java.util.ArrayList;
3232
import java.util.Base64;
3333
import java.util.List;
@@ -71,7 +71,7 @@ public static <K extends String, V> Struct adaptToJsonStructValue(Map<K, V> map)
7171
@SuppressWarnings("unchecked")
7272
public static Value adaptValueToJsonValue(Object value) {
7373
Value.Builder json = Value.newBuilder();
74-
if (value == null || value instanceof NullValue) {
74+
if (value == null || value instanceof dev.cel.common.values.NullValue) {
7575
return json.setNullValue(NullValue.NULL_VALUE).build();
7676
}
7777
if (value instanceof Boolean) {
@@ -93,9 +93,9 @@ public static Value adaptValueToJsonValue(Object value) {
9393
if (value instanceof Float || value instanceof Double) {
9494
return json.setNumberValue(((Number) value).doubleValue()).build();
9595
}
96-
if (value instanceof ByteString) {
96+
if (value instanceof CelByteString) {
9797
return json.setStringValue(
98-
Base64.getEncoder().encodeToString(((ByteString) value).toByteArray()))
98+
Base64.getEncoder().encodeToString(((CelByteString) value).toByteArray()))
9999
.build();
100100
}
101101
if (value instanceof String) {

common/src/main/java/dev/cel/common/ast/BUILD.bazel

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ java_library(
4949
deps = [
5050
"//:auto_value",
5151
"//common/annotations",
52+
"//common/values",
53+
"//common/values:cel_byte_string",
5254
"@maven//:com_google_errorprone_error_prone_annotations",
5355
"@maven//:com_google_guava_guava",
5456
"@maven//:com_google_protobuf_protobuf_java",
@@ -62,9 +64,12 @@ java_library(
6264
],
6365
deps = [
6466
":ast",
67+
"//common/values",
68+
"//common/values:cel_byte_string",
6569
"@cel_spec//proto/cel/expr:checked_java_proto",
6670
"@cel_spec//proto/cel/expr:syntax_java_proto",
6771
"@maven//:com_google_guava_guava",
72+
"@maven//:com_google_protobuf_protobuf_java",
6873
],
6974
)
7075

@@ -75,9 +80,12 @@ cel_android_library(
7580
],
7681
deps = [
7782
":ast_android",
83+
"//common/values:cel_byte_string",
84+
"//common/values:values_android",
7885
"@cel_spec//proto/cel/expr:checked_java_proto_lite",
7986
"@cel_spec//proto/cel/expr:syntax_java_proto_lite",
8087
"@maven_android//:com_google_guava_guava",
88+
"@maven_android//:com_google_protobuf_protobuf_javalite",
8189
],
8290
)
8391

@@ -88,8 +96,11 @@ java_library(
8896
],
8997
deps = [
9098
":ast",
99+
"//common/values",
100+
"//common/values:cel_byte_string",
91101
"@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto",
92102
"@maven//:com_google_guava_guava",
103+
"@maven//:com_google_protobuf_protobuf_java",
93104
],
94105
)
95106

@@ -112,8 +123,8 @@ java_library(
112123
deps = [
113124
":ast",
114125
"//common/annotations",
126+
"//common/values:cel_byte_string",
115127
"@maven//:com_google_guava_guava",
116-
"@maven//:com_google_protobuf_protobuf_java",
117128
],
118129
)
119130

@@ -136,6 +147,8 @@ cel_android_library(
136147
deps = [
137148
"//:auto_value",
138149
"//common/annotations",
150+
"//common/values:cel_byte_string",
151+
"//common/values:values_android",
139152
"@maven//:com_google_errorprone_error_prone_annotations",
140153
"@maven_android//:com_google_guava_guava",
141154
"@maven_android//:com_google_protobuf_protobuf_javalite",

common/src/main/java/dev/cel/common/ast/CelConstant.java

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import com.google.common.collect.ImmutableSet;
2020
import com.google.common.primitives.UnsignedLong;
2121
import com.google.errorprone.annotations.Immutable;
22+
import com.google.errorprone.annotations.InlineMe;
2223
import com.google.protobuf.ByteString;
2324
import com.google.protobuf.Duration;
24-
import com.google.protobuf.NullValue;
2525
import com.google.protobuf.Timestamp;
2626
import dev.cel.common.annotations.Internal;
27+
import dev.cel.common.values.CelByteString;
28+
import dev.cel.common.values.NullValue;
2729

2830
/**
2931
* Represents a primitive literal.
@@ -42,7 +44,7 @@ public abstract class CelConstant {
4244
UnsignedLong.class,
4345
Double.class,
4446
String.class,
45-
ByteString.class);
47+
CelByteString.class);
4648

4749
/** Represents the type of the Constant */
4850
public enum Kind {
@@ -92,7 +94,7 @@ public abstract static class CelConstantNotSet {}
9294

9395
public abstract String stringValue();
9496

95-
public abstract ByteString bytesValue();
97+
public abstract CelByteString bytesValue();
9698

9799
/**
98100
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
@@ -134,10 +136,46 @@ public static CelConstant ofValue(String value) {
134136
return AutoOneOf_CelConstant.stringValue(value);
135137
}
136138

137-
public static CelConstant ofValue(ByteString value) {
139+
public static CelConstant ofValue(CelByteString value) {
138140
return AutoOneOf_CelConstant.bytesValue(value);
139141
}
140142

143+
/**
144+
* @deprecated Use native type equivalent {@link #ofValue(NullValue)} instead.
145+
*/
146+
@InlineMe(
147+
replacement = "CelConstant.ofValue(NullValue.NULL_VALUE)",
148+
imports = {"dev.cel.common.ast.CelConstant", "dev.cel.common.values.NullValue"})
149+
@Deprecated
150+
public static CelConstant ofValue(com.google.protobuf.NullValue unused) {
151+
return ofValue(NullValue.NULL_VALUE);
152+
}
153+
154+
/**
155+
* @deprecated Use native type equivalent {@link #ofValue(CelByteString)} instead.
156+
*/
157+
@Deprecated
158+
public static CelConstant ofValue(ByteString value) {
159+
CelByteString celByteString = CelByteString.of(value.toByteArray());
160+
return ofValue(celByteString);
161+
}
162+
163+
/**
164+
* @deprecated Do not use. Duration is no longer built-in CEL type.
165+
*/
166+
@Deprecated
167+
public static CelConstant ofValue(Duration value) {
168+
return AutoOneOf_CelConstant.durationValue(value);
169+
}
170+
171+
/**
172+
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
173+
*/
174+
@Deprecated
175+
public static CelConstant ofValue(Timestamp value) {
176+
return AutoOneOf_CelConstant.timestampValue(value);
177+
}
178+
141179
/** Checks whether the provided Java object is a valid CelConstant value. */
142180
public static boolean isConstantValue(Object value) {
143181
return CONSTANT_CLASSES.contains(value.getClass());
@@ -163,26 +201,10 @@ public static CelConstant ofObjectValue(Object value) {
163201
return ofValue((double) value);
164202
} else if (value instanceof String) {
165203
return ofValue((String) value);
166-
} else if (value instanceof ByteString) {
167-
return ofValue((ByteString) value);
204+
} else if (value instanceof CelByteString) {
205+
return ofValue((CelByteString) value);
168206
}
169207

170208
throw new IllegalArgumentException("Value is not a CelConstant: " + value);
171209
}
172-
173-
/**
174-
* @deprecated Do not use. Duration is no longer built-in CEL type.
175-
*/
176-
@Deprecated
177-
public static CelConstant ofValue(Duration value) {
178-
return AutoOneOf_CelConstant.durationValue(value);
179-
}
180-
181-
/**
182-
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
183-
*/
184-
@Deprecated
185-
public static CelConstant ofValue(Timestamp value) {
186-
return AutoOneOf_CelConstant.timestampValue(value);
187-
}
188210
}

common/src/main/java/dev/cel/common/ast/CelExprConverter.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import com.google.common.collect.ImmutableList;
3131
import com.google.common.collect.ImmutableMap;
3232
import com.google.common.primitives.UnsignedLong;
33+
import com.google.protobuf.ByteString;
34+
import dev.cel.common.values.CelByteString;
35+
import dev.cel.common.values.NullValue;
3336
import java.util.Map;
3437
import java.util.Optional;
3538

@@ -179,7 +182,7 @@ public static CelConstant exprConstantToCelConstant(Constant constExpr) {
179182
case CONSTANTKIND_NOT_SET:
180183
return CelConstant.ofNotSet();
181184
case NULL_VALUE:
182-
return CelConstant.ofValue(constExpr.getNullValue());
185+
return CelConstant.ofValue(NullValue.NULL_VALUE);
183186
case BOOL_VALUE:
184187
return CelConstant.ofValue(constExpr.getBoolValue());
185188
case INT64_VALUE:
@@ -191,7 +194,8 @@ public static CelConstant exprConstantToCelConstant(Constant constExpr) {
191194
case STRING_VALUE:
192195
return CelConstant.ofValue(constExpr.getStringValue());
193196
case BYTES_VALUE:
194-
return CelConstant.ofValue(constExpr.getBytesValue());
197+
ByteString bytesValue = constExpr.getBytesValue();
198+
return CelConstant.ofValue(CelByteString.of(bytesValue.toByteArray()));
195199
case DURATION_VALUE:
196200
return CelConstant.ofValue(constExpr.getDurationValue());
197201
case TIMESTAMP_VALUE:
@@ -250,7 +254,7 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) {
250254
case NOT_SET:
251255
return Constant.getDefaultInstance();
252256
case NULL_VALUE:
253-
return Constant.newBuilder().setNullValue(celConstant.nullValue()).build();
257+
return Constant.newBuilder().setNullValue(com.google.protobuf.NullValue.NULL_VALUE).build();
254258
case BOOLEAN_VALUE:
255259
return Constant.newBuilder().setBoolValue(celConstant.booleanValue()).build();
256260
case INT64_VALUE:
@@ -262,7 +266,10 @@ public static Constant celConstantToExprConstant(CelConstant celConstant) {
262266
case STRING_VALUE:
263267
return Constant.newBuilder().setStringValue(celConstant.stringValue()).build();
264268
case BYTES_VALUE:
265-
return Constant.newBuilder().setBytesValue(celConstant.bytesValue()).build();
269+
CelByteString celByteString = celConstant.bytesValue();
270+
return Constant.newBuilder()
271+
.setBytesValue(ByteString.copyFrom(celByteString.toByteArray()))
272+
.build();
266273
case DURATION_VALUE:
267274
return Constant.newBuilder().setDurationValue(celConstant.durationValue()).build();
268275
case TIMESTAMP_VALUE:

0 commit comments

Comments
 (0)