From bfd0d4e9046aea8e28baf63fda4cba74a2d4375a Mon Sep 17 00:00:00 2001 From: Fred Zhang Date: Sat, 10 Jun 2023 00:34:47 -0700 Subject: [PATCH 1/3] Validate directive arguments --- validator/schema.go | 16 ++++++++++++++-- validator/schema_test.yml | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/validator/schema.go b/validator/schema.go index e7c661d1..a11d178c 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -359,11 +359,12 @@ func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLo if currentDirective != nil && dir.Name == currentDirective.Name { return gqlerror.ErrorPosf(dir.Position, "Directive %s cannot refer to itself.", currentDirective.Name) } - if schema.Directives[dir.Name] == nil { + dirDefinition := schema.Directives[dir.Name] + if dirDefinition == nil { return gqlerror.ErrorPosf(dir.Position, "Undefined directive %s.", dir.Name) } validKind := false - for _, dirLocation := range schema.Directives[dir.Name].Locations { + for _, dirLocation := range dirDefinition.Locations { if dirLocation == location { validKind = true break @@ -372,6 +373,17 @@ func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLo if !validKind { return gqlerror.ErrorPosf(dir.Position, "Directive %s is not applicable on %s.", dir.Name, location) } + possibleArgsList := dirDefinition.Arguments + for _, arg := range dir.Arguments { + if possibleArgsList.ForName(arg.Name) == nil { + return gqlerror.ErrorPosf(arg.Position, "Undefined argument %s for directive %s.", arg.Name, dir.Name) + } + } + for _, schemaArg := range possibleArgsList { + if schemaArg.Type.NonNull && dir.Arguments.ForName(schemaArg.Name) == nil { + return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name) + } + } dir.Definition = schema.Directives[dir.Name] } return nil diff --git a/validator/schema_test.yml b/validator/schema_test.yml index 7034a469..7acdd7ae 100644 --- a/validator/schema_test.yml +++ b/validator/schema_test.yml @@ -604,6 +604,23 @@ directives: type P { name: String @testField } interface I { id: ID @testField } + - name: Invalid directive argument not allowed + input: | + directive @foo(bla: Int!) on FIELD_DEFINITION + type P {f: Int @foo(foobla: 11)} + + error: + message: 'Undefined argument foobla for directive foo.' + locations: [{line: 2, column: 21}] + + - name: Nil value not allowed for non-null types + input: | + directive @foo(bla: Int!) on FIELD_DEFINITION + type P {f: Int @foo } + + error: + message: 'Argument bla for directive foo cannot be null.' + locations: [{line: 2, column: 17}] entry points: - name: multiple schema entry points From 55c965a14e27f0af0aea26036aa33c50f4d426ba Mon Sep 17 00:00:00 2001 From: Fred Zhang Date: Sat, 10 Jun 2023 00:45:41 -0700 Subject: [PATCH 2/3] nits clean --- validator/schema.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validator/schema.go b/validator/schema.go index a11d178c..bd97fe9d 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -373,13 +373,12 @@ func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLo if !validKind { return gqlerror.ErrorPosf(dir.Position, "Directive %s is not applicable on %s.", dir.Name, location) } - possibleArgsList := dirDefinition.Arguments for _, arg := range dir.Arguments { - if possibleArgsList.ForName(arg.Name) == nil { + if dirDefinition.Arguments.ForName(arg.Name) == nil { return gqlerror.ErrorPosf(arg.Position, "Undefined argument %s for directive %s.", arg.Name, dir.Name) } } - for _, schemaArg := range possibleArgsList { + for _, schemaArg := range dirDefinition.Arguments { if schemaArg.Type.NonNull && dir.Arguments.ForName(schemaArg.Name) == nil { return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name) } From 83105de509f68c280dd5b5c1c2ccc45965af70db Mon Sep 17 00:00:00 2001 From: Fred Zhang Date: Sat, 10 Jun 2023 00:53:56 -0700 Subject: [PATCH 3/3] Check for pass in null explicitly --- validator/schema.go | 6 ++++-- validator/schema_test.yml | 11 ++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/validator/schema.go b/validator/schema.go index bd97fe9d..fdfabf0b 100644 --- a/validator/schema.go +++ b/validator/schema.go @@ -379,8 +379,10 @@ func validateDirectives(schema *Schema, dirs DirectiveList, location DirectiveLo } } for _, schemaArg := range dirDefinition.Arguments { - if schemaArg.Type.NonNull && dir.Arguments.ForName(schemaArg.Name) == nil { - return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name) + if schemaArg.Type.NonNull { + if arg := dir.Arguments.ForName(schemaArg.Name); arg == nil || arg.Value.Kind == NullValue { + return gqlerror.ErrorPosf(dir.Position, "Argument %s for directive %s cannot be null.", schemaArg.Name, dir.Name) + } } } dir.Definition = schema.Directives[dir.Name] diff --git a/validator/schema_test.yml b/validator/schema_test.yml index 7acdd7ae..2a9feed3 100644 --- a/validator/schema_test.yml +++ b/validator/schema_test.yml @@ -613,7 +613,7 @@ directives: message: 'Undefined argument foobla for directive foo.' locations: [{line: 2, column: 21}] - - name: Nil value not allowed for non-null types + - name: non-null argument must be provided input: | directive @foo(bla: Int!) on FIELD_DEFINITION type P {f: Int @foo } @@ -622,6 +622,15 @@ directives: message: 'Argument bla for directive foo cannot be null.' locations: [{line: 2, column: 17}] + - name: non-null argument must not be null + input: | + directive @foo(bla: Int!) on FIELD_DEFINITION + type P {f: Int @foo(bla: null) } + + error: + message: 'Argument bla for directive foo cannot be null.' + locations: [{line: 2, column: 17}] + entry points: - name: multiple schema entry points input: |