From d4becf263871e69f51da6425d4fd1777dd3e1d39 Mon Sep 17 00:00:00 2001 From: Sean Huh Date: Wed, 21 Oct 2026 10:04:31 -0700 Subject: [PATCH] Expose the verifier's counterexamples as structured CelWitness values PiperOrigin-RevId: 1004026905 --- verifier/README.md | 5 +- .../main/java/dev/cel/verifier/BUILD.bazel | 8 + .../cel/verifier/CelAstToZ3Translator.java | 1084 +---------------- .../cel/verifier/CelVerificationResult.java | 65 +- .../dev/cel/verifier/CelVerifierZ3Impl.java | 71 +- .../java/dev/cel/verifier/CelWitness.java | 52 + .../CelZ3ComprehensionTranslator.java | 535 ++++++++ .../CelZ3CounterexampleGenerator.java | 462 +++---- .../java/dev/cel/verifier/CelZ3Exprs.java | 2 + .../cel/verifier/CelZ3OperatorTranslator.java | 89 +- .../cel/verifier/CelZ3StructTranslator.java | 560 +++++++++ .../cel/verifier/CelZ3TranslationContext.java | 148 +++ .../verifier/CelPolicyVerifierImplTest.java | 29 +- .../cel/verifier/CelVerifierZ3ImplTest.java | 232 +++- .../verifier/tools/CelVerifierReplTest.java | 2 +- 15 files changed, 1951 insertions(+), 1393 deletions(-) create mode 100644 verifier/src/main/java/dev/cel/verifier/CelWitness.java create mode 100644 verifier/src/main/java/dev/cel/verifier/CelZ3ComprehensionTranslator.java create mode 100644 verifier/src/main/java/dev/cel/verifier/CelZ3StructTranslator.java create mode 100644 verifier/src/main/java/dev/cel/verifier/CelZ3TranslationContext.java diff --git a/verifier/README.md b/verifier/README.md index d0c054485..7d9d7f899 100644 --- a/verifier/README.md +++ b/verifier/README.md @@ -224,8 +224,8 @@ public class PolicyVerifierExample { System.out.println(result.message()); // Output: // Equivalence violation detected. Counterexample input: - // country = "a" // role = "editor" + // country = "a" // port = 443 break; case INCONCLUSIVE: @@ -241,7 +241,8 @@ public class PolicyVerifierExample { When checking whether an expression is satisfiable using `isSatisfiable`, the verifier returns `VERIFIED` if there exists at least one input combination where the expression evaluates to `true`. Furthermore, `result.message()` -provides concrete satisfying model assignments (witness/test case generation). +provides concrete satisfying model assignments (witness/test case generation), +and `result.witness()` exposes them as CEL runtime values. ```java import dev.cel.common.CelAbstractSyntaxTree; diff --git a/verifier/src/main/java/dev/cel/verifier/BUILD.bazel b/verifier/src/main/java/dev/cel/verifier/BUILD.bazel index d48faf98f..2d2549456 100644 --- a/verifier/src/main/java/dev/cel/verifier/BUILD.bazel +++ b/verifier/src/main/java/dev/cel/verifier/BUILD.bazel @@ -15,6 +15,7 @@ java_library( "CelVerificationResult.java", "CelVerifier.java", "CelVerifierBuilder.java", + "CelWitness.java", ], tags = [ ], @@ -23,6 +24,7 @@ java_library( "//common:cel_ast", "//common/types:type_providers", "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", ], ) @@ -160,10 +162,13 @@ java_library( "CelAstAlphaHasher.java", "CelAstToZ3Translator.java", "CelVerifierZ3Impl.java", + "CelZ3ComprehensionTranslator.java", "CelZ3CounterexampleGenerator.java", "CelZ3ExtensionalityAxioms.java", "CelZ3FunctionRegistry.java", "CelZ3OperatorTranslator.java", + "CelZ3StructTranslator.java", + "CelZ3TranslationContext.java", "CelZ3TypeConstraintGenerator.java", "TranslatedValue.java", ], @@ -183,10 +188,13 @@ java_library( "//common/ast", "//common/ast:cel_block", "//common/internal:cel_descriptor_pools", + "//common/internal:proto_time_utils", "//common/internal:well_known_proto", "//common/types", "//common/types:cel_types", "//common/types:type_providers", + "//common/values", + "//common/values:cel_byte_string", "//optimizer", "//optimizer:optimization_exception", "//optimizer:optimizer_builder", diff --git a/verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java b/verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java index 20050cd82..db344960b 100644 --- a/verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java +++ b/verifier/src/main/java/dev/cel/verifier/CelAstToZ3Translator.java @@ -18,15 +18,11 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Streams; -import com.microsoft.z3.ArithExpr; import com.microsoft.z3.ArrayExpr; import com.microsoft.z3.BoolExpr; import com.microsoft.z3.Context; import com.microsoft.z3.Expr; -import com.microsoft.z3.FPExpr; import com.microsoft.z3.FuncDecl; -import com.microsoft.z3.IntExpr; import com.microsoft.z3.Quantifier; import com.microsoft.z3.SeqExpr; import com.microsoft.z3.Sort; @@ -35,20 +31,11 @@ import dev.cel.common.ast.CelBlock; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExpr; -import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.CelList; import dev.cel.common.ast.CelExpr.ExprKind; import dev.cel.common.types.CelKind; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; -import dev.cel.common.types.ListType; -import dev.cel.common.types.MapType; -import dev.cel.common.types.NullableType; -import dev.cel.common.types.OptionalType; -import dev.cel.common.types.SimpleType; -import dev.cel.common.types.StructType; -import dev.cel.common.types.StructTypeReference; import dev.cel.common.types.TypeType; import java.util.ArrayList; import java.util.Arrays; @@ -58,14 +45,13 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.Supplier; /** * Internal translator from CEL AST to Z3 SMT expressions using a 4-valued logic tagged union. * *

Lifetime & Mutability: This translator is stateful and highly mutable. It accumulates - * type constraints, loop variables (via its symbol table), and uninterpreted functions (via field - * caches) during AST traversal. + * constraints and symbol bindings in a shared {@link CelZ3TranslationContext}, and literal caches + * in itself and its delegate translators. * *