Common Expression Language (CEL) è un linguaggio di espressioni per uso generico progettato per essere veloce, portatile e sicuro da eseguire. Puoi utilizzare CEL da solo o incorporarlo in un prodotto più grande. CEL è ideale per un'ampia gamma di applicazioni, dal routing delle chiamate di procedura remota (RPC) alla definizione dei criteri di sicurezza. CEL è estensibile, indipendente dalla piattaforma, verificabile formalmente e ottimizzato per i flussi di lavoro di compilazione una volta/valutazione molte volte.
CEL è stato progettato appositamente per essere sicuro per l'esecuzione del codice utente. Sebbene sia pericoloso chiamare ciecamente eval() sul codice Python di un utente, puoi eseguire in sicurezza il codice CEL di un utente. Inoltre, poiché CEL impedisce comportamenti che ne ridurrebbero il rendimento, viene valutato in sicurezza in nanosecondi o microsecondi. La velocità e la sicurezza di CEL lo rendono ideale per le applicazioni sensibili al rendimento.
CEL valuta le espressioni simili a funzioni a riga singola o espressioni lambda. Sebbene CEL sia di uso comune per le decisioni booleane, puoi utilizzarlo anche per creare oggetti più complessi come messaggi JSON o buffer di protocollo.
Perché CEL?
Molti servizi e applicazioni valutano le configurazioni dichiarative. Ad esempio, il controllo dell'accesso basato sui ruoli (RBAC) è una configurazione dichiarativa che produce una decisione di accesso in base al ruolo di un utente e a un insieme di utenti. Sebbene le configurazioni dichiarative siano sufficienti nella maggior parte dei casi, a volte è necessario un potere espressivo maggiore. È qui che entra in gioco CEL.
Ad esempio, per estendere una configurazione dichiarativa con CEL, considera le funzionalità di Google Cloud Identity and Access Management (IAM). Sebbene RBAC sia il caso comune, IAM offre espressioni CEL per consentire agli utenti di limitare ulteriormente l'ambito della concessione basata sui ruoli in base alle proprietà del messaggio proto della richiesta o delle risorse a cui si accede. La descrizione di queste condizioni tramite il modello di dati comporterebbe una superficie API complessa e difficile da utilizzare. Al contrario, l'utilizzo di CEL con il controllo dell'accesso basato sugli attributi (ABAC) è un'estensione espressiva e potente di RBAC.
Concetti di base di CEL
In CEL, un'espressione viene compilata in base a un ambiente. Il passaggio di compilazione produce un albero sintattico astratto (AST) in formato buffer di protocollo. Le espressioni compilate vengono archiviate per un utilizzo futuro per mantenere la valutazione il più veloce possibile. Una singola espressione compilata può essere valutata con molti input diversi.
Diamo un'occhiata più da vicino ad alcuni di questi concetti.
Espressioni
Le espressioni vengono scritte dagli utenti. Le espressioni sono simili a corpi di funzioni a riga singola o espressioni lambda. La firma della funzione che dichiara l'input viene scritta al di fuori dell'espressione CEL e la libreria di funzioni disponibili per CEL viene importata automaticamente.
Ad esempio, la seguente espressione CEL accetta un oggetto richiesta e la richiesta include un token claims. L'espressione restituisce un valore booleano che indica se il token claims è ancora valido.
Esempio di espressione CEL per autenticare un token di rivendicazioni
// 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
Mentre gli utenti definiscono l'espressione CEL, i servizi e le applicazioni definiscono l'ambiente in cui viene eseguita.
Ambienti
Gli ambienti sono definiti dai servizi. I servizi e le applicazioni che incorporano CEL dichiarano l'ambiente di espressione. L'ambiente è la raccolta di variabili e funzioni che possono essere utilizzate nelle espressioni CEL.
Ad esempio, il seguente codice textproto dichiara un ambiente contenente le variabili request e now utilizzando il messaggio CompileRequest di un servizio CEL.
Esempio di dichiarazione dell'ambiente 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" }
}
}
Le dichiarazioni basate su proto vengono utilizzate dal controllo dei tipi CEL per garantire che tutti gli identificatori e i riferimenti alle funzioni all'interno di un'espressione siano dichiarati e utilizzati correttamente.
Fasi di elaborazione delle espressioni
Le espressioni CEL vengono elaborate in tre fasi:
- Analizza
- Assegno
- Valuta
Il pattern di utilizzo di CEL più comune consiste nell'analizzare e controllare le espressioni in fase di configurazione, archiviare l'AST e poi recuperare e valutare ripetutamente l'AST in fase di runtime.
Illustrazione delle fasi di elaborazione di CEL

CEL viene analizzato da un'espressione leggibile da persone a un AST utilizzando una
ANTLR. La fase di analisi lessicale e sintattica genera un
AST basato su proto in cui ogni nodo Expr nell'AST contiene un ID intero utilizzato per
indicizzare i metadati generati durante l'analisi lessicale e sintattica e il controllo. Il
syntax.proto file prodotto durante l'analisi lessicale e sintattica rappresenta
la rappresentazione astratta di ciò che è stato digitato nella forma di stringa dell'
espressione.
Dopo l'analisi lessicale e sintattica di un'espressione, viene eseguito il controllo dei tipi in base all'ambiente per garantire che tutti gli identificatori di variabili e funzioni nell'espressione siano stati dichiarati e vengano utilizzati correttamente. Il controllo dei tipi produce un
checked.proto file che include metadati di risoluzione di tipi, variabili e funzioni
che possono migliorare drasticamente l'efficienza della valutazione.
Infine, dopo l'analisi lessicale e sintattica e il controllo di un'espressione, viene valutato l'AST archiviato.
Il valutatore CEL ha bisogno di tre elementi:
- Associazioni di funzioni per eventuali estensioni personalizzate
- Associazioni di variabili
- Un AST da valutare
Le associazioni di funzioni e variabili devono corrispondere a quelle utilizzate per compilare l'AST. Uno qualsiasi di questi input può essere riutilizzato in più valutazioni, ad esempio un AST valutato in più insiemi di associazioni di variabili, le stesse variabili utilizzate in più AST o le associazioni di funzioni utilizzate per tutta la durata di un processo (un caso comune).
Verifica formale
Oltre alla valutazione in fase di runtime, le espressioni e i criteri CEL possono essere verificati formalmente per dimostrare matematicamente la loro correttezza in tutti gli input possibili.
Basato sul dimostratore di teoremi Z3, il framework di verifica formale CEL in CEL-Java traduce le espressioni e i criteri CEL in formule di soddisfacibilità modulo teorie (SMT) per:
- Dimostrare le invarianti di sicurezza: verifica che i criteri critici non possano essere bypassati con qualsiasi combinazione di input utilizzando le specifiche
assumeeassert. - Verificare l'equivalenza logica: dimostra matematicamente che le espressioni sottoposte a refactoring o generate dall'AI si comportano in modo identico alla regola originale.
- Applicare la validità esaustiva: garantisce che i guardrail (ad esempio i criteri di ammissione di convalida di Kubernetes) siano validi per tutti gli input o genera controesempi concreti in caso di violazione.
- Eliminare i falsi positivi: utilizza il rilevamento della contaminazione a tre passaggi per isolare le funzioni personalizzate non mappate, assicurandosi che le violazioni segnalate siano sempre bug riproducibili.
Per un'introduzione ed esempi reali, consulta il post del blog Google Open Source: Securing the era agentica: Introducing formal verification for CEL.