Common Expression Language (CEL) — это язык выражений общего назначения, разработанный для обеспечения быстроты, переносимости и безопасности выполнения. Вы можете использовать CEL как самостоятельно, так и встраивать его в более крупный продукт. CEL отлично подходит для самых разных приложений: от маршрутизации удалённых вызовов процедур (RPC) до определения политик безопасности. CEL расширяем, независим от платформы и оптимизирован для рабочих процессов с однократной компиляцией и многократным вычислением.
 CEL был разработан специально для безопасного выполнения пользовательского кода. Хотя слепой вызов eval() для пользовательского кода Python опасен, вы можете безопасно выполнить пользовательский CEL-код. Поскольку CEL предотвращает поведение, которое могло бы снизить производительность, он выполняет вычисления безопасно за наносекунды или микросекунды. Скорость и безопасность CEL делают его идеальным для приложений, критичных к производительности.
CEL вычисляет выражения, аналогичные однострочным функциям или лямбда-выражениям. Хотя CEL обычно используется для принятия решений с логическими значениями, его также можно использовать для создания более сложных объектов, таких как JSON или сообщения буфера протокола.
Почему CEL?
Многие сервисы и приложения оценивают декларативные конфигурации. Например, управление доступом на основе ролей (RBAC) — это декларативная конфигурация, которая принимает решение о доступе на основе роли пользователя и набора пользователей. Хотя декларативные конфигурации достаточны в большинстве случаев, иногда требуются более широкие возможности. Именно здесь на помощь приходит CEL.
В качестве примера расширения декларативной конфигурации с помощью CEL рассмотрим возможности Google Cloud Identity and Access Management (IAM) . Хотя RBAC является распространённым вариантом, IAM предлагает выражения CEL, позволяющие пользователям дополнительно ограничивать область действия ролевого гранта в соответствии со свойствами сообщения proto запроса или доступными ресурсами. Описание таких условий через модель данных привело бы к созданию сложной поверхности API, с которой трудно работать. Использование CEL с управлением доступом на основе атрибутов (ABAC) — это выразительное и мощное расширение RBAC.
Основные концепции CEL
В CEL выражение компилируется с учётом заданной среды. На этапе компиляции создаётся абстрактное синтаксическое дерево (AST) в формате буфера протокола . Скомпилированные выражения сохраняются для дальнейшего использования, что позволяет максимально ускорить вычисление. Одно скомпилированное выражение может быть вычислено с использованием множества различных входных данных.
Давайте подробнее рассмотрим некоторые из этих концепций.
Выражения
Выражения пишутся пользователями. Выражения аналогичны однострочным функциям или лямбда-выражениям. Сигнатура функции, объявляющая входные данные, записывается вне выражения CEL, а библиотека функций, доступная CEL, импортируется автоматически.
 Например, следующее выражение CEL принимает объект запроса, а запрос включает токен claims . Выражение возвращает логическое значение, указывающее, действителен ли ещё токен claims .
Пример выражения CEL для аутентификации токена утверждений
// Check whether a JSON Web Token has expired by inspecting the 'exp' claim.
//
// Args:
//   claims - authentication claims.
//   now    - timestamp indicating the current system time.
// Returns: true if the token has expired.
//
timestamp(claims["exp"]) < now
В то время как пользователи определяют выражение CEL, службы и приложения определяют среду, в которой оно выполняется.
Окружающая среда
Окружения определяются службами . Службы и приложения, в которые встроен CEL, объявляют окружение выражений. Окружение — это набор переменных и функций, которые можно использовать в выражениях CEL.
 Например, следующий код textproto объявляет среду, содержащую request и переменные now , используя сообщение CompileRequest от службы CEL.
Пример декларации среды CEL
# Format: $SOURCE_PATH/service.proto#CompileRequest
declarations {
  name: "request"
  ident {
    type { message_type: "google.rpc.context.AttributeContext.Request" }
  }
}
declarations {
  name: "now"
  ident {
    type { well_known: "TIMESTAMP" }
  }
}
Основанные на прототипах объявления используются средством проверки типов CEL для обеспечения того, чтобы все ссылки на идентификаторы и функции в выражении были объявлены и использовались правильно.
Фазы обработки выражения
Выражения CEL обрабатываются в три этапа:
- Анализировать
- Проверять
- Оценивать
Наиболее распространенный шаблон использования CEL — это разбор и проверка выражений во время конфигурации, сохранение AST, а затем повторное извлечение и оценка AST во время выполнения.
Иллюстрация фаз обработки CEL

 CEL-код разбирается из человекочитаемого выражения в AST с помощью лексера ANTLR и грамматики парсера. На этапе разбора формируется AST на основе прото, где каждый узел Expr в AST содержит целочисленный идентификатор, используемый для индексации метаданных, сгенерированных в ходе разбора и проверки. Файл syntax.proto , создаваемый в процессе разбора, представляет собой абстрактное представление того, что было введено в строковой форме выражения.
 После разбора выражения выполняется проверка его типов в соответствии с окружением, чтобы убедиться, что все идентификаторы переменных и функций в выражении объявлены и используются корректно. Проверка типов создаёт файл checked.proto , содержащий метаданные разрешения типов, переменных и функций, которые могут значительно повысить эффективность вычисления.
Наконец, после анализа и проверки выражения оценивается сохраненное AST.
Оценщику CEL нужны три вещи:
- Привязки функций для любых пользовательских расширений
- Переменные привязки
- AST для оценки
Связывания функций и переменных должны соответствовать тем, которые использовались при компиляции AST. Любые из этих входных данных могут быть повторно использованы в нескольких вычислениях, например, AST, оцениваемый с использованием нескольких наборов связываний переменных, одни и те же переменные, используемые для нескольких AST, или связывания функций, используемые на протяжении всего жизненного цикла процесса (распространённый случай).