Skip to content

Commit e80c3ca

Browse files
l46kokcopybara-github
authored andcommitted
Harden cel.@Attribute type identifiers and leaf validation across producers.
PiperOrigin-RevId: 989888489
1 parent 83507f7 commit e80c3ca

4 files changed

Lines changed: 89 additions & 0 deletions

File tree

‎optimizer/src/test/java/dev/cel/optimizer/optimizers/SelectOptimizerTest.java‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@
2626
import com.google.common.collect.ImmutableList;
2727
import com.google.common.collect.ImmutableMap;
2828
import com.google.common.primitives.UnsignedLong;
29+
import com.google.protobuf.Any;
2930
import com.google.protobuf.Descriptors.Descriptor;
3031
import com.google.protobuf.Descriptors.FileDescriptor;
32+
import com.google.protobuf.Int64Value;
33+
import com.google.protobuf.Struct;
3134
import com.google.protobuf.TextFormat;
35+
import com.google.protobuf.Value;
3236
import com.google.testing.junit.testparameterinjector.TestParameter;
3337
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
3438
import dev.cel.bundle.Cel;
@@ -592,6 +596,38 @@ private enum NativeSelectEvaluationTestCase {
592596
"msg.single_timestamp",
593597
ImmutableMap.of("msg", TestAllTypes.getDefaultInstance()),
594598
Instant.EPOCH),
599+
PROTO3_MAP_OF_ANY_UNPACKS_VALUE(
600+
"msg.map_string_any['k']",
601+
ImmutableMap.of(
602+
"msg",
603+
TestAllTypes.newBuilder().putMapStringAny("k", Any.pack(Int64Value.of(5))).build()),
604+
5L),
605+
PROTO3_MAP_OF_WRAPPER_UNWRAPS_MAP_VALUES(
606+
"msg.map_string_int64_wrapper",
607+
ImmutableMap.of(
608+
"msg",
609+
TestAllTypes.newBuilder().putMapStringInt64Wrapper("k", Int64Value.of(5)).build()),
610+
ImmutableMap.of("k", 5L)),
611+
PROTO3_MAP_OF_VALUE_CONVERTS_TO_JSON(
612+
"msg.map_string_value['k']",
613+
ImmutableMap.of(
614+
"msg",
615+
TestAllTypes.newBuilder()
616+
.putMapStringValue("k", Value.newBuilder().setNumberValue(1.5).build())
617+
.build()),
618+
1.5),
619+
PROTO3_MAP_OF_STRUCT_CONVERTS_TO_MAP(
620+
"msg.map_string_struct['k'].a",
621+
ImmutableMap.of(
622+
"msg",
623+
TestAllTypes.newBuilder()
624+
.putMapStringStruct(
625+
"k",
626+
Struct.newBuilder()
627+
.putFields("a", Value.newBuilder().setNumberValue(1.5).build())
628+
.build())
629+
.build()),
630+
1.5),
595631
DEEPLY_NESTED_PROTO2_MESSAGE_POPULATED(
596632
"nested_msg.child.payload.single_int64",
597633
ImmutableMap.of("nested_msg", newNestedTestAllTypes(999L)),

‎runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ java_library(
533533
":planner_helpers",
534534
"//common/ast",
535535
"//common/types",
536+
"//common/types:cel_types",
536537
"//common/types:type_providers",
537538
"//common/values",
538539
"//common/values:cel_byte_string",
@@ -1178,6 +1179,7 @@ cel_android_library(
11781179
":planned_interpretable_android",
11791180
":planner_helpers_android",
11801181
"//common/ast:ast_android",
1182+
"//common/types:cel_types_android",
11811183
"//common/types:type_providers_android",
11821184
"//common/types:types_android",
11831185
"//common/values:cel_byte_string",

‎runtime/src/main/java/dev/cel/runtime/planner/OptimizedSelectPlanner.java‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020
import com.google.common.collect.ImmutableList;
2121
import com.google.common.collect.ImmutableMap;
22+
import com.google.common.collect.ImmutableSet;
2223
import com.google.common.primitives.UnsignedLong;
2324
import com.google.errorprone.annotations.Immutable;
2425
import dev.cel.common.ast.CelConstant;
2526
import dev.cel.common.ast.CelExpr;
2627
import dev.cel.common.ast.CelExpr.CelCall;
2728
import dev.cel.common.ast.CelExpr.ExprKind.Kind;
2829
import dev.cel.common.types.CelType;
30+
import dev.cel.common.types.CelTypes;
2931
import dev.cel.common.types.SimpleType;
3032
import dev.cel.common.values.CelByteString;
3133
import dev.cel.common.values.CelValueConverter;
@@ -56,6 +58,18 @@ final class OptimizedSelectPlanner {
5658
private static final String DURATION_TYPE_IDENT = SimpleType.DURATION.name();
5759
private static final String TIMESTAMP_TYPE_IDENT = SimpleType.TIMESTAMP.name();
5860

61+
/**
62+
* Well-known message types whose CEL semantics (Any unpacking, JSON value conversion) are not
63+
* implemented by the optimized traversal. Wrapper types are rejected via {@link
64+
* CelTypes#isWrapperType}.
65+
*/
66+
private static final ImmutableSet<String> UNSUPPORTED_WELL_KNOWN_TYPE_IDENTS =
67+
ImmutableSet.of(
68+
CelTypes.ANY_MESSAGE,
69+
CelTypes.STRUCT_MESSAGE,
70+
CelTypes.VALUE_MESSAGE,
71+
CelTypes.LIST_VALUE_MESSAGE);
72+
5973
private final AttributeFactory attributeFactory;
6074
private final CelValueConverter celValueConverter;
6175

@@ -228,6 +242,11 @@ private static void validateLeafTypeIdent(
228242
!ScalarType.isScalarTypeIdent(typeIdent),
229243
"Leaf MESSAGE type code (11) is incompatible with scalar typeIdent '%s'",
230244
typeIdent);
245+
checkArgument(
246+
!CelTypes.isWrapperType(typeIdent)
247+
&& !UNSUPPORTED_WELL_KNOWN_TYPE_IDENTS.contains(typeIdent),
248+
"Leaf well-known type '%s' is not supported by the select-optimized runtime",
249+
typeIdent);
231250
if (typeIdent.equals(DURATION_TYPE_IDENT)) {
232251
checkArgument(
233252
Objects.equals(defaultValue, Duration.ZERO),

‎runtime/src/test/java/dev/cel/runtime/planner/OptimizedSelectPlannerTest.java‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,38 @@ public void plan_invalidAst_messageTypeCodeWithScalarTypeIdent_throwsEvaluationE
535535
.contains("Leaf MESSAGE type code (11) is incompatible with scalar typeIdent 'int'");
536536
}
537537

538+
@Test
539+
public void plan_invalidAst_unsupportedWellKnownType_throwsEvaluationException() {
540+
CelAbstractSyntaxTree ast =
541+
CelAbstractSyntaxTree.newParsedAst(
542+
CelExpr.ofCall(
543+
1L,
544+
OptimizedSelectPlanner.CEL_ATTRIBUTE_FUNCTION_NAME,
545+
ImmutableList.of(
546+
CelExpr.ofIdent(2L, "msg"),
547+
CelExpr.ofList(
548+
3L,
549+
ImmutableList.of(
550+
CelExpr.ofList(
551+
4L,
552+
ImmutableList.of(
553+
CelExpr.ofConstant(5L, CelConstant.ofValue(105L)),
554+
CelExpr.ofConstant(
555+
6L, CelConstant.ofValue("single_int64_wrapper")),
556+
CelExpr.ofConstant(7L, CelConstant.ofValue(11L))),
557+
ImmutableList.of())),
558+
ImmutableList.of()),
559+
CelExpr.ofIdent(8L, "google.protobuf.Int64Value"))),
560+
CelSource.newBuilder().build());
561+
562+
CelEvaluationException e = assertThrows(CelEvaluationException.class, () -> PLANNER.plan(ast));
563+
564+
assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
565+
assertThat(e)
566+
.hasMessageThat()
567+
.contains("Leaf well-known type 'google.protobuf.Int64Value' is not supported");
568+
}
569+
538570
private static CelAbstractSyntaxTree optimizeSelectAst(String expression) throws Exception {
539571
CelAbstractSyntaxTree ast = CEL.compile(expression).getAst();
540572
CelAbstractSyntaxTree optimizedAst = SELECT_OPTIMIZER.optimize(ast);

0 commit comments

Comments
 (0)