From b25941b58f3926e278da549f157a05e3277eb4d7 Mon Sep 17 00:00:00 2001 From: CEL Dev Team Date: Tue, 25 Aug 2026 23:43:48 -0700 Subject: [PATCH] this is not a CEL CL. PiperOrigin-RevId: 971054056 --- tools/proto_to_predicate.cc | 32 +++++++++++++++--- tools/proto_to_predicate_test.cc | 57 ++++++++++++++++++++++++++++++++ tools/testdata/BUILD | 1 + tools/testdata/test_policy.proto | 20 +++++++++++ 4 files changed, 106 insertions(+), 4 deletions(-) diff --git a/tools/proto_to_predicate.cc b/tools/proto_to_predicate.cc index 8c89ee2f0..926982d98 100644 --- a/tools/proto_to_predicate.cc +++ b/tools/proto_to_predicate.cc @@ -246,7 +246,13 @@ class ProtoToPredicateBuilder final : private ExprFactory { const FieldDescriptor* const value_field = field->message_type()->FindFieldByName("value"); - Expr map_path = NewSelect(NextId(), base_expr, field->name()); + std::string match_path_val = GetMatchPath(field); + Expr map_path; + if (!match_path_val.empty()) { + map_path = ParseAndBuildPath(match_path_val); + } else { + map_path = NewSelect(NextId(), base_expr, field->name()); + } struct MapEntry { const Message* message; @@ -355,7 +361,13 @@ class ProtoToPredicateBuilder final : private ExprFactory { const Message& sub_message = reflection->GetRepeatedMessage(message, field, i); std::vector sub_predicates; - Expr sub_base = NewSelect(NextId(), base_expr, field->name()); + std::string match_path_val = GetMatchPath(field); + Expr sub_base; + if (!match_path_val.empty()) { + sub_base = ParseAndBuildPath(match_path_val); + } else { + sub_base = NewSelect(NextId(), base_expr, field->name()); + } CEL_RETURN_IF_ERROR(Walk(sub_message, sub_base, sub_predicates)); message_asts.push_back(LogicalAnd(sub_predicates)); } @@ -426,11 +438,23 @@ class ProtoToPredicateBuilder final : private ExprFactory { } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { const Message& sub_message = reflection->GetMessage(message, field); - Expr field_path = NewSelect(NextId(), base_expr, field->name()); + std::string match_path_val = GetMatchPath(field); + Expr field_path; + if (!match_path_val.empty()) { + field_path = ParseAndBuildPath(match_path_val); + } else { + field_path = NewSelect(NextId(), base_expr, field->name()); + } CEL_RETURN_IF_ERROR(Walk(sub_message, field_path, predicates)); } else { // Primitive field: base_expr.field == - Expr field_path = NewSelect(NextId(), base_expr, field->name()); + std::string match_path_val = GetMatchPath(field); + Expr field_path; + if (!match_path_val.empty()) { + field_path = ParseAndBuildPath(match_path_val); + } else { + field_path = NewSelect(NextId(), base_expr, field->name()); + } predicates.push_back( ConstructEquality(std::move(field_path), PrimitiveToExpr(message, reflection, field))); diff --git a/tools/proto_to_predicate_test.cc b/tools/proto_to_predicate_test.cc index 80ad140c7..cba6293c0 100644 --- a/tools/proto_to_predicate_test.cc +++ b/tools/proto_to_predicate_test.cc @@ -549,6 +549,63 @@ INSTANTIATE_TEST_SUITE_P( .json_input = R"({ "destinations": [ { "tool": { } } ] })", .expected_unparsed = "true", }, + PolicyTestCase{ + .name = "AnnotatedSingularFieldInMessage", + .json_input = + R"({ "destinations": [ { + "agent": { + "id": "agent-007", + "location": "us-central1" + } + } ] })", + .expected_unparsed = "dest.agent.name == \"agent-007\" && " + "custom.agent.location == \"us-central1\"", + }, + PolicyTestCase{ + .name = "AnnotatedOneofPrimitiveField", + .json_input = + R"({ "destinations": [ { + "ip": "192.168.1.1" + } ] })", + .expected_unparsed = "custom.ip == \"192.168.1.1\"", + }, + PolicyTestCase{ + .name = "AnnotatedMapFieldPrimitive", + .json_input = + R"({ "destinations": [ { + "tool": { + "annotated_labels": { + "cluster": "us-central1" + } + } + } ] })", + .expected_unparsed = + "\"cluster\" in custom.labels && " + "custom.labels[\"cluster\"] == \"us-central1\"", + }, + PolicyTestCase{ + .name = "AnnotatedMapFieldMessage", + .json_input = + R"({ "destinations": [ { + "tool": { + "annotated_role_members": { + "admin": { + "all_users": true, + "principals": ["alice_user"], + "leader": "alice", + "leaders": ["bob"] + } + } + } + } ] })", + .expected_unparsed = + "\"admin\" in custom.role_members && " + "\"alice_user\" in custom.role_members[\"admin\"].principals " + "&& " + "custom.role_members[\"admin\"].all_users == true && " + "custom.member.leader == \"alice\" && " + "custom.member.leaders in [\"bob\"]", + }, PolicyTestCase{ .name = "MapEquality", .json_input = diff --git a/tools/testdata/BUILD b/tools/testdata/BUILD index f9d8ea4b9..a0d26f490 100644 --- a/tools/testdata/BUILD +++ b/tools/testdata/BUILD @@ -32,6 +32,7 @@ proto_library( name = "test_policy_proto", srcs = ["test_policy.proto"], visibility = ["//tools:__subpackages__"], + deps = ["@com_google_protobuf//:protobuf"], ) cc_proto_library( diff --git a/tools/testdata/test_policy.proto b/tools/testdata/test_policy.proto index b5d424c04..f5812dc34 100644 --- a/tools/testdata/test_policy.proto +++ b/tools/testdata/test_policy.proto @@ -19,11 +19,18 @@ edition = "2023"; package cel.cpp.tools; +import "net/proto2/proto/descriptor.proto"; + option cc_enable_arenas = true; +extend proto2.FieldOptions { + string match_path = 51074; +} + // Represents the targeted client agent. message Agent { string name = 1 [json_name = "id"]; + string location = 2 [(match_path) = "custom.agent.location"]; } // Specifies additional metadata tool annotations. @@ -40,6 +47,10 @@ message Members { bool all_users = 3; bool all_authenticated_users = 4; + + string leader = 5 [(match_path) = "custom.member.leader"]; + + repeated string leaders = 6 [(match_path) = "custom.member.leaders"]; } // Represents a metadata tool block. @@ -56,6 +67,14 @@ message Tool { // A map with string keys representing roles and Member instances as values. map role_members = 4; + + // A map with string keys representing roles and Member instances as values, + // annotated with a match_path. + map annotated_role_members = 5 + [(match_path) = "custom.role_members"]; + + // A string-to-string map, annotated with a match_path. + map annotated_labels = 6 [(match_path) = "custom.labels"]; } // Represents a policy mapping destination block. @@ -63,6 +82,7 @@ message Target { oneof kind { Agent agent = 1; Tool tool = 2; + string ip = 3 [(match_path) = "custom.ip"]; } }