Skip to content

Commit 4c0c0e8

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

67 files changed

Lines changed: 463 additions & 219 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: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ 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",
57+
"@maven_android//:com_google_protobuf_protobuf_javalite",
5558
],
5659
)
5760

@@ -62,9 +65,12 @@ java_library(
6265
],
6366
deps = [
6467
":ast",
68+
"//common/values",
69+
"//common/values:cel_byte_string",
6570
"@cel_spec//proto/cel/expr:checked_java_proto",
6671
"@cel_spec//proto/cel/expr:syntax_java_proto",
6772
"@maven//:com_google_guava_guava",
73+
"@maven//:com_google_protobuf_protobuf_java",
6874
],
6975
)
7076

@@ -75,9 +81,12 @@ cel_android_library(
7581
],
7682
deps = [
7783
":ast_android",
84+
"//common/values:cel_byte_string",
85+
"//common/values:values_android",
7886
"@cel_spec//proto/cel/expr:checked_java_proto_lite",
7987
"@cel_spec//proto/cel/expr:syntax_java_proto_lite",
8088
"@maven_android//:com_google_guava_guava",
89+
"@maven_android//:com_google_protobuf_protobuf_javalite",
8190
],
8291
)
8392

@@ -88,8 +97,11 @@ java_library(
8897
],
8998
deps = [
9099
":ast",
100+
"//common/values",
101+
"//common/values:cel_byte_string",
91102
"@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto",
92103
"@maven//:com_google_guava_guava",
104+
"@maven//:com_google_protobuf_protobuf_java",
93105
],
94106
)
95107

@@ -112,8 +124,8 @@ java_library(
112124
deps = [
113125
":ast",
114126
"//common/annotations",
127+
"//common/values:cel_byte_string",
115128
"@maven//:com_google_guava_guava",
116-
"@maven//:com_google_protobuf_protobuf_java",
117129
],
118130
)
119131

@@ -136,6 +148,8 @@ cel_android_library(
136148
deps = [
137149
"//:auto_value",
138150
"//common/annotations",
151+
"//common/values:cel_byte_string",
152+
"//common/values:values_android",
139153
"@maven//:com_google_errorprone_error_prone_annotations",
140154
"@maven_android//:com_google_guava_guava",
141155
"@maven_android//:com_google_protobuf_protobuf_javalite",

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

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
import com.google.errorprone.annotations.Immutable;
2222
import com.google.protobuf.ByteString;
2323
import com.google.protobuf.Duration;
24-
import com.google.protobuf.NullValue;
2524
import com.google.protobuf.Timestamp;
2625
import dev.cel.common.annotations.Internal;
26+
import dev.cel.common.values.CelByteString;
27+
import dev.cel.common.values.NullValue;
2728

2829
/**
2930
* Represents a primitive literal.
@@ -42,7 +43,7 @@ public abstract class CelConstant {
4243
UnsignedLong.class,
4344
Double.class,
4445
String.class,
45-
ByteString.class);
46+
CelByteString.class);
4647

4748
/** Represents the type of the Constant */
4849
public enum Kind {
@@ -92,7 +93,7 @@ public abstract static class CelConstantNotSet {}
9293

9394
public abstract String stringValue();
9495

95-
public abstract ByteString bytesValue();
96+
public abstract CelByteString bytesValue();
9697

9798
/**
9899
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
@@ -134,10 +135,43 @@ public static CelConstant ofValue(String value) {
134135
return AutoOneOf_CelConstant.stringValue(value);
135136
}
136137

137-
public static CelConstant ofValue(ByteString value) {
138+
public static CelConstant ofValue(CelByteString value) {
138139
return AutoOneOf_CelConstant.bytesValue(value);
139140
}
140141

142+
/**
143+
* @deprecated Use native type equivalent {@link #ofValue(NullValue)} instead.
144+
*/
145+
@Deprecated
146+
public static CelConstant ofValue(com.google.protobuf.NullValue unused) {
147+
return ofValue(NullValue.NULL_VALUE);
148+
}
149+
150+
/**
151+
* @deprecated Use native type equivalent {@link #ofValue(CelByteString)} instead.
152+
*/
153+
@Deprecated
154+
public static CelConstant ofValue(ByteString value) {
155+
CelByteString celByteString = CelByteString.of(value.toByteArray());
156+
return ofValue(celByteString);
157+
}
158+
159+
/**
160+
* @deprecated Do not use. Duration is no longer built-in CEL type.
161+
*/
162+
@Deprecated
163+
public static CelConstant ofValue(Duration value) {
164+
return AutoOneOf_CelConstant.durationValue(value);
165+
}
166+
167+
/**
168+
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
169+
*/
170+
@Deprecated
171+
public static CelConstant ofValue(Timestamp value) {
172+
return AutoOneOf_CelConstant.timestampValue(value);
173+
}
174+
141175
/** Checks whether the provided Java object is a valid CelConstant value. */
142176
public static boolean isConstantValue(Object value) {
143177
return CONSTANT_CLASSES.contains(value.getClass());
@@ -163,26 +197,10 @@ public static CelConstant ofObjectValue(Object value) {
163197
return ofValue((double) value);
164198
} else if (value instanceof String) {
165199
return ofValue((String) value);
166-
} else if (value instanceof ByteString) {
167-
return ofValue((ByteString) value);
200+
} else if (value instanceof CelByteString) {
201+
return ofValue((CelByteString) value);
168202
}
169203

170204
throw new IllegalArgumentException("Value is not a CelConstant: " + value);
171205
}
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-
}
188206
}

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)