Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ java_library(
"//common/types:cel_proto_types",
"//common/types:message_type_provider",
"//common/types:type_providers",
"//common/values",
"//common/values:cel_byte_string",
"//compiler",
"//compiler:compiler_builder",
"//extensions",
Expand All @@ -64,7 +66,6 @@ java_library(
"@maven//:com_google_truth_extensions_truth_proto_extension",
"@maven//:junit_junit",
"@maven//:org_jspecify_jspecify",
"@maven_android//:com_google_protobuf_protobuf_javalite",
],
)

Expand Down
40 changes: 35 additions & 5 deletions bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import com.google.protobuf.Empty;
import com.google.protobuf.FieldMask;
import com.google.protobuf.Message;
import com.google.protobuf.NullValue;
import com.google.protobuf.Struct;
import com.google.protobuf.TextFormat;
import com.google.protobuf.Timestamp;
Expand Down Expand Up @@ -86,6 +85,8 @@
import dev.cel.common.types.ProtoMessageTypeProvider;
import dev.cel.common.types.SimpleType;
import dev.cel.common.types.StructTypeReference;
import dev.cel.common.values.CelByteString;
import dev.cel.common.values.NullValue;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerFactory;
import dev.cel.compiler.CelCompilerImpl;
Expand All @@ -108,6 +109,7 @@
import dev.cel.runtime.UnknownContext;
import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -1019,7 +1021,10 @@ public void program_enumTypeReferenceResolution(boolean resolveTypeDependencies)
Cel cel =
standardCelBuilderWithMacros()
.setOptions(
CelOptions.current().resolveTypeDependencies(resolveTypeDependencies).build())
CelOptions.current()
.evaluateCanonicalTypesToNativeValues(true)
.resolveTypeDependencies(resolveTypeDependencies)
.build())
.addMessageTypes(Struct.getDescriptor())
.setResultType(StructTypeReference.create("google.protobuf.NullValue"))
.setContainer(CelContainer.ofName("google.protobuf"))
Expand All @@ -1037,7 +1042,11 @@ public void program_enumTypeReferenceResolution(boolean resolveTypeDependencies)
public void program_enumTypeTransitiveResolution() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(CelOptions.current().resolveTypeDependencies(true).build())
.setOptions(
CelOptions.current()
.evaluateCanonicalTypesToNativeValues(true)
.resolveTypeDependencies(true)
.build())
.addMessageTypes(Proto2ExtensionScopedMessage.getDescriptor())
.setResultType(StructTypeReference.create("google.protobuf.NullValue"))
.setContainer(CelContainer.ofName("google.protobuf"))
Expand Down Expand Up @@ -1626,7 +1635,11 @@ public void programAdvanceEvaluation_indexOnUnknownContainer() throws Exception
public void programAdvanceEvaluation_unsupportedIndexIgnored() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(CelOptions.current().enableUnknownTracking(true).build())
.setOptions(
CelOptions.current()
.evaluateCanonicalTypesToNativeValues(true)
.enableUnknownTracking(true)
.build())
.addVar("unk", MapType.create(SimpleType.STRING, SimpleType.BOOL))
.setContainer(CelContainer.ofName(""))
.addFunctionBindings()
Expand Down Expand Up @@ -1654,7 +1667,7 @@ public void programAdvanceEvaluation_unsupportedIndexIgnored() throws Exception
UnknownContext.create(
fromMap(
ImmutableMap.of(
"unk", ImmutableMap.of(ByteString.copyFromUtf8("a"), false))),
"unk", ImmutableMap.of(CelByteString.copyFromUtf8("a"), false))),
ImmutableList.of())))
.isEqualTo(false);
}
Expand Down Expand Up @@ -2077,6 +2090,23 @@ public void program_regexProgramSizeExceedsLimit_throws() throws Exception {
assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.INVALID_ARGUMENT);
}

@Test
@SuppressWarnings("unchecked") // test only
public void program_evaluateCanonicalTypesToNativeTypesDisabled_producesProtoValues()
throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(CelOptions.current().evaluateCanonicalTypesToNativeValues(false).build())
.build();
CelAbstractSyntaxTree ast = cel.compile("[null, {b'abc': null}]").getAst();
Map<ByteString, Object> expectedNestedMap = new LinkedHashMap<>();
expectedNestedMap.put(ByteString.copyFromUtf8("abc"), com.google.protobuf.NullValue.NULL_VALUE);

