Skip to content

Commit

Permalink
Add WithAllowUnknownFields option
Browse files Browse the repository at this point in the history
  • Loading branch information
jchadwick-buf committed Sep 17, 2024
1 parent 4bf8570 commit 74f0326
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 8 deletions.
14 changes: 8 additions & 6 deletions internal/constraints/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,25 @@ func (c *Cache) Build(
fieldDesc protoreflect.FieldDescriptor,
fieldConstraints *validate.FieldConstraints,
extensionTypeResolver protoregistry.ExtensionTypeResolver,
allowUnknownFields bool,
forItems bool,
) (set expression.ProgramSet, err error) {
constraints, done, err := c.resolveConstraints(
fieldDesc,
fieldConstraints,
extensionTypeResolver,
forItems,
)
if done {
return nil, err
}

if err = reparseUnrecognized(extensionTypeResolver, constraints); err != nil {
return nil, fmt.Errorf("error reparsing message: %w", err)
}
if !allowUnknownFields && len(constraints.GetUnknown()) > 0 {
return nil, errors.NewCompilationErrorf("unknown rules in %s", constraints.Descriptor().FullName())
}

env, err = c.prepareEnvironment(env, fieldDesc, constraints, forItems)
if err != nil {
return nil, err
Expand Down Expand Up @@ -103,7 +110,6 @@ func (c *Cache) Build(
func (c *Cache) resolveConstraints(
fieldDesc protoreflect.FieldDescriptor,
fieldConstraints *validate.FieldConstraints,
extensionTypeResolver protoregistry.ExtensionTypeResolver,
forItems bool,
) (rules protoreflect.Message, done bool, err error) {
constraints := fieldConstraints.ProtoReflect()
Expand All @@ -124,10 +130,6 @@ func (c *Cache) resolveConstraints(
return nil, true, nil
}
rules = constraints.Get(setOneof).Message()
// Reparse unrecognized fields so that we get dynamic extensions.
if err = reparseUnrecognized(extensionTypeResolver, rules); err != nil {
return nil, false, fmt.Errorf("error reparsing message: %w", err)
}
return rules, false, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/constraints/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func TestCache_BuildStandardConstraints(t *testing.T) {
require.NoError(t, err)
c := NewCache()

set, err := c.Build(env, test.desc, test.cons, protoregistry.GlobalTypes, test.forItems)
set, err := c.Build(env, test.desc, test.cons, protoregistry.GlobalTypes, false, test.forItems)
if test.exErr {
assert.Error(t, err)
} else {
Expand Down
4 changes: 4 additions & 0 deletions internal/evaluator/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Builder struct {
constraints constraints.Cache
resolver StandardConstraintResolver
extensionTypeResolver protoregistry.ExtensionTypeResolver
allowUnknownFields bool
Load func(desc protoreflect.MessageDescriptor) MessageEvaluator
}

Expand All @@ -53,13 +54,15 @@ func NewBuilder(
disableLazy bool,
res StandardConstraintResolver,
extensionTypeResolver protoregistry.ExtensionTypeResolver,
allowUnknownFields bool,
seedDesc ...protoreflect.MessageDescriptor,
) *Builder {
bldr := &Builder{
env: env,
constraints: constraints.NewCache(),
resolver: res,
extensionTypeResolver: extensionTypeResolver,
allowUnknownFields: allowUnknownFields,
}

if disableLazy {
Expand Down Expand Up @@ -362,6 +365,7 @@ func (bldr *Builder) processStandardConstraints(
fdesc,
constraints,
bldr.extensionTypeResolver,
bldr.allowUnknownFields,
forItems,
)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/evaluator/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestBuildCache(t *testing.T) {
env, err := celext.DefaultEnv(true)
require.NoError(t, err, "failed to construct CEL environment")
bldr := NewBuilder(
env, false, resolver.DefaultResolver{}, protoregistry.GlobalTypes,
env, false, resolver.DefaultResolver{}, protoregistry.GlobalTypes, false,
)
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
Expand Down
15 changes: 15 additions & 0 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func New(options ...ValidatorOption) (*Validator, error) {
cfg.disableLazy,
cfg.resolver,
cfg.extensionTypeResolver,
cfg.allowUnknownFields,
cfg.desc...,
)

Expand Down Expand Up @@ -110,6 +111,7 @@ type config struct {
desc []protoreflect.MessageDescriptor
resolver StandardConstraintResolver
extensionTypeResolver protoregistry.ExtensionTypeResolver
allowUnknownFields bool
}

// A ValidatorOption modifies the default configuration of a Validator. See the
Expand Down Expand Up @@ -198,3 +200,16 @@ func WithExtensionTypeResolver(extensionTypeResolver protoregistry.ExtensionType
c.extensionTypeResolver = extensionTypeResolver
}
}

// WithAllowUnknownFields specifies if the presence of unknown field constraints
// should cause compilation to fail with an error. When set to false, an unknown
// field will simply be ignored, which will cause constraints to silently not be
// applied. This condition may occur if a predefined constraint definition isn't
// present in the extension type resolver, or when passing dynamic messages with
// standard constraints defined in a newer version of protovalidate. The default
// value is false, to prevent silently-incorrect validation from occurring.
func WithAllowUnknownFields(allowUnknownFields bool) ValidatorOption {
return func(c *config) {
c.allowUnknownFields = allowUnknownFields
}
}

0 comments on commit 74f0326

Please sign in to comment.