All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.cel.common.CelOptions Maven / Gradle / Ivy

The newest version!
// Copyright 2022 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
//
//      https://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.

package dev.cel.common;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.errorprone.annotations.Immutable;

/**
 * Options to configure how the CEL parser, type-checker, and evaluator behave.
 *
 * 

Users are strongly encouraged to use {@link #current} to ensure that the overall CEL stack * behaves in the manner most consistent with the CEL specification. */ @CheckReturnValue @AutoValue @Immutable public abstract class CelOptions { /** * ProtoUnsetFieldOptions describes how to handle Activation.fromProto() calls where proto message * fields may be unset and should either be handled perhaps as absent or as the default proto * value. */ public enum ProtoUnsetFieldOptions { // Do not bind a field if it is unset. Repeated fields are bound as empty list. SKIP, // Bind the (proto api) default value for a field. BIND_DEFAULT; } public static final CelOptions DEFAULT = current().build(); public static final CelOptions LEGACY = newBuilder().disableCelStandardEquality(true).build(); // Package-private constructor to prevent extension. CelOptions() {} // Parser related options public abstract boolean enableReservedIds(); public abstract boolean enableOptionalSyntax(); public abstract int maxExpressionCodePointSize(); public abstract int maxParseErrorRecoveryLimit(); public abstract int maxParseRecursionDepth(); public abstract boolean populateMacroCalls(); public abstract boolean retainRepeatedUnaryOperators(); public abstract boolean retainUnbalancedLogicalExpressions(); // Type-Checker related options public abstract boolean enableCompileTimeOverloadResolution(); public abstract boolean enableHomogeneousLiterals(); public abstract boolean enableTimestampEpoch(); public abstract boolean enableHeterogeneousNumericComparisons(); public abstract boolean enableNamespacedDeclarations(); // Evaluation related options public abstract boolean disableCelStandardEquality(); public abstract boolean enableShortCircuiting(); public abstract boolean enableRegexPartialMatch(); public abstract boolean enableUnsignedComparisonAndArithmeticIsUnsigned(); public abstract boolean enableUnsignedLongs(); public abstract boolean enableProtoDifferencerEquality(); public abstract boolean errorOnDuplicateMapKeys(); public abstract boolean errorOnIntWrap(); public abstract boolean resolveTypeDependencies(); public abstract boolean enableUnknownTracking(); public abstract boolean enableCelValue(); public abstract int comprehensionMaxIterations(); public abstract boolean unwrapWellKnownTypesOnFunctionDispatch(); public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption(); public abstract Builder toBuilder(); public ImmutableSet toExprFeatures() { ImmutableSet.Builder features = ImmutableSet.builder(); if (enableCompileTimeOverloadResolution()) { features.add(ExprFeatures.COMPILE_TIME_OVERLOAD_RESOLUTION); } if (disableCelStandardEquality()) { features.add(ExprFeatures.LEGACY_JAVA_EQUALITY); } if (enableHomogeneousLiterals()) { features.add(ExprFeatures.HOMOGENEOUS_LITERALS); } if (enableRegexPartialMatch()) { features.add(ExprFeatures.REGEX_PARTIAL_MATCH); } if (enableReservedIds()) { features.add(ExprFeatures.RESERVED_IDS); } if (enableUnsignedComparisonAndArithmeticIsUnsigned()) { features.add(ExprFeatures.UNSIGNED_COMPARISON_AND_ARITHMETIC_IS_UNSIGNED); } if (retainRepeatedUnaryOperators()) { features.add(ExprFeatures.RETAIN_REPEATED_UNARY_OPERATORS); } if (retainUnbalancedLogicalExpressions()) { features.add(ExprFeatures.RETAIN_UNBALANCED_LOGICAL_EXPRESSIONS); } if (errorOnIntWrap()) { features.add(ExprFeatures.ERROR_ON_WRAP); } if (errorOnDuplicateMapKeys()) { features.add(ExprFeatures.ERROR_ON_DUPLICATE_KEYS); } if (populateMacroCalls()) { features.add(ExprFeatures.POPULATE_MACRO_CALLS); } if (enableTimestampEpoch()) { features.add(ExprFeatures.ENABLE_TIMESTAMP_EPOCH); } if (enableHeterogeneousNumericComparisons()) { features.add(ExprFeatures.ENABLE_HETEROGENEOUS_NUMERIC_COMPARISONS); } if (enableNamespacedDeclarations()) { features.add(ExprFeatures.ENABLE_NAMESPACED_DECLARATIONS); } if (enableUnsignedLongs()) { features.add(ExprFeatures.ENABLE_UNSIGNED_LONGS); } if (enableProtoDifferencerEquality()) { features.add(ExprFeatures.PROTO_DIFFERENCER_EQUALITY); } return features.build(); } /** * Return an unconfigured {@code Builder}. This is equivalent to preserving all legacy behaviors, * both good and bad, of the original CEL implementation. */ public static Builder newBuilder() { return new AutoValue_CelOptions.Builder() // Parser options .enableReservedIds(false) .enableOptionalSyntax(false) .maxExpressionCodePointSize(100_000) .maxParseErrorRecoveryLimit(30) .maxParseRecursionDepth(250) .populateMacroCalls(false) .retainRepeatedUnaryOperators(false) .retainUnbalancedLogicalExpressions(false) // Type-Checker options .enableCompileTimeOverloadResolution(false) .enableHomogeneousLiterals(false) .enableTimestampEpoch(false) .enableHeterogeneousNumericComparisons(false) .enableNamespacedDeclarations(true) // Evaluation options .disableCelStandardEquality(true) .enableShortCircuiting(true) .enableRegexPartialMatch(false) .enableUnsignedComparisonAndArithmeticIsUnsigned(false) .enableUnsignedLongs(false) .enableProtoDifferencerEquality(false) .errorOnIntWrap(false) .errorOnDuplicateMapKeys(false) .resolveTypeDependencies(true) .enableUnknownTracking(false) .enableCelValue(false) .comprehensionMaxIterations(-1) .unwrapWellKnownTypesOnFunctionDispatch(true) .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT); } /** * Return a {@code Builder} configured with the most current set of {@code CelOptions} * (recommended). */ public static Builder current() { return newBuilder() .enableReservedIds(true) .enableUnsignedComparisonAndArithmeticIsUnsigned(true) .enableUnsignedLongs(true) .enableRegexPartialMatch(true) .errorOnDuplicateMapKeys(true) .errorOnIntWrap(true) .resolveTypeDependencies(true) .disableCelStandardEquality(false); } public static CelOptions fromExprFeatures(ImmutableSet features) { return newBuilder() .enableCompileTimeOverloadResolution( features.contains(ExprFeatures.COMPILE_TIME_OVERLOAD_RESOLUTION)) .disableCelStandardEquality(features.contains(ExprFeatures.LEGACY_JAVA_EQUALITY)) .enableHomogeneousLiterals(features.contains(ExprFeatures.HOMOGENEOUS_LITERALS)) .enableRegexPartialMatch(features.contains(ExprFeatures.REGEX_PARTIAL_MATCH)) .enableReservedIds(features.contains(ExprFeatures.RESERVED_IDS)) .enableUnsignedComparisonAndArithmeticIsUnsigned( features.contains(ExprFeatures.UNSIGNED_COMPARISON_AND_ARITHMETIC_IS_UNSIGNED)) .retainRepeatedUnaryOperators( features.contains(ExprFeatures.RETAIN_REPEATED_UNARY_OPERATORS)) .retainUnbalancedLogicalExpressions( features.contains(ExprFeatures.RETAIN_UNBALANCED_LOGICAL_EXPRESSIONS)) .errorOnIntWrap(features.contains(ExprFeatures.ERROR_ON_WRAP)) .errorOnDuplicateMapKeys(features.contains(ExprFeatures.ERROR_ON_DUPLICATE_KEYS)) .populateMacroCalls(features.contains(ExprFeatures.POPULATE_MACRO_CALLS)) .enableTimestampEpoch(features.contains(ExprFeatures.ENABLE_TIMESTAMP_EPOCH)) .enableHeterogeneousNumericComparisons( features.contains(ExprFeatures.ENABLE_HETEROGENEOUS_NUMERIC_COMPARISONS)) .enableNamespacedDeclarations( features.contains(ExprFeatures.ENABLE_NAMESPACED_DECLARATIONS)) .enableUnsignedLongs(features.contains(ExprFeatures.ENABLE_UNSIGNED_LONGS)) .enableProtoDifferencerEquality(features.contains(ExprFeatures.PROTO_DIFFERENCER_EQUALITY)) .build(); } /** Builder for configuring the {@code CelOptions}. */ @AutoValue.Builder public abstract static class Builder { // Package-private constructor to prevent extension. Builder() {} // Parser related builder options. /** * Check for use of reserved identifiers during parsing. * *

See the language * spec for a list of reserved identifiers. */ public abstract Builder enableReservedIds(boolean value); /** * EnableOptionalSyntax enables syntax for optional field and index selection (e.g: msg.?field). * *

Note: This option is automatically enabled for the parser by adding {@code * CelOptionalLibrary} to the environment. */ public abstract Builder enableOptionalSyntax(boolean value); /** * Set a limit on the size of the expression string which may be parsed in terms of the number * of code points contained within the string. */ public abstract Builder maxExpressionCodePointSize(int value); /** * Limit the number of error recovery attempts which may be made by the parser for a given * syntax error before terminating the parse completely. */ public abstract Builder maxParseErrorRecoveryLimit(int value); /** Limit the amount of recursion within parse expressions. */ public abstract Builder maxParseRecursionDepth(int value); /** Populate macro_calls map in source_info with macro calls parsed from the expression. */ public abstract Builder populateMacroCalls(boolean value); /** * Retain all invocations of unary '-' and '!' that occur in source in the abstract syntax. * *

By default the parser collapses towers of repeated unary '-' and '!' into zero or one * instance by assuming these operators to be inverses of themselves. This behavior may not * always be desirable. */ public abstract Builder retainRepeatedUnaryOperators(boolean value); /** * Retain the original grouping of logical connectives '&&' and '||' without attempting to * rebalance them in the abstract syntax. * *

The default rebalancing can reduce the overall nesting depth of the generated protos * representing abstract syntax, but it relies on associativity of the operations themselves. * This behavior may not always be desirable. */ public abstract Builder retainUnbalancedLogicalExpressions(boolean value); // Type-Checker related options /** * Require overloads to resolve (narrow to a single candidate) during type checking. * *

This eliminates run-time overload dispatch and avoids implicit coercions of the result * type to type dyn. However, this configuration should only be used if your application is not * handling any form of dynamic data such as JSON or {@code google.protobuf.Any}. */ public abstract Builder enableCompileTimeOverloadResolution(boolean value); /** * During type checking require list-, and map literals to be type-homogeneous in their * element-, key-, and value types, respectively. * *

Without this flag one can use type-mismatched elements, keys, and values, and the type * checker will implicitly coerce them to type dyn. * *

This flag is recommended for all new uses of CEL. * * @deprecated Use standalone {@code dev.cel.validators.validator.HomogeneousLiteralValidator} * instead. */ @Deprecated public abstract Builder enableHomogeneousLiterals(boolean value); /** * Enable the {@code int64_to_timestamp} overload which creates a timestamp from Uxix epoch * seconds. * *

This option will be automatically enabled after a sufficient period of time has elapsed to * ensure that all runtimes support the implementation. * *

TODO: Remove this feature once it has been auto-enabled. */ public abstract Builder enableTimestampEpoch(boolean value); /** * Enable the {@code less_equals_double_int64} and other cross-type numeric comparisons for * {@code double}, {@code int64}, and {@code uint64} values. * *

This feature adds the declarations for these overloads to the CEL standard environment, * but the runtime functions are enabled by default. * *

TODO: Remove this feature once it has been auto-enabled. */ public abstract Builder enableHeterogeneousNumericComparisons(boolean value); /** * Enables the usage of namespaced functions and identifiers. This causes the type-checker to * rewrite the AST to support namespacing (e.g: a field selector of form `namespace.msg.field` * gets rewritten as a fully qualified identifier name of `namespace.msg.field`). * *

TODO: Remove this feature once it has been auto-enabled. * * @deprecated This will be removed in the future. Please update your codebase to not rely on * existence of certain expression nodes that would be collapsed/removed with this feature * enabled. */ @Deprecated public abstract Builder enableNamespacedDeclarations(boolean value); // Evaluation related options /** * Disable standard CEL equality in favor of the legacy Java equality calls for (in)equality * tests. * *

This feature is how the legacy CEL-Java APIs were originally configured, and in most cases * will yield identical results to CEL equality, with the exception that equality between * well-known protobuf types (wrapper types, {@code protobuf.Value}, {@code protobuf.Any}) may * not compare correctly to simple and aggregate CEL types. * *

Additionally, Java equality across numeric types such as {@code double} and {@code long}, * will be trivially false, whereas CEL equality will compare the values as though they exist on * a continuous number line. */ public abstract Builder disableCelStandardEquality(boolean value); /** * Enable short-circuiting of the logical operator evaluation. If enabled, AND, OR, and TERNARY * do not evaluate the entire expression once the resulting value is known from the left-hand * side. * *

This option is enabled by default. In most cases, this should not be disabled except for * debugging purposes or collecting results for all evaluated branches through {@link * dev.cel.runtime.CelEvaluationListener}. */ public abstract Builder enableShortCircuiting(boolean value); /** * Treat regex {@code matches} calls as substring (unanchored) match patterns. * *

The default treatment for pattern matching within RE2 is full match within Java; however, * the CEL standard specifies that the matches() function is a substring match. */ public abstract Builder enableRegexPartialMatch(boolean value); /** * Treat unsigned integers as unsigned when doing arithmetic and comparisons. * *

Prior to turning on this feature, attempts to perform arithmetic or comparisons on * unsigned integers larger than 2^63-1 may result in a runtime exception in the form of an * {@link java.lang.IllegalArgumentException}. */ public abstract Builder enableUnsignedComparisonAndArithmeticIsUnsigned(boolean value); /** * Use {@code UnsignedLong} values to represent unsigned integers within CEL instead of the * nearest Java equivalent of {@code Long}. */ public abstract Builder enableUnsignedLongs(boolean value); /** * Perform equality using {@code ProtoEquality} proto equality. * *

CEL's alternative implementation to the {@code Message#equals} comes with a few key * differences: * *

    *
  • NaN is not equal to itself. *
  • Any values are unpacked before comparison. *
  • If two Any values cannot be unpacked, they are compared by bytes. *
*/ public abstract Builder enableProtoDifferencerEquality(boolean value); /** Throw errors on duplicate keys in map literals. */ public abstract Builder errorOnDuplicateMapKeys(boolean value); /** * Throw errors when ints or uints wrap. * *

Prior to this feature, int and uint arithmetic wrapped, i.e. was coerced into range via * mod 2^64. The spec settled on throwing an error instead. Note that this makes arithmetic non- * associative. */ public abstract Builder errorOnIntWrap(boolean value); /** * Enable or disable the resolution of {@code Descriptor} type dependencies as part of the CEL * environment setup. Defaults to disabled. * *

Disabling this feature should only be done when you know that only the types provided will * be referenced within the CEL expression. This means that either the type set provided was * complete, or that the type set is only what is referenced within expressions. */ public abstract Builder resolveTypeDependencies(boolean value); /** * Enable tracking unknown attributes and function invocations encountered during evaluation. * *

When enabled, the evaluator will track unknown attributes (leaf values in the activations) * and function results (a particular invocation that was identified as unknown). */ public abstract Builder enableUnknownTracking(boolean value); /** * Enables the usage of {@code CelValue} for the runtime. It is a native value representation of * CEL that wraps Java native objects, and comes with extended capabilities, such as allowing * value constructs not understood by CEL (ex: POJOs). * *

Warning: This option is experimental. */ public abstract Builder enableCelValue(boolean value); /** * Limit the total number of iterations permitted within comprehension loops. * *

If the limit is reached, then an evaluation exception will be thrown. This limit also * affects nested comprehension interactions as well. * *

A negative {@code value} will disable max iteration checks. * *

Note: comprehension limits are not supported within the async CEL interpreter. */ public abstract Builder comprehensionMaxIterations(int 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. * * @deprecated This will be removed in the future. Please update your codebase to be conformant * with CEL specification. */ @Deprecated public abstract Builder unwrapWellKnownTypesOnFunctionDispatch(boolean value); /** * Configure how unset proto fields are handled when evaluating over a protobuf message where * fields are intended to be treated as top-level variables. Defaults to binding all fields to * their default value if unset. * * @see ProtoUnsetFieldOptions */ public abstract Builder fromProtoUnsetFieldOption(ProtoUnsetFieldOptions value); public abstract CelOptions build(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy