From 6ae69b4cc83818db60ea7c0e4716eceb1df05d1a Mon Sep 17 00:00:00 2001 From: aman bansal Date: Mon, 5 Oct 2020 20:52:21 +0530 Subject: [PATCH] fix (graphql): disallowing field names with as (#6645) This is related to GRAPHQL-564. as is Dgraph reserved keyword. It's being used by DQL to identify variables. This PR is to restrict the naming for fields with the name as. --- graphql/schema/gqlschema_test.yml | 41 +++++++++++++++++++++++++ graphql/schema/rules.go | 24 ++++++++++++++- wiki/content/graphql/schema/reserved.md | 13 +++++++- 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/graphql/schema/gqlschema_test.yml b/graphql/schema/gqlschema_test.yml index d783ebfdd97..499f519b92b 100644 --- a/graphql/schema/gqlschema_test.yml +++ b/graphql/schema/gqlschema_test.yml @@ -2398,6 +2398,47 @@ invalid_schemas: {"message": "Subscription is a reserved word, so you can't declare a type with this name. Pick a different name for the type.", "locations": [{"line":1, "column":6}]}, ] + - + name: "as is reserved keyword - type Name" + input: | + type As { + id: ID! + name: String + } + errlist: [ + { "message": "As is a reserved word, so you can't declare a type with this name. Pick a different name for the type.", "locations": [ { "line": 1, "column": 6 } ] }, + ] + + - name: "as is reserved keyword - field name" + input: | + type X { + as: ID! + name: String + } + errlist: [ + { "message": "Type X; Field as: as is a reserved keyword and you cannot declare a field with this name.", "locations": [ { "line": 2, "column": 3 } ] }, + ] + + - name: "as is reserved keyword - type name using @dgraph directive" + input: | + type X @dgraph(type:"as") { + id: ID! + name: String + } + errlist: [ + { "message": "Type X; type argument 'as' for @dgraph directive is a reserved keyword.", "locations": [ { "line": 1, "column": 9 } ] }, + ] + + - name: "as is reserved keyword - field name using @dgraph directive" + input: | + type X { + id: ID! + name: String @dgraph(pred:"as") + } + errlist: [ + { "message": "Type X; Field name: pred argument 'as' for @dgraph directive is a reserved keyword.", "locations": [ { "line": 3, "column": 17 } ] }, + ] + valid_schemas: - name: "@auth on interface implementation" diff --git a/graphql/schema/rules.go b/graphql/schema/rules.go index 4b868ea682c..e1f25710240 100644 --- a/graphql/schema/rules.go +++ b/graphql/schema/rules.go @@ -547,11 +547,19 @@ func dgraphDirectiveTypeValidation(schema *ast.Schema, typ *ast.Definition) gqle dir.Position, "Type %s; type argument for @dgraph directive should not be empty.", typ.Name)} } + if typeArg.Value.Kind != ast.StringValue { return []*gqlerror.Error{gqlerror.ErrorPosf( dir.Position, "Type %s; type argument for @dgraph directive should of type String.", typ.Name)} } + + if isReservedKeyWord(typeArg.Value.Raw) { + return []*gqlerror.Error{gqlerror.ErrorPosf( + dir.Position, + "Type %s; type argument '%s' for @dgraph directive is a reserved keyword.", typ.Name, typeArg.Value.Raw)} + } + return nil } @@ -1048,6 +1056,7 @@ func dgraphDirectiveValidation(sch *ast.Schema, typ *ast.Definition, field *ast. typ.Name, field.Name)) return errs } + if predArg.Value.Kind != ast.StringValue { errs = append(errs, gqlerror.ErrorPosf( dir.Position, @@ -1055,6 +1064,15 @@ func dgraphDirectiveValidation(sch *ast.Schema, typ *ast.Definition, field *ast. typ.Name, field.Name)) return errs } + + if isReservedKeyWord(predArg.Value.Raw) { + errs = append(errs, gqlerror.ErrorPosf( + dir.Position, + "Type %s; Field %s: pred argument '%s' for @dgraph directive is a reserved keyword.", + typ.Name, field.Name, predArg.Value.Raw)) + return errs + } + if strings.HasPrefix(predArg.Value.Raw, "~") || strings.HasPrefix(predArg.Value.Raw, "<~") { if sch.Types[typ.Name].Kind == ast.Interface { // We don't want to consider the field of an interface but only the fields with @@ -1808,7 +1826,11 @@ func isReservedKeyWord(name string) bool { "Subscription": true, } - if isScalar(name) || isQueryOrMutation(name) || reservedTypeNames[name] { + caseInsensitiveKeywords := map[string]bool{ + "as": true, // this is reserved keyword because DQL uses this for variables + } + + if isScalar(name) || isQueryOrMutation(name) || reservedTypeNames[name] || caseInsensitiveKeywords[strings.ToLower(name)] { return true } diff --git a/wiki/content/graphql/schema/reserved.md b/wiki/content/graphql/schema/reserved.md index 84228f5819f..b48571bab89 100644 --- a/wiki/content/graphql/schema/reserved.md +++ b/wiki/content/graphql/schema/reserved.md @@ -4,7 +4,18 @@ title = "Reserved Names" parent = "schema" weight = 1 +++ +The following names are reserved and can't be used to define any other identifiers: -Names `Int`, `Float`, `Boolean`, `String`, `DateTime` and `ID` are reserved and cannot be used to define any other identifiers. +- `Int` +- `Float` +- `Boolean` +- `String` +- `DateTime` +- `ID` +- `uid` +- `Subscription` +- `as` (case-insensitive) +- `Query` +- `Mutation` For each type, Dgraph generates a number of GraphQL types needed to operate the GraphQL API, these generated type names also can't be present in the input schema. For example, for a type `Author`, Dgraph generates `AuthorFilter`, `AuthorOrderable`, `AuthorOrder`, `AuthorRef`, `AddAuthorInput`, `UpdateAuthorInput`, `AuthorPatch`, `AddAuthorPayload`, `DeleteAuthorPayload` and `UpdateAuthorPayload`. Thus if `Author` is present in the input schema, all of those become reserved type names. \ No newline at end of file