List<Object> result = (List<Object>) cel.createProgram(ast).eval();

assertThat(result).containsExactly(com.google.protobuf.NullValue.NULL_VALUE, expectedNestedMap);
}

@Test
public void toBuilder_isImmutable() {
CelBuilder celBuilder = CelFactory.standardCelBuilder();
Expand Down
2 changes: 2 additions & 0 deletions common/src/main/java/dev/cel/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ java_library(
],
deps = [
"//common/internal:proto_time_utils",
"//common/values",
"//common/values:cel_byte_string",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
Expand Down
16 changes: 16 additions & 0 deletions common/src/main/java/dev/cel/common/CelOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public enum ProtoUnsetFieldOptions {

public abstract int comprehensionMaxIterations();

public abstract boolean evaluateCanonicalTypesToNativeValues();

public abstract boolean unwrapWellKnownTypesOnFunctionDispatch();

public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption();
Expand Down Expand Up @@ -150,6 +152,7 @@ public static Builder newBuilder() {
.enableNamespacedDeclarations(true)
// Evaluation options
.disableCelStandardEquality(true)
.evaluateCanonicalTypesToNativeValues(false)
.enableShortCircuiting(true)
.enableRegexPartialMatch(false)
.enableUnsignedComparisonAndArithmeticIsUnsigned(false)
Expand Down Expand Up @@ -450,6 +453,19 @@ public abstract static class Builder {
*/
public abstract Builder comprehensionMaxIterations(int value);

/**
* If set, canonical CEL types such as bytes and CEL null will return their native value
* equivalents instead of protobuf based values. Specifically:
*
* <ul>
* <li>Bytes: {@code dev.cel.common.values.CelByteString} instead of {@code
* com.google.protobuf.ByteString}.
* <li>CEL null: {@code dev.cel.common.values.NullValue} instead of {@code
* com.google.protobuf.NullValue}.
* </ul>
*/
public abstract Builder evaluateCanonicalTypesToNativeValues(boolean value);

/**
* If disabled, CEL runtime will no longer adapt the function dispatch results for protobuf's
* well known types to other types. This option is enabled by default.
Expand Down
8 changes: 4 additions & 4 deletions common/src/main/java/dev/cel/common/CelProtoJsonAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import com.google.common.base.Joiner;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.ByteString;
import com.google.protobuf.Duration;
import com.google.protobuf.Empty;
import com.google.protobuf.FieldMask;
Expand All @@ -28,6 +27,7 @@
import com.google.protobuf.Timestamp;
import com.google.protobuf.Value;
import dev.cel.common.internal.ProtoTimeUtils;
import dev.cel.common.values.CelByteString;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
Expand Down Expand Up @@ -71,7 +71,7 @@ public static <K extends String, V> Struct adaptToJsonStructValue(Map<K, V> map)
@SuppressWarnings("unchecked")
public static Value adaptValueToJsonValue(Object value) {
Value.Builder json = Value.newBuilder();
if (value == null || value instanceof NullValue) {
if (value == null || value instanceof dev.cel.common.values.NullValue) {
return json.setNullValue(NullValue.NULL_VALUE).build();
}
if (value instanceof Boolean) {
Expand All @@ -93,9 +93,9 @@ public static Value adaptValueToJsonValue(Object value) {
if (value instanceof Float || value instanceof Double) {
return json.setNumberValue(((Number) value).doubleValue()).build();
}
if (value instanceof ByteString) {
if (value instanceof CelByteString) {
return json.setStringValue(
Base64.getEncoder().encodeToString(((ByteString) value).toByteArray()))
Base64.getEncoder().encodeToString(((CelByteString) value).toByteArray()))
.build();
}
if (value instanceof String) {
Expand Down
15 changes: 14 additions & 1 deletion common/src/main/java/dev/cel/common/ast/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ java_library(
deps = [
"//:auto_value",
"//common/annotations",
"//common/values",
"//common/values:cel_byte_string",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
Expand All @@ -62,9 +64,12 @@ java_library(
],
deps = [
":ast",
"//common/values",
"//common/values:cel_byte_string",
"@cel_spec//proto/cel/expr:checked_java_proto",
"@cel_spec//proto/cel/expr:syntax_java_proto",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
],
)

Expand All @@ -75,9 +80,12 @@ cel_android_library(
],
deps = [
":ast_android",
"//common/values:cel_byte_string",
"//common/values:values_android",
"@cel_spec//proto/cel/expr:checked_java_proto_lite",
"@cel_spec//proto/cel/expr:syntax_java_proto_lite",
"@maven_android//:com_google_guava_guava",
"@maven_android//:com_google_protobuf_protobuf_javalite",
],
)

Expand All @@ -88,8 +96,11 @@ java_library(
],
deps = [
":ast",
"//common/values",
"//common/values:cel_byte_string",
"@com_google_googleapis//google/api/expr/v1alpha1:expr_java_proto",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
],
)

Expand All @@ -112,8 +123,8 @@ java_library(
deps = [
":ast",
"//common/annotations",
"//common/values:cel_byte_string",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
],
)

Expand All @@ -136,6 +147,8 @@ cel_android_library(
deps = [
"//:auto_value",
"//common/annotations",
"//common/values:cel_byte_string",
"//common/values:values_android",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
"@maven_android//:com_google_protobuf_protobuf_javalite",
Expand Down
66 changes: 44 additions & 22 deletions common/src/main/java/dev/cel/common/ast/CelConstant.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.annotations.InlineMe;
import com.google.protobuf.ByteString;
import com.google.protobuf.Duration;
import com.google.protobuf.NullValue;
import com.google.protobuf.Timestamp;
import dev.cel.common.annotations.Internal;
import dev.cel.common.values.CelByteString;
import dev.cel.common.values.NullValue;

/**
* Represents a primitive literal.
Expand All @@ -42,7 +44,7 @@ public abstract class CelConstant {
UnsignedLong.class,
Double.class,
String.class,
ByteString.class);
CelByteString.class);

/** Represents the type of the Constant */
public enum Kind {
Expand Down Expand Up @@ -92,7 +94,7 @@ public abstract static class CelConstantNotSet {}

public abstract String stringValue();

public abstract ByteString bytesValue();
public abstract CelByteString bytesValue();

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

public static CelConstant ofValue(ByteString value) {
public static CelConstant ofValue(CelByteString value) {
return AutoOneOf_CelConstant.bytesValue(value);
}

/**
* @deprecated Use native type equivalent {@link #ofValue(NullValue)} instead.
*/
@InlineMe(
replacement = "CelConstant.ofValue(NullValue.NULL_VALUE)",
imports = {"dev.cel.common.ast.CelConstant", "dev.cel.common.values.NullValue"})
@Deprecated
public static CelConstant ofValue(com.google.protobuf.NullValue unused) {
return ofValue(NullValue.NULL_VALUE);
}

/**
* @deprecated Use native type equivalent {@link #ofValue(CelByteString)} instead.
*/
@Deprecated
public static CelConstant ofValue(ByteString value) {
CelByteString celByteString = CelByteString.of(value.toByteArray());
return ofValue(celByteString);
}

/**
* @deprecated Do not use. Duration is no longer built-in CEL type.
*/
@Deprecated
public static CelConstant ofValue(Duration value) {
return AutoOneOf_CelConstant.durationValue(value);
}

/**
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
*/
@Deprecated
public static CelConstant ofValue(Timestamp value) {
return AutoOneOf_CelConstant.timestampValue(value);
}

/** Checks whether the provided Java object is a valid CelConstant value. */
public static boolean isConstantValue(Object value) {
return CONSTANT_CLASSES.contains(value.getClass());
Expand All @@ -163,26 +201,10 @@ public static CelConstant ofObjectValue(Object value) {
return ofValue((double) value);
} else if (value instanceof String) {
return ofValue((String) value);
} else if (value instanceof ByteString) {
return ofValue((ByteString) value);
} else if (value instanceof CelByteString) {
return ofValue((CelByteString) value);
}

throw new IllegalArgumentException("Value is not a CelConstant: " + value);
}

/**
* @deprecated Do not use. Duration is no longer built-in CEL type.
*/
@Deprecated
public static CelConstant ofValue(Duration value) {
return AutoOneOf_CelConstant.durationValue(value);
}

/**
* @deprecated Do not use. Timestamp is no longer built-in CEL type.
*/
@Deprecated
public static CelConstant ofValue(Timestamp value) {
return AutoOneOf_CelConstant.timestampValue(value);
}
}
Loading
Loading