// Copyright 2025 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. // Package env provides a representation of a CEL environment. package env import ( "errors" "fmt" "math" "strconv" "strings" "github.com/google/cel-go/common/decls" "github.com/google/cel-go/common/types" ) // NewConfig creates an instance of a YAML serializable CEL environment configuration. func NewConfig(name string) *Config { return &Config{ Name: name, } } // Config represents a serializable form of the CEL environment configuration. // // Note: custom validations, feature flags, and performance tuning parameters are not (yet) // considered part of the core CEL environment configuration and should be managed separately // until a common convention for such settings is developed. type Config struct { Name string `yaml:"name,omitempty"` Description string `yaml:"description,omitempty"` Container string `yaml:"container,omitempty"` Imports []*Import `yaml:"imports,omitempty"` StdLib *LibrarySubset `yaml:"stdlib,omitempty"` Extensions []*Extension `yaml:"extensions,omitempty"` ContextVariable *ContextVariable `yaml:"context_variable,omitempty"` Variables []*Variable `yaml:"variables,omitempty"` Functions []*Function `yaml:"functions,omitempty"` Validators []*Validator `yaml:"validators,omitempty"` Features []*Feature `yaml:"features,omitempty"` } // Validate validates the whole configuration is well-formed. func (c *Config) Validate() error { if c == nil { return nil } var errs []error for _, imp := range c.Imports { if err := imp.Validate(); err != nil { errs = append(errs, err) } } if err := c.StdLib.Validate(); err != nil { errs = append(errs, err) } for _, ext := range c.Extensions { if err := ext.Validate(); err != nil { errs = append(errs, err) } } if err := c.ContextVariable.Validate(); err != nil { errs = append(errs, err) } if c.ContextVariable != nil && len(c.Variables) != 0 { errs = append(errs, errors.New("invalid config: either context variable or variables may be set, but not both")) } for _, v := range c.Variables { if err := v.Validate(); err != nil { errs = append(errs, err) } } for _, fn := range c.Functions { if err := fn.Validate(); err != nil { errs = append(errs, err) } } for _, feat := range c.Features { if err := feat.Validate(); err != nil { errs = append(errs, err) } } for _, val := range c.Validators { if err := val.Validate(); err != nil { errs = append(errs, err) } } return errors.Join(errs...) } // SetContainer configures the container name for this configuration. func (c *Config) SetContainer(container string) *Config { c.Container = container return c } // AddVariableDecls adds one or more variables to the config, converting them to serializable values first. // // VariableDecl inputs are expected to be well-formed. func (c *Config) AddVariableDecls(vars ...*decls.VariableDecl) *Config { convVars := make([]*Variable, len(vars)) for i, v := range vars { if v == nil { continue } cv := NewVariable(v.Name(), SerializeTypeDesc(v.Type())) cv.Description = v.Description() convVars[i] = cv } return c.AddVariables(convVars...) } // AddVariables adds one or more vairables to the config. func (c *Config) AddVariables(vars ...*Variable) *Config { c.Variables = append(c.Variables, vars...) return c } // SetContextVariable configures the ContextVariable for this configuration. func (c *Config) SetContextVariable(ctx *ContextVariable) *Config { c.ContextVariable = ctx return c } // AddFunctionDecls adds one or more functions to the config, converting them to serializable values first. // // FunctionDecl inputs are expected to be well-formed. func (c *Config) AddFunctionDecls(funcs ...*decls.FunctionDecl) *Config { convFuncs := make([]*Function, len(funcs)) for i, fn := range funcs { if fn == nil { continue } overloads := make([]*Overload, 0, len(fn.OverloadDecls())) for _, o := range fn.OverloadDecls() { overloadID := o.ID() args := make([]*TypeDesc, 0, len(o.ArgTypes())) for _, a := range o.ArgTypes() { args = append(args, SerializeTypeDesc(a)) } ret := SerializeTypeDesc(o.ResultType()) var overload *Overload if o.IsMemberFunction() { overload = NewMemberOverload(overloadID, args[0], args[1:], ret) } else { overload = NewOverload(overloadID, args, ret) } exampleCount := len(o.Examples()) if exampleCount > 0 { overload.Examples = o.Examples() } overloads = append(overloads, overload) } cf := NewFunction(fn.Name(), overloads...) cf.Description = fn.Description() convFuncs[i] = cf } return c.AddFunctions(convFuncs...) } // AddFunctions adds one or more functions to the config. func (c *Config) AddFunctions(funcs ...*Function) *Config { c.Functions = append(c.Functions, funcs...) return c } // SetStdLib configures the LibrarySubset for the standard library. func (c *Config) SetStdLib(subset *LibrarySubset) *Config { c.StdLib = subset return c } // AddImports appends a set of imports to the config. func (c *Config) AddImports(imps ...*Import) *Config { c.Imports = append(c.Imports, imps...) return c } // AddExtensions appends a set of extensions to the config. func (c *Config) AddExtensions(exts ...*Extension) *Config { c.Extensions = append(c.Extensions, exts...) return c } // AddValidators appends one or more validators to the config. func (c *Config) AddValidators(vals ...*Validator) *Config { c.Validators = append(c.Validators, vals...) return c } // AddFeatures appends one or more features to the config. func (c *Config) AddFeatures(feats ...*Feature) *Config { c.Features = append(c.Features, feats...) return c } // NewImport returns a serializable import value from the qualified type name. func NewImport(name string) *Import { return &Import{Name: name} } // Import represents a type name that will be appreviated by its simple name using // the cel.Abbrevs() option. type Import struct { Name string `yaml:"name"` } // Validate validates the import configuration is well-formed. func (imp *Import) Validate() error { if imp == nil { return errors.New("invalid import: nil") } if imp.Name == "" { return errors.New("invalid import: missing type name") } return nil } // NewVariable returns a serializable variable from a name and type definition func NewVariable(name string, t *TypeDesc) *Variable { return NewVariableWithDoc(name, t, "") } // NewVariableWithDoc returns a serializable variable from a name, type definition, and doc string. func NewVariableWithDoc(name string, t *TypeDesc, doc string) *Variable { return &Variable{Name: name, TypeDesc: t, Description: doc} } // Variable represents a typed variable declaration which will be published via the // cel.VariableDecls() option. type Variable struct { Name string `yaml:"name"` Description string `yaml:"description,omitempty"` // Type represents the type declaration for the variable. // // Deprecated: use the embedded *TypeDesc fields directly. Type *TypeDesc `yaml:"type,omitempty"` // TypeDesc is an embedded set of fields allowing for the specification of the Variable type. *TypeDesc `yaml:",inline"` } // Validate validates the variable configuration is well-formed. func (v *Variable) Validate() error { if v == nil { return errors.New("invalid variable: nil") } if v.Name == "" { return errors.New("invalid variable: missing variable name") } if err := v.GetType().Validate(); err != nil { return fmt.Errorf("invalid variable %q: %w", v.Name, err) } return nil } // GetType returns the variable type description. // // Note, if both the embedded TypeDesc and the field Type are non-nil, the embedded TypeDesc will // take precedence. func (v *Variable) GetType() *TypeDesc { if v == nil { return nil } if v.TypeDesc != nil { return v.TypeDesc } if v.Type != nil { return v.Type } return nil } // AsCELVariable converts the serializable form of the Variable into a CEL environment declaration. func (v *Variable) AsCELVariable(tp types.Provider) (*decls.VariableDecl, error) { if err := v.Validate(); err != nil { return nil, err } t, err := v.GetType().AsCELType(tp) if err != nil { return nil, fmt.Errorf("invalid variable %q: %w", v.Name, err) } return decls.NewVariableWithDoc(v.Name, t, v.Description), nil } // NewContextVariable returns a serializable context variable with a specific type name. func NewContextVariable(typeName string) *ContextVariable { return &ContextVariable{TypeName: typeName} } // ContextVariable represents a structured message whose fields are to be treated as the top-level // variable identifiers within CEL expressions. type ContextVariable struct { // TypeName represents the fully qualified typename of the context variable. // Currently, only protobuf types are supported. TypeName string `yaml:"type_name"` } // Validate validates the context-variable configuration is well-formed. func (ctx *ContextVariable) Validate() error { if ctx == nil { return nil } if ctx.TypeName == "" { return errors.New("invalid context variable: missing type name") } return nil } // NewFunction creates a serializable function and overload set. func NewFunction(name string, overloads ...*Overload) *Function { return &Function{Name: name, Overloads: overloads} } // NewFunctionWithDoc creates a serializable function and overload set. func NewFunctionWithDoc(name, doc string, overloads ...*Overload) *Function { return &Function{Name: name, Description: doc, Overloads: overloads} } // Function represents the serializable format of a function and its overloads. type Function struct { Name string `yaml:"name"` Description string `yaml:"description,omitempty"` Overloads []*Overload `yaml:"overloads,omitempty"` } // Validate validates the function configuration is well-formed. func (fn *Function) Validate() error { if fn == nil { return errors.New("invalid function: nil") } if fn.Name == "" { return errors.New("invalid function: missing function name") } if len(fn.Overloads) == 0 { return fmt.Errorf("invalid function %q: missing overloads", fn.Name) } var errs []error for _, o := range fn.Overloads { if err := o.Validate(); err != nil { errs = append(errs, fmt.Errorf("invalid function %q: %w", fn.Name, err)) } } return errors.Join(errs...) } // AsCELFunction converts the serializable form of the Function into CEL environment declaration. func (fn *Function) AsCELFunction(tp types.Provider) (*decls.FunctionDecl, error) { if err := fn.Validate(); err != nil { return nil, err } opts := make([]decls.FunctionOpt, 0, len(fn.Overloads)+1) for _, o := range fn.Overloads { opt, err := o.AsFunctionOption(tp) opts = append(opts, opt) if err != nil { return nil, fmt.Errorf("invalid function %q: %w", fn.Name, err) } } if len(fn.Description) != 0 { opts = append(opts, decls.FunctionDocs(fn.Description)) } return decls.NewFunction(fn.Name, opts...) } // NewOverload returns a new serializable representation of a global overload. func NewOverload(id string, args []*TypeDesc, ret *TypeDesc, examples ...string) *Overload { return &Overload{ID: id, Args: args, Return: ret, Examples: examples} } // NewMemberOverload returns a new serializable representation of a member (receiver) overload. func NewMemberOverload(id string, target *TypeDesc, args []*TypeDesc, ret *TypeDesc, examples ...string) *Overload { return &Overload{ID: id, Target: target, Args: args, Return: ret, Examples: examples} } // Overload represents the serializable format of a function overload. type Overload struct { ID string `yaml:"id"` Examples []string `yaml:"examples,omitempty"` Target *TypeDesc `yaml:"target,omitempty"` Args []*TypeDesc `yaml:"args,omitempty"` Return *TypeDesc `yaml:"return,omitempty"` } // Validate validates the overload configuration is well-formed. func (od *Overload) Validate() error { if od == nil { return errors.New("invalid overload: nil") } if od.ID == "" { return errors.New("invalid overload: missing overload id") } var errs []error if od.Target != nil { if err := od.Target.Validate(); err != nil { errs = append(errs, fmt.Errorf("invalid overload %q target: %w", od.ID, err)) } } for i, arg := range od.Args { if err := arg.Validate(); err != nil { errs = append(errs, fmt.Errorf("invalid overload %q arg[%d]: %w", od.ID, i, err)) } } if err := od.Return.Validate(); err != nil { errs = append(errs, fmt.Errorf("invalid overload %q return: %w", od.ID, err)) } return errors.Join(errs...) } // AsFunctionOption converts the serializable form of the Overload into a function declaration option. func (od *Overload) AsFunctionOption(tp types.Provider) (decls.FunctionOpt, error) { if err := od.Validate(); err != nil { return nil, err } args := make([]*types.Type, len(od.Args)) var err error var errs []error for i, a := range od.Args { args[i], err = a.AsCELType(tp) if err != nil { errs = append(errs, err) } } result, err := od.Return.AsCELType(tp) if err != nil { errs = append(errs, err) } if od.Target != nil { t, err := od.Target.AsCELType(tp) if err != nil { return nil, errors.Join(append(errs, err)...) } args = append([]*types.Type{t}, args...) return decls.MemberOverload(od.ID, args, result), nil } if len(errs) != 0 { return nil, errors.Join(errs...) } return decls.Overload(od.ID, args, result, decls.OverloadExamples(od.Examples...)), nil } // NewExtension creates a serializable Extension from a name and version string. func NewExtension(name string, version uint32) *Extension { versionString := "latest" if version < math.MaxUint32 { versionString = strconv.FormatUint(uint64(version), 10) } return &Extension{ Name: name, Version: versionString, } } // Extension represents a named and optionally versioned extension library configured in the environment. type Extension struct { // Name is either the LibraryName() or some short-hand simple identifier which is understood by the config-handler. Name string `yaml:"name"` // Version may either be an unsigned long value or the string 'latest'. If empty, the value is treated as '0'. Version string `yaml:"version,omitempty"` } // Validate validates the extension configuration is well-formed. func (e *Extension) Validate() error { _, err := e.VersionNumber() return err } // VersionNumber returns the parsed version string, or an error if the version cannot be parsed. func (e *Extension) VersionNumber() (uint32, error) { if e == nil { return 0, fmt.Errorf("invalid extension: nil") } if e.Name == "" { return 0, fmt.Errorf("invalid extension: missing name") } if e.Version == "latest" { return math.MaxUint32, nil } if e.Version == "" { return 0, nil } ver, err := strconv.ParseUint(e.Version, 10, 32) if err != nil { return 0, fmt.Errorf("invalid extension %q version: %w", e.Name, err) } return uint32(ver), nil } // NewLibrarySubset returns an empty library subsetting config which permits all library features. func NewLibrarySubset() *LibrarySubset { return &LibrarySubset{} } // LibrarySubset indicates a subset of the macros and function supported by a subsettable library. type LibrarySubset struct { // Disabled indicates whether the library has been disabled, typically only used for // default-enabled libraries like stdlib. Disabled bool `yaml:"disabled,omitempty"` // DisableMacros disables macros for the given library. DisableMacros bool `yaml:"disable_macros,omitempty"` // IncludeMacros specifies a set of macro function names to include in the subset. IncludeMacros []string `yaml:"include_macros,omitempty"` // ExcludeMacros specifies a set of macro function names to exclude from the subset. // Note: if IncludeMacros is non-empty, then ExcludeFunctions is ignored. ExcludeMacros []string `yaml:"exclude_macros,omitempty"` // IncludeFunctions specifies a set of functions to include in the subset. // // Note: the overloads specified in the subset need only specify their ID. // Note: if IncludeFunctions is non-empty, then ExcludeFunctions is ignored. IncludeFunctions []*Function `yaml:"include_functions,omitempty"` // ExcludeFunctions specifies the set of functions to exclude from the subset. // // Note: the overloads specified in the subset need only specify their ID. ExcludeFunctions []*Function `yaml:"exclude_functions,omitempty"` } // Validate validates the library configuration is well-formed. // // For example, setting both the IncludeMacros and ExcludeMacros together could be confusing // and create a broken expectation, likewise for IncludeFunctions and ExcludeFunctions. func (lib *LibrarySubset) Validate() error { if lib == nil { return nil } var errs []error if len(lib.IncludeMacros) != 0 && len(lib.ExcludeMacros) != 0 { errs = append(errs, errors.New("invalid subset: cannot both include and exclude macros")) } if len(lib.IncludeFunctions) != 0 && len(lib.ExcludeFunctions) != 0 { errs = append(errs, errors.New("invalid subset: cannot both include and exclude functions")) } return errors.Join(errs...) } // SubsetFunction produces a function declaration which matches the supported subset, or nil // if the function is not supported by the LibrarySubset. // // For IncludeFunctions, if the function does not specify a set of overloads to include, the // whole function definition is included. If overloads are set, then a new function which // includes only the specified overloads is produced. // // For ExcludeFunctions, if the function does not specify a set of overloads to exclude, the // whole function definition is excluded. If overloads are set, then a new function which // includes only the permitted overloads is produced. func (lib *LibrarySubset) SubsetFunction(fn *decls.FunctionDecl) (*decls.FunctionDecl, bool) { // When lib is null, it should indicate that all values are included in the subset. if lib == nil { return fn, true } if lib.Disabled { return nil, false } if len(lib.IncludeFunctions) != 0 { for _, include := range lib.IncludeFunctions { if include.Name != fn.Name() { continue } if len(include.Overloads) == 0 { return fn, true } overloadIDs := make([]string, len(include.Overloads)) for i, o := range include.Overloads { overloadIDs[i] = o.ID } return fn.Subset(decls.IncludeOverloads(overloadIDs...)), true } return nil, false } if len(lib.ExcludeFunctions) != 0 { for _, exclude := range lib.ExcludeFunctions { if exclude.Name != fn.Name() { continue } if len(exclude.Overloads) == 0 { return nil, false } overloadIDs := make([]string, len(exclude.Overloads)) for i, o := range exclude.Overloads { overloadIDs[i] = o.ID } return fn.Subset(decls.ExcludeOverloads(overloadIDs...)), true } return fn, true } return fn, true } // SubsetMacro indicates whether the macro function should be included in the library subset. func (lib *LibrarySubset) SubsetMacro(macroFunction string) bool { // When lib is null, it should indicate that all values are included in the subset. if lib == nil { return true } if lib.Disabled || lib.DisableMacros { return false } if len(lib.IncludeMacros) != 0 { for _, name := range lib.IncludeMacros { if name == macroFunction { return true } } return false } if len(lib.ExcludeMacros) != 0 { for _, name := range lib.ExcludeMacros { if name == macroFunction { return false } } return true } return true } // SetDisabled disables or enables the library. func (lib *LibrarySubset) SetDisabled(value bool) *LibrarySubset { lib.Disabled = value return lib } // SetDisableMacros disables the macros for the library. func (lib *LibrarySubset) SetDisableMacros(value bool) *LibrarySubset { lib.DisableMacros = value return lib } // AddIncludedMacros allow-lists one or more macros by function name. // // Note, this option will override any excluded macros. func (lib *LibrarySubset) AddIncludedMacros(macros ...string) *LibrarySubset { lib.IncludeMacros = append(lib.IncludeMacros, macros...) return lib } // AddExcludedMacros deny-lists one or more macros by function name. func (lib *LibrarySubset) AddExcludedMacros(macros ...string) *LibrarySubset { lib.ExcludeMacros = append(lib.ExcludeMacros, macros...) return lib } // AddIncludedFunctions allow-lists one or more functions from the subset. // // Note, this option will override any excluded functions. func (lib *LibrarySubset) AddIncludedFunctions(funcs ...*Function) *LibrarySubset { lib.IncludeFunctions = append(lib.IncludeFunctions, funcs...) return lib } // AddExcludedFunctions deny-lists one or more functions from the subset. func (lib *LibrarySubset) AddExcludedFunctions(funcs ...*Function) *LibrarySubset { lib.ExcludeFunctions = append(lib.ExcludeFunctions, funcs...) return lib } // NewValidator returns a named Validator instance. func NewValidator(name string) *Validator { return &Validator{Name: name} } // Validator represents a named validator with an optional map-based configuration object. // // Note: the map-keys must directly correspond to the internal representation of the original // validator, and should only use primitive scalar types as values at this time. type Validator struct { Name string `yaml:"name"` Config map[string]any `yaml:"config,omitempty"` } // Validate validates the configuration of the validator object. func (v *Validator) Validate() error { if v == nil { return errors.New("invalid validator: nil") } if v.Name == "" { return errors.New("invalid validator: missing name") } return nil } // SetConfig sets the set of map key-value pairs associated with this validator's configuration. func (v *Validator) SetConfig(config map[string]any) *Validator { v.Config = config return v } // ConfigValue retrieves the value associated with the config key name, if one exists. func (v *Validator) ConfigValue(name string) (any, bool) { if v == nil { return nil, false } value, found := v.Config[name] return value, found } // NewFeature creates a new feature flag with a boolean enablement flag. func NewFeature(name string, enabled bool) *Feature { return &Feature{Name: name, Enabled: enabled} } // Feature represents a named boolean feature flag supported by CEL. type Feature struct { Name string `yaml:"name"` Enabled bool `yaml:"enabled"` } // Validate validates whether the feature is well-configured. func (feat *Feature) Validate() error { if feat == nil { return errors.New("invalid feature: nil") } if feat.Name == "" { return errors.New("invalid feature: missing name") } return nil } // NewTypeDesc describes a simple or complex type with parameters. func NewTypeDesc(typeName string, params ...*TypeDesc) *TypeDesc { return &TypeDesc{TypeName: typeName, Params: params} } // NewTypeParam describe a type-param type. func NewTypeParam(paramName string) *TypeDesc { return &TypeDesc{TypeName: paramName, IsTypeParam: true} } // TypeDesc represents the serializable format of a CEL *types.Type value. type TypeDesc struct { TypeName string `yaml:"type_name"` Params []*TypeDesc `yaml:"params,omitempty"` IsTypeParam bool `yaml:"is_type_param,omitempty"` } // String implements the strings.Stringer interface method. func (td *TypeDesc) String() string { ps := make([]string, len(td.Params)) for i, p := range td.Params { ps[i] = p.String() } typeName := td.TypeName if len(ps) != 0 { typeName = fmt.Sprintf("%s(%s)", typeName, strings.Join(ps, ",")) } return typeName } // Validate validates the type configuration is well-formed. func (td *TypeDesc) Validate() error { if td == nil { return errors.New("invalid type: nil") } if td.TypeName == "" { return errors.New("invalid type: missing type name") } if td.IsTypeParam && len(td.Params) != 0 { return errors.New("invalid type: param type cannot have parameters") } switch td.TypeName { case "list": if len(td.Params) != 1 { return fmt.Errorf("invalid type: list expects 1 parameter, got %d", len(td.Params)) } return td.Params[0].Validate() case "map": if len(td.Params) != 2 { return fmt.Errorf("invalid type: map expects 2 parameters, got %d", len(td.Params)) } if err := td.Params[0].Validate(); err != nil { return err } if err := td.Params[1].Validate(); err != nil { return err } case "optional_type": if len(td.Params) != 1 { return fmt.Errorf("invalid type: optional_type expects 1 parameter, got %d", len(td.Params)) } return td.Params[0].Validate() default: } return nil } // AsCELType converts the serializable object to a *types.Type value. func (td *TypeDesc) AsCELType(tp types.Provider) (*types.Type, error) { err := td.Validate() if err != nil { return nil, err } switch td.TypeName { case "dyn": return types.DynType, nil case "map": kt, err := td.Params[0].AsCELType(tp) if err != nil { return nil, err } vt, err := td.Params[1].AsCELType(tp) if err != nil { return nil, err } return types.NewMapType(kt, vt), nil case "list": et, err := td.Params[0].AsCELType(tp) if err != nil { return nil, err } return types.NewListType(et), nil case "optional_type": et, err := td.Params[0].AsCELType(tp) if err != nil { return nil, err } return types.NewOptionalType(et), nil default: if td.IsTypeParam { return types.NewTypeParamType(td.TypeName), nil } if msgType, found := tp.FindStructType(td.TypeName); found { // First parameter is the type name. return msgType.Parameters()[0], nil } t, found := tp.FindIdent(td.TypeName) if !found { return nil, fmt.Errorf("undefined type name: %q", td.TypeName) } _, ok := t.(*types.Type) if ok && len(td.Params) == 0 { return t.(*types.Type), nil } params := make([]*types.Type, len(td.Params)) for i, p := range td.Params { params[i], err = p.AsCELType(tp) if err != nil { return nil, err } } return types.NewOpaqueType(td.TypeName, params...), nil } } // SerializeTypeDesc converts a CEL native *types.Type to a serializable TypeDesc. func SerializeTypeDesc(t *types.Type) *TypeDesc { typeName := t.TypeName() if t.Kind() == types.TypeParamKind { return NewTypeParam(typeName) } if t != types.NullType && t.IsAssignableType(types.NullType) { if wrapperTypeName, found := wrapperTypes[t.Kind()]; found { return NewTypeDesc(wrapperTypeName) } } var params []*TypeDesc for _, p := range t.Parameters() { params = append(params, SerializeTypeDesc(p)) } return NewTypeDesc(typeName, params...) } var wrapperTypes = map[types.Kind]string{ types.BoolKind: "google.protobuf.BoolValue", types.BytesKind: "google.protobuf.BytesValue", types.DoubleKind: "google.protobuf.DoubleValue", types.IntKind: "google.protobuf.Int64Value", types.StringKind: "google.protobuf.StringValue", types.UintKind: "google.protobuf.UInt64Value", }