// Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; package google.cloud.policytroubleshooter.iam.v3beta; import "google/api/annotations.proto"; import "google/api/client.proto"; import "google/api/field_behavior.proto"; import "google/iam/v1/policy.proto"; import "google/iam/v2/policy.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; import "google/rpc/status.proto"; import "google/type/expr.proto"; option cc_enable_arenas = true; option go_package = "cloud.google.com/go/policytroubleshooter/iam/apiv3beta/iampb;iampb"; option java_multiple_files = true; option java_outer_classname = "TroubleshooterProto"; option java_package = "com.google.cloud.policytroubleshooter.iam.v3beta"; // IAM Policy Troubleshooter service. // // This service helps you troubleshoot access issues for Google Cloud resources. service PolicyTroubleshooter { option (google.api.default_host) = "policytroubleshooter.googleapis.com"; option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; // Checks whether a principal has a specific permission for a specific // resource, and explains why the principal does or doesn't have that // permission. rpc TroubleshootIamPolicy(TroubleshootIamPolicyRequest) returns (TroubleshootIamPolicyResponse) { option (google.api.http) = { post: "/v3beta/iam:troubleshoot" body: "*" }; } } // Whether IAM allow policies gives the principal the permission. enum AllowAccessState { // Not specified. ALLOW_ACCESS_STATE_UNSPECIFIED = 0; // The allow policy gives the principal the permission. ALLOW_ACCESS_STATE_GRANTED = 1; // The allow policy doesn't give the principal the permission. ALLOW_ACCESS_STATE_NOT_GRANTED = 2; // The allow policy gives the principal the permission if a condition // expression evaluate to `true`. However, the sender of the request didn't // provide enough context for Policy Troubleshooter to evaluate the condition // expression. ALLOW_ACCESS_STATE_UNKNOWN_CONDITIONAL = 3; // The sender of the request doesn't have access to all of the allow policies // that Policy Troubleshooter needs to evaluate the principal's access. ALLOW_ACCESS_STATE_UNKNOWN_INFO = 4; } // Whether IAM deny policies deny the principal the permission. enum DenyAccessState { // Not specified. DENY_ACCESS_STATE_UNSPECIFIED = 0; // The deny policy denies the principal the permission. DENY_ACCESS_STATE_DENIED = 1; // The deny policy doesn't deny the principal the permission. DENY_ACCESS_STATE_NOT_DENIED = 2; // The deny policy denies the principal the permission if a condition // expression evaluates to `true`. However, the sender of the request didn't // provide enough context for Policy Troubleshooter to evaluate the condition // expression. DENY_ACCESS_STATE_UNKNOWN_CONDITIONAL = 3; // The sender of the request does not have access to all of the deny policies // that Policy Troubleshooter needs to evaluate the principal's access. DENY_ACCESS_STATE_UNKNOWN_INFO = 4; } // Whether a role includes a specific permission. enum RolePermissionInclusionState { // Not specified. ROLE_PERMISSION_INCLUSION_STATE_UNSPECIFIED = 0; // The permission is included in the role. ROLE_PERMISSION_INCLUDED = 1; // The permission is not included in the role. ROLE_PERMISSION_NOT_INCLUDED = 2; // The sender of the request is not allowed to access the role definition. ROLE_PERMISSION_UNKNOWN_INFO = 3; } // Whether the permission in the request matches the permission in the policy. enum PermissionPatternMatchingState { // Not specified. PERMISSION_PATTERN_MATCHING_STATE_UNSPECIFIED = 0; // The permission in the request matches the permission in the policy. PERMISSION_PATTERN_MATCHED = 1; // The permission in the request matches the permission in the policy. PERMISSION_PATTERN_NOT_MATCHED = 2; } // Whether the principal in the request matches the principal in the policy. enum MembershipMatchingState { // Not specified. MEMBERSHIP_MATCHING_STATE_UNSPECIFIED = 0; // The principal in the request matches the principal in the policy. The // principal can be included directly or indirectly: // // * A principal is included directly if that principal is listed in the // role binding. // * A principal is included indirectly if that principal is in a Google // group, Google Workspace account, or Cloud Identity domain that is listed // in the policy. MEMBERSHIP_MATCHED = 1; // The principal in the request doesn't match the principal in the policy. MEMBERSHIP_NOT_MATCHED = 2; // The principal in the policy is a group or domain, and the sender of the // request doesn't have permission to view whether the principal in the // request is a member of the group or domain. MEMBERSHIP_UNKNOWN_INFO = 3; // The principal is an unsupported type. MEMBERSHIP_UNKNOWN_UNSUPPORTED = 4; } // The extent to which a single data point contributes to an overall // determination. enum HeuristicRelevance { // Not specified. HEURISTIC_RELEVANCE_UNSPECIFIED = 0; // The data point has a limited effect on the result. Changing the data point // is unlikely to affect the overall determination. HEURISTIC_RELEVANCE_NORMAL = 1; // The data point has a strong effect on the result. Changing the data point // is likely to affect the overall determination. HEURISTIC_RELEVANCE_HIGH = 2; } // Request for // [TroubleshootIamPolicy][google.cloud.policytroubleshooter.iam.v3beta.PolicyTroubleshooter.TroubleshootIamPolicy]. message TroubleshootIamPolicyRequest { // The information to use for checking whether a principal has a permission // for a resource. AccessTuple access_tuple = 1; } // Response for // [TroubleshootIamPolicy][google.cloud.policytroubleshooter.iam.v3beta.PolicyTroubleshooter.TroubleshootIamPolicy]. message TroubleshootIamPolicyResponse { // Whether the principal has the permission on the resource. enum OverallAccessState { // Not specified. OVERALL_ACCESS_STATE_UNSPECIFIED = 0; // The principal has the permission. CAN_ACCESS = 1; // The principal doesn't have the permission. CANNOT_ACCESS = 2; // The principal might have the permission, but the sender can't access all // of the information needed to fully evaluate the principal's access. UNKNOWN_INFO = 3; // The principal might have the permission, but Policy Troubleshooter can't // fully evaluate the principal's access because the sender didn't provide // the required context to evaluate the condition. UNKNOWN_CONDITIONAL = 4; } // Indicates whether the principal has the specified permission for the // specified resource, based on evaluating all types of the applicable IAM // policies. OverallAccessState overall_access_state = 1; // The access tuple from the request, including any provided context used to // evaluate the condition. AccessTuple access_tuple = 2; // An explanation of how the applicable IAM allow policies affect the final // access state. AllowPolicyExplanation allow_policy_explanation = 3; // An explanation of how the applicable IAM deny policies affect the final // access state. DenyPolicyExplanation deny_policy_explanation = 4; } // Information about the principal, resource, and permission to check. message AccessTuple { // Required. The email address of the principal whose access you want to // check. For example, `alice@example.com` or // `my-service-account@my-project.iam.gserviceaccount.com`. // // The principal must be a Google Account or a service account. Other types of // principals are not supported. string principal = 1 [(google.api.field_behavior) = REQUIRED]; // Required. The full resource name that identifies the resource. For example, // `//compute.googleapis.com/projects/my-project/zones/us-central1-a/instances/my-instance`. // // For examples of full resource names for Google Cloud services, see // https://cloud.google.com/iam/help/troubleshooter/full-resource-names. string full_resource_name = 2 [(google.api.field_behavior) = REQUIRED]; // Required. The IAM permission to check for, either in the `v1` permission // format or the `v2` permission format. // // For a complete list of IAM permissions in the `v1` format, see // https://cloud.google.com/iam/help/permissions/reference. // // For a list of IAM permissions in the `v2` format, see // https://cloud.google.com/iam/help/deny/supported-permissions. // // For a complete list of predefined IAM roles and the permissions in each // role, see https://cloud.google.com/iam/help/roles/reference. string permission = 3 [(google.api.field_behavior) = REQUIRED]; // Output only. The permission that Policy Troubleshooter checked for, in // the `v2` format. string permission_fqdn = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; // Optional. Additional context for the request, such as the request time or // IP address. This context allows Policy Troubleshooter to troubleshoot // conditional role bindings and deny rules. ConditionContext condition_context = 5 [(google.api.field_behavior) = OPTIONAL]; } // Additional context for troubleshooting conditional role bindings and deny // rules. message ConditionContext { // Core attributes for a resource. A resource is an // addressable (named) entity provided by the destination service. For // example, a Compute Engine instance. message Resource { // The name of the service that this resource belongs to, such as // `compute.googleapis.com`. The service name might not match the DNS // hostname that actually serves the request. // // For a full list of resource service values, see // https://cloud.google.com/iam/help/conditions/resource-services string service = 1; // The stable identifier (name) of a resource on the `service`. A resource // can be logically identified as `//{resource.service}/{resource.name}`. // Unlike the resource URI, the resource name doesn't contain any protocol // and version information. // // For a list of full resource name formats, see // https://cloud.google.com/iam/help/troubleshooter/full-resource-names string name = 2; // The type of the resource, in the format `{service}/{kind}`. // // For a full list of resource type values, see // https://cloud.google.com/iam/help/conditions/resource-types string type = 3; } // This message defines attributes for a node that handles a network request. // The node can be either a service or an application that sends, forwards, // or receives the request. Service peers should fill in // `principal` and `labels` as appropriate. message Peer { // The IPv4 or IPv6 address of the peer. string ip = 1; // The network port of the peer. int64 port = 2; } // This message defines attributes for an HTTP request. If the actual // request is not an HTTP request, the runtime system should try to map // the actual request to an equivalent HTTP request. message Request { // Optional. The timestamp when the destination service receives the first // byte of the request. google.protobuf.Timestamp receive_time = 1 [(google.api.field_behavior) = OPTIONAL]; } // A tag that applies to a resource during policy evaluation. Tags can be // either directly bound to a resource or inherited from its ancestor. // `EffectiveTag` contains the `name` and `namespaced_name` of the tag value // and tag key, with additional fields of `inherited` to indicate the // inheritance status of the effective tag. message EffectiveTag { // Output only. Resource name for TagValue in the format `tagValues/456`. string tag_value = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; // Output only. The namespaced name of the TagValue. Can be in the form // `{organization_id}/{tag_key_short_name}/{tag_value_short_name}` or // `{project_id}/{tag_key_short_name}/{tag_value_short_name}` or // `{project_number}/{tag_key_short_name}/{tag_value_short_name}`. string namespaced_tag_value = 2 [(google.api.field_behavior) = OUTPUT_ONLY]; // Output only. The name of the TagKey, in the format `tagKeys/{id}`, such // as `tagKeys/123`. string tag_key = 3 [(google.api.field_behavior) = OUTPUT_ONLY]; // Output only. The namespaced name of the TagKey. Can be in the form // `{organization_id}/{tag_key_short_name}` or // `{project_id}/{tag_key_short_name}` or // `{project_number}/{tag_key_short_name}`. string namespaced_tag_key = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; // The parent name of the tag key. // Must be in the format `organizations/{organization_id}` or // `projects/{project_number}` string tag_key_parent_name = 6; // Output only. Indicates the inheritance status of a tag value // attached to the given resource. If the tag value is inherited from one of // the resource's ancestors, inherited will be true. If false, then the tag // value is directly attached to the resource, inherited will be false. bool inherited = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; } // Represents a target resource that is involved with a network activity. // If multiple resources are involved with an activity, this must be the // primary one. Resource resource = 1; // The destination of a network activity, such as accepting a TCP connection. // In a multi-hop network activity, the destination represents the receiver of // the last hop. Peer destination = 2; // Represents a network request, such as an HTTP request. Request request = 3; // Output only. The effective tags on the resource. The effective tags are // fetched during troubleshooting. repeated EffectiveTag effective_tags = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; } // Details about how the relevant IAM allow policies affect the final access // state. message AllowPolicyExplanation { // Indicates whether the principal has the specified permission for the // specified resource, based on evaluating all applicable IAM allow policies. AllowAccessState allow_access_state = 1; // List of IAM allow policies that were evaluated to check the principal's // permissions, with annotations to indicate how each policy contributed to // the final result. // // The list of policies includes the policy for the resource itself, as well // as allow policies that are inherited from higher levels of the resource // hierarchy, including the organization, the folder, and the project. // // To learn more about the resource hierarchy, see // https://cloud.google.com/iam/help/resource-hierarchy. repeated ExplainedAllowPolicy explained_policies = 2; // The relevance of the allow policy type to the overall access state. HeuristicRelevance relevance = 3; } // Details about how a specific IAM allow policy contributed to the final access // state. message ExplainedAllowPolicy { // Required. Indicates whether _this policy_ provides the specified permission // to the specified principal for the specified resource. // // This field does _not_ indicate whether the principal actually has the // permission for the resource. There might be another policy that overrides // this policy. To determine whether the principal actually has the // permission, use the `overall_access_state` field in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. AllowAccessState allow_access_state = 1 [(google.api.field_behavior) = REQUIRED]; // The full resource name that identifies the resource. For example, // `//compute.googleapis.com/projects/my-project/zones/us-central1-a/instances/my-instance`. // // If the sender of the request does not have access to the policy, this field // is omitted. // // For examples of full resource names for Google Cloud services, see // https://cloud.google.com/iam/help/troubleshooter/full-resource-names. string full_resource_name = 2; // Details about how each role binding in the policy affects the principal's // ability, or inability, to use the permission for the resource. The order of // the role bindings matches the role binding order in the policy. // // If the sender of the request does not have access to the policy, this field // is omitted. repeated AllowBindingExplanation binding_explanations = 3; // The relevance of this policy to the overall access state in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. // // If the sender of the request does not have access to the policy, this field // is omitted. HeuristicRelevance relevance = 4; // The IAM allow policy attached to the resource. // // If the sender of the request does not have access to the policy, this field // is empty. google.iam.v1.Policy policy = 5; } // Details about how a role binding in an allow policy affects a principal's // ability to use a permission. message AllowBindingExplanation { // Details about whether the role binding includes the principal. message AnnotatedAllowMembership { // Indicates whether the role binding includes the principal. MembershipMatchingState membership = 1; // The relevance of the principal's status to the overall determination for // the role binding. HeuristicRelevance relevance = 2; } // Required. Indicates whether _this role binding_ gives the specified // permission to the specified principal on the specified resource. // // This field does _not_ indicate whether the principal actually has the // permission on the resource. There might be another role binding that // overrides this role binding. To determine whether the principal actually // has the permission, use the `overall_access_state` field in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. AllowAccessState allow_access_state = 1 [(google.api.field_behavior) = REQUIRED]; // The role that this role binding grants. For example, // `roles/compute.admin`. // // For a complete list of predefined IAM roles, as well as the permissions in // each role, see https://cloud.google.com/iam/help/roles/reference. string role = 2; // Indicates whether the role granted by this role binding contains the // specified permission. RolePermissionInclusionState role_permission = 3; // The relevance of the permission's existence, or nonexistence, in the role // to the overall determination for the entire policy. HeuristicRelevance role_permission_relevance = 4; // The combined result of all memberships. Indicates if the principal is // included in any role binding, either directly or indirectly. AnnotatedAllowMembership combined_membership = 5; // Indicates whether each role binding includes the principal specified in the // request, either directly or indirectly. Each key identifies a principal in // the role binding, and each value indicates whether the principal in the // role binding includes the principal in the request. // // For example, suppose that a role binding includes the following principals: // // * `user:alice@example.com` // * `group:product-eng@example.com` // // You want to troubleshoot access for `user:bob@example.com`. This user is a // member of the group `group:product-eng@example.com`. // // For the first principal in the role binding, the key is // `user:alice@example.com`, and the `membership` field in the value is set to // `NOT_INCLUDED`. // // For the second principal in the role binding, the key is // `group:product-eng@example.com`, and the `membership` field in the value is // set to `INCLUDED`. map memberships = 6; // The relevance of this role binding to the overall determination for the // entire policy. HeuristicRelevance relevance = 7; // A condition expression that specifies when the role binding grants access. // // To learn about IAM Conditions, see // https://cloud.google.com/iam/help/conditions/overview. google.type.Expr condition = 8; // Condition evaluation state for this role binding. ConditionExplanation condition_explanation = 9; } // Details about how the relevant IAM deny policies affect the final access // state. message DenyPolicyExplanation { // Indicates whether the principal is denied the specified permission for // the specified resource, based on evaluating all applicable IAM deny // policies. DenyAccessState deny_access_state = 1; // List of resources with IAM deny policies that were evaluated to check the // principal's denied permissions, with annotations to indicate how each // policy contributed to the final result. // // The list of resources includes the policy for the resource itself, as well // as policies that are inherited from higher levels of the resource // hierarchy, including the organization, the folder, and the project. The // order of the resources starts from the resource and climbs up the resource // hierarchy. // // To learn more about the resource hierarchy, see // https://cloud.google.com/iam/help/resource-hierarchy. repeated ExplainedDenyResource explained_resources = 2; // The relevance of the deny policy result to the overall access state. HeuristicRelevance relevance = 3; // Indicates whether the permission to troubleshoot is supported in deny // policies. bool permission_deniable = 4; } // Details about how a specific resource contributed to the deny policy // evaluation. message ExplainedDenyResource { // Required. Indicates whether any policies attached to _this resource_ deny // the specific permission to the specified principal for the specified // resource. // // This field does _not_ indicate whether the principal actually has the // permission for the resource. There might be another policy that overrides // this policy. To determine whether the principal actually has the // permission, use the `overall_access_state` field in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. DenyAccessState deny_access_state = 1 [(google.api.field_behavior) = REQUIRED]; // The full resource name that identifies the resource. For example, // `//compute.googleapis.com/projects/my-project/zones/us-central1-a/instances/my-instance`. // // If the sender of the request does not have access to the policy, this field // is omitted. // // For examples of full resource names for Google Cloud services, see // https://cloud.google.com/iam/help/troubleshooter/full-resource-names. string full_resource_name = 2; // List of IAM deny policies that were evaluated to check the principal's // denied permissions, with annotations to indicate how each policy // contributed to the final result. repeated ExplainedDenyPolicy explained_policies = 3; // The relevance of this policy to the overall access state in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. // // If the sender of the request does not have access to the policy, this field // is omitted. HeuristicRelevance relevance = 4; } // Details about how a specific IAM deny policy [Policy][google.iam.v2.Policy] // contributed to the access check. message ExplainedDenyPolicy { // Required. Indicates whether _this policy_ denies the specified permission // to the specified principal for the specified resource. // // This field does _not_ indicate whether the principal actually has the // permission for the resource. There might be another policy that overrides // this policy. To determine whether the principal actually has the // permission, use the `overall_access_state` field in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. DenyAccessState deny_access_state = 1 [(google.api.field_behavior) = REQUIRED]; // The IAM deny policy attached to the resource. // // If the sender of the request does not have access to the policy, this field // is omitted. google.iam.v2.Policy policy = 2; // Details about how each rule in the policy affects the principal's inability // to use the permission for the resource. The order of the deny rule matches // the order of the rules in the deny policy. // // If the sender of the request does not have access to the policy, this field // is omitted. repeated DenyRuleExplanation rule_explanations = 3; // The relevance of this policy to the overall access state in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. // // If the sender of the request does not have access to the policy, this field // is omitted. HeuristicRelevance relevance = 4; } // Details about how a deny rule in a deny policy affects a principal's ability // to use a permission. message DenyRuleExplanation { // Details about whether the permission in the request is denied by the // deny rule. message AnnotatedPermissionMatching { // Indicates whether the permission in the request is denied by the deny // rule. PermissionPatternMatchingState permission_matching_state = 1; // The relevance of the permission status to the overall determination for // the rule. HeuristicRelevance relevance = 2; } // Details about whether the principal in the request is listed as a denied // principal in the deny rule, either directly or through membership in a // principal set. message AnnotatedDenyPrincipalMatching { // Indicates whether the principal is listed as a denied principal in the // deny rule, either directly or through membership in a principal set. MembershipMatchingState membership = 1; // The relevance of the principal's status to the overall determination for // the role binding. HeuristicRelevance relevance = 2; } // Required. Indicates whether _this rule_ denies the specified permission to // the specified principal for the specified resource. // // This field does _not_ indicate whether the principal is actually denied on // the permission for the resource. There might be another rule that overrides // this rule. To determine whether the principal actually has the permission, // use the `overall_access_state` field in the // [TroubleshootIamPolicyResponse][google.cloud.policytroubleshooter.iam.v3beta.TroubleshootIamPolicyResponse]. DenyAccessState deny_access_state = 1 [(google.api.field_behavior) = REQUIRED]; // Indicates whether the permission in the request is listed as a denied // permission in the deny rule. AnnotatedPermissionMatching combined_denied_permission = 2; // Lists all denied permissions in the deny rule and indicates whether each // permission matches the permission in the request. // // Each key identifies a denied permission in the rule, and each value // indicates whether the denied permission matches the permission in the // request. map denied_permissions = 3; // Indicates whether the permission in the request is listed as an exception // permission in the deny rule. AnnotatedPermissionMatching combined_exception_permission = 4; // Lists all exception permissions in the deny rule and indicates whether each // permission matches the permission in the request. // // Each key identifies a exception permission in the rule, and each value // indicates whether the exception permission matches the permission in the // request. map exception_permissions = 5; // Indicates whether the principal is listed as a denied principal in the // deny rule, either directly or through membership in a principal set. AnnotatedDenyPrincipalMatching combined_denied_principal = 6; // Lists all denied principals in the deny rule and indicates whether each // principal matches the principal in the request, either directly or through // membership in a principal set. // // Each key identifies a denied principal in the rule, and each value // indicates whether the denied principal matches the principal in the // request. map denied_principals = 7; // Indicates whether the principal is listed as an exception principal in the // deny rule, either directly or through membership in a principal set. AnnotatedDenyPrincipalMatching combined_exception_principal = 8; // Lists all exception principals in the deny rule and indicates whether each // principal matches the principal in the request, either directly or through // membership in a principal set. // // Each key identifies a exception principal in the rule, and each value // indicates whether the exception principal matches the principal in the // request. map exception_principals = 9; // The relevance of this role binding to the overall determination for the // entire policy. HeuristicRelevance relevance = 10; // A condition expression that specifies when the deny rule denies the // principal access. // // To learn about IAM Conditions, see // https://cloud.google.com/iam/help/conditions/overview. google.type.Expr condition = 11; // Condition evaluation state for this role binding. ConditionExplanation condition_explanation = 12; } // Explanation for how a condition affects a principal's access message ConditionExplanation { // Evaluated state of a condition expression. message EvaluationState { // Start position of an expression in the condition, by character. int32 start = 1; // End position of an expression in the condition, by character, // end included, for example: the end position of the first part of // `a==b || c==d` would be 4. int32 end = 2; // Value of this expression. google.protobuf.Value value = 3; // Any errors that prevented complete evaluation of the condition // expression. repeated google.rpc.Status errors = 4; } // Value of the condition. google.protobuf.Value value = 1; // Any errors that prevented complete evaluation of the condition expression. repeated google.rpc.Status errors = 3; // The value of each statement of the condition expression. The value can be // `true`, `false`, or `null`. The value is `null` if the statement can't be // evaluated. repeated EvaluationState evaluation_states = 2; }