mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-25 17:55:15 -06:00
45a3d8ee70
This commit addresses issues around vendoring the 3rd party GraphQL parser library, `vektah/gqlparser`, which is used by our GraphQL builtins. By directly depending on the library, we accidentally forced all of our library users to have to match `gqlparser` versions, which could cause problems if they wanted to use downstream GraphQL libraries. To fix this version clash problem, this PR internalizes `vektah/gqlparser` v2.4.8 into the `internal/gqlparser` package (we can update to v2.5.0 later). Scripts are included to automate some of the internalizing process if we wish to update the library in the future. Fixes: #5065 Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
679 lines
16 KiB
YAML
679 lines
16 KiB
YAML
types:
|
|
- name: cannot be redeclared
|
|
input: |
|
|
type A {
|
|
name: String
|
|
}
|
|
type A {
|
|
name: String
|
|
}
|
|
error:
|
|
message: "Cannot redeclare type A."
|
|
locations: [{line: 4, column: 6}]
|
|
- name: cannot be duplicated field at same definition 1
|
|
input: |
|
|
type A {
|
|
name: String
|
|
name: String
|
|
}
|
|
error:
|
|
message: "Field A.name can only be defined once."
|
|
locations: [{line: 3, column: 3}]
|
|
- name: cannot be duplicated field at same definition 2
|
|
input: |
|
|
type A {
|
|
name: String
|
|
}
|
|
extend type A {
|
|
name: String
|
|
}
|
|
error:
|
|
message: "Field A.name can only be defined once."
|
|
locations: [{line: 5, column: 3}]
|
|
- name: cannot be duplicated field at same definition 3
|
|
input: |
|
|
type A {
|
|
name: String
|
|
}
|
|
extend type A {
|
|
age: Int
|
|
age: Int
|
|
}
|
|
error:
|
|
message: "Field A.age can only be defined once."
|
|
locations: [{line: 6, column: 3}]
|
|
|
|
object types:
|
|
- name: must define one or more fields
|
|
input: |
|
|
directive @D on OBJECT
|
|
|
|
# This pattern rejected by parser
|
|
# type InvalidObject1 {}
|
|
|
|
type InvalidObject2 @D
|
|
|
|
type ValidObject {
|
|
id: ID
|
|
}
|
|
extend type ValidObject @D
|
|
extend type ValidObject {
|
|
b: Int
|
|
}
|
|
error:
|
|
message: 'OBJECT InvalidObject2: must define one or more fields.'
|
|
locations: [{line: 6, column: 6}]
|
|
- name: check reserved names on type name
|
|
input: |
|
|
type __FooBar {
|
|
id: ID
|
|
}
|
|
error:
|
|
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 1, column: 6}]
|
|
- name: check reserved names on type field
|
|
input: |
|
|
type FooBar {
|
|
__id: ID
|
|
}
|
|
error:
|
|
message: 'Name "__id" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 2, column: 3}]
|
|
|
|
- name: check reserved names on type field argument
|
|
input: |
|
|
type FooBar {
|
|
foo(__bar: ID): ID
|
|
}
|
|
error:
|
|
message: 'Name "__bar" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 2, column: 7}]
|
|
|
|
- name: must not allow input object as field type
|
|
input: |
|
|
input Input {
|
|
id: ID
|
|
}
|
|
type Query {
|
|
input: Input!
|
|
}
|
|
error:
|
|
message: 'OBJECT Query: field must be one of SCALAR, OBJECT, INTERFACE, UNION, ENUM.'
|
|
locations: [{line: 5, column: 3}]
|
|
|
|
interfaces:
|
|
- name: must exist
|
|
input: |
|
|
type Thing implements Object {
|
|
id: ID!
|
|
}
|
|
|
|
type Query {
|
|
Things: [Thing!]!
|
|
}
|
|
error:
|
|
message: 'Undefined type "Object".'
|
|
locations: [{line: 1, column: 6}]
|
|
|
|
- name: must be an interface
|
|
input: |
|
|
type Thing implements Object {
|
|
id: ID!
|
|
}
|
|
|
|
type Query {
|
|
Things: [Thing!]!
|
|
}
|
|
|
|
type Object {
|
|
name: String
|
|
}
|
|
error:
|
|
message: '"Object" is a non interface type OBJECT.'
|
|
locations: [{line: 1, column: 6}]
|
|
|
|
- name: must define one or more fields
|
|
input: |
|
|
directive @D on INTERFACE
|
|
|
|
# This pattern rejected by parser
|
|
# interface InvalidInterface1 {}
|
|
|
|
interface InvalidInterface2 @D
|
|
|
|
interface ValidInterface {
|
|
id: ID
|
|
}
|
|
extend interface ValidInterface @D
|
|
extend interface ValidInterface {
|
|
b: Int
|
|
}
|
|
error:
|
|
message: 'INTERFACE InvalidInterface2: must define one or more fields.'
|
|
locations: [{line: 6, column: 11}]
|
|
|
|
- name: check reserved names on type name
|
|
input: |
|
|
interface __FooBar {
|
|
id: ID
|
|
}
|
|
error:
|
|
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 1, column: 11}]
|
|
|
|
- name: must not allow input object as field type
|
|
input: |
|
|
input Input {
|
|
id: ID
|
|
}
|
|
type Query {
|
|
foo: Foo!
|
|
}
|
|
interface Foo {
|
|
input: Input!
|
|
}
|
|
error:
|
|
message: 'INTERFACE Foo: field must be one of SCALAR, OBJECT, INTERFACE, UNION, ENUM.'
|
|
locations: [{line: 8, column: 3}]
|
|
|
|
- name: must have all fields from interface
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
someField: Int!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id: ID!
|
|
}
|
|
error:
|
|
message: 'For Bar to implement BarInterface it must have a field called id.'
|
|
locations: [{line: 1, column: 6}]
|
|
|
|
- name: must have same type of fields
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id: Int!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id: ID!
|
|
}
|
|
error:
|
|
message: 'For Bar to implement BarInterface the field id must have type ID!.'
|
|
locations: [{line: 2, column: 5}]
|
|
|
|
- name: must have all required arguments
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id: ID!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id(ff: Int!): ID!
|
|
}
|
|
error:
|
|
message: 'For Bar to implement BarInterface the field id must have the same arguments but it is missing ff.'
|
|
locations: [{line: 2, column: 5}]
|
|
|
|
- name: must have same argument types
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id(ff: ID!): ID!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id(ff: Int!): ID!
|
|
}
|
|
error:
|
|
message: 'For Bar to implement BarInterface the field id must have the same arguments but ff has the wrong type.'
|
|
locations: [{line: 2, column: 8}]
|
|
|
|
- name: may defined additional nullable arguments
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id(opt: Int): ID!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id: ID!
|
|
}
|
|
|
|
- name: may defined additional required arguments with defaults
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id(opt: Int! = 1): ID!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id: ID!
|
|
}
|
|
|
|
- name: must not define additional required arguments without defaults
|
|
input: |
|
|
type Bar implements BarInterface {
|
|
id(opt: Int!): ID!
|
|
}
|
|
|
|
interface BarInterface {
|
|
id: ID!
|
|
}
|
|
error:
|
|
message: 'For Bar to implement BarInterface any additional arguments on id must be optional or have a default value but opt is required.'
|
|
locations: [{line: 2, column: 8}]
|
|
|
|
- name: can have covariant argument types
|
|
input: |
|
|
union U = A|B
|
|
|
|
type A { name: String }
|
|
type B { name: String }
|
|
|
|
type Bar implements BarInterface {
|
|
f: A!
|
|
}
|
|
|
|
interface BarInterface {
|
|
f: U!
|
|
}
|
|
|
|
- name: may define intermediate interfaces
|
|
input: |
|
|
interface IA {
|
|
id: ID!
|
|
}
|
|
|
|
interface IIA implements IA {
|
|
id: ID!
|
|
}
|
|
|
|
type A implements IIA & IA {
|
|
id: ID!
|
|
}
|
|
|
|
- name: Type Foo must implement Baz because it is implemented by Bar
|
|
input: |
|
|
interface Baz {
|
|
baz: String
|
|
}
|
|
|
|
interface Bar implements Baz {
|
|
bar: String
|
|
baz: String
|
|
}
|
|
|
|
type Foo implements Bar {
|
|
foo: String
|
|
bar: String
|
|
baz: String
|
|
}
|
|
error:
|
|
message: 'Type Foo must implement Baz because it is implemented by Bar.'
|
|
locations: [{line: 10, column: 6}]
|
|
|
|
- name: circular reference error
|
|
input: |
|
|
interface Circular1 implements Circular2 {
|
|
id: ID!
|
|
}
|
|
|
|
interface Circular2 implements Circular1 {
|
|
id: ID!
|
|
}
|
|
error:
|
|
message: 'Type Circular1 cannot implement Circular2 because it would create a circular reference.'
|
|
locations: [{line: 1, column: 11}]
|
|
|
|
inputs:
|
|
- name: must define one or more input fields
|
|
input: |
|
|
directive @D on INPUT_OBJECT
|
|
|
|
# This pattern rejected by parser
|
|
# input InvalidInput1 {}
|
|
|
|
input InvalidInput2 @D
|
|
|
|
input ValidInput {
|
|
id: ID
|
|
}
|
|
extend input ValidInput @D
|
|
extend input ValidInput {
|
|
b: Int
|
|
}
|
|
error:
|
|
message: 'INPUT_OBJECT InvalidInput2: must define one or more input fields.'
|
|
locations: [{line: 6, column: 7}]
|
|
- name: check reserved names on type name
|
|
input: |
|
|
input __FooBar {
|
|
id: ID
|
|
}
|
|
error:
|
|
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 1, column: 7}]
|
|
|
|
- name: fields cannot be Objects
|
|
input: |
|
|
type Object { id: ID }
|
|
input Foo { a: Object! }
|
|
error:
|
|
message: 'OBJECT a: field must be one of SCALAR, ENUM, INPUT_OBJECT.'
|
|
locations: [{line: 2, column: 13}]
|
|
|
|
- name: fields cannot be Interfaces
|
|
input: |
|
|
interface Interface { id: ID! }
|
|
input Foo { a: Interface! }
|
|
error:
|
|
message: 'INTERFACE a: field must be one of SCALAR, ENUM, INPUT_OBJECT.'
|
|
locations: [{line: 2, column: 13}]
|
|
|
|
- name: fields cannot be Unions
|
|
input: |
|
|
type Object { id: ID }
|
|
union Union = Object
|
|
input Foo { a: Union! }
|
|
error:
|
|
message: 'UNION a: field must be one of SCALAR, ENUM, INPUT_OBJECT.'
|
|
locations: [{line: 3, column: 13}]
|
|
|
|
args:
|
|
- name: Valid arg types
|
|
input: |
|
|
input Input { id: ID }
|
|
enum Enum { A }
|
|
scalar Scalar
|
|
|
|
type Query {
|
|
f(a: Input, b: Scalar, c: Enum): Boolean!
|
|
}
|
|
|
|
- name: Objects not allowed
|
|
input: |
|
|
type Object { id: ID }
|
|
type Query { f(a: Object): Boolean! }
|
|
|
|
error:
|
|
message: 'cannot use Object as argument a because OBJECT is not a valid input type'
|
|
locations: [{line: 2, column: 16}]
|
|
|
|
- name: Union not allowed
|
|
input: |
|
|
type Object { id: ID }
|
|
union Union = Object
|
|
type Query { f(a: Union): Boolean! }
|
|
|
|
error:
|
|
message: 'cannot use Union as argument a because UNION is not a valid input type'
|
|
locations: [{line: 3, column: 16}]
|
|
|
|
- name: Interface not allowed
|
|
input: |
|
|
interface Interface { id: ID }
|
|
type Query { f(a: Interface): Boolean! }
|
|
|
|
error:
|
|
message: 'cannot use Interface as argument a because INTERFACE is not a valid input type'
|
|
locations: [{line: 2, column: 16}]
|
|
|
|
enums:
|
|
- name: must define one or more unique enum values
|
|
input: |
|
|
directive @D on ENUM
|
|
|
|
# This pattern rejected by parser
|
|
# enum InvalidEmum1 {}
|
|
|
|
enum InvalidEnum2 @D
|
|
|
|
enum ValidEnum {
|
|
FOO
|
|
}
|
|
extend enum ValidEnum @D
|
|
extend enum ValidEnum {
|
|
BAR
|
|
}
|
|
error:
|
|
message: 'ENUM InvalidEnum2: must define one or more unique enum values.'
|
|
locations: [{line: 6, column: 6}]
|
|
- name: check reserved names on type name
|
|
input: |
|
|
enum __FooBar {
|
|
A
|
|
B
|
|
}
|
|
error:
|
|
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 1, column: 6}]
|
|
|
|
unions:
|
|
- name: union types must be defined
|
|
input: |
|
|
union Foo = Bar | Baz
|
|
type Bar {
|
|
id: ID
|
|
}
|
|
error:
|
|
message: "Undefined type \"Baz\"."
|
|
locations: [{line: 1, column: 7}]
|
|
- name: union types must be objects
|
|
input: |
|
|
union Foo = Baz
|
|
interface Baz {
|
|
id: ID
|
|
}
|
|
error:
|
|
message: "UNION type \"Baz\" must be OBJECT."
|
|
locations: [{line: 1, column: 7}]
|
|
|
|
- name: unions of pure type extensions are valid
|
|
input: |
|
|
|
|
type Review {
|
|
body: String!
|
|
author: User! @provides(fields: "username")
|
|
product: Product!
|
|
}
|
|
|
|
extend type User @key(fields: "id") {
|
|
id: ID! @external
|
|
reviews: [Review]
|
|
}
|
|
|
|
extend type Product @key(fields: "upc") {
|
|
upc: String! @external
|
|
reviews: [Review]
|
|
}
|
|
|
|
union Foo = User | Product
|
|
scalar _Any
|
|
scalar _FieldSet
|
|
directive @external on FIELD_DEFINITION
|
|
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
|
|
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
|
|
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
|
|
directive @extends on OBJECT
|
|
|
|
|
|
|
|
type extensions:
|
|
- name: can extend non existant types
|
|
input: |
|
|
extend type A {
|
|
name: String
|
|
}
|
|
|
|
|
|
- name: cannot extend incorret type existant types
|
|
input: |
|
|
scalar A
|
|
extend type A {
|
|
name: String
|
|
}
|
|
error:
|
|
message: "Cannot extend type A because the base type is a SCALAR, not OBJECT."
|
|
locations: [{line: 2, column: 13}]
|
|
|
|
directives:
|
|
- name: cannot redeclare directives
|
|
input: |
|
|
directive @A on FIELD_DEFINITION
|
|
directive @A on FIELD_DEFINITION
|
|
error:
|
|
message: "Cannot redeclare directive A."
|
|
locations: [{line: 2, column: 12}]
|
|
|
|
- name: can redeclare builtin directives
|
|
input: |
|
|
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
|
|
|
- name: must be declared
|
|
input: |
|
|
type User {
|
|
name: String @foo
|
|
}
|
|
error:
|
|
message: "Undefined directive foo."
|
|
locations: [{line: 2, column: 17}]
|
|
|
|
- name: cannot be self-referential
|
|
input: |
|
|
directive @A(foo: Int! @A) on FIELD_DEFINITION
|
|
error:
|
|
message: "Directive A cannot refer to itself."
|
|
locations: [{line: 1, column: 25}]
|
|
- name: check reserved names on type name
|
|
input: |
|
|
directive @__A on FIELD_DEFINITION
|
|
error:
|
|
message: 'Name "__A" must not begin with "__", which is reserved by GraphQL introspection.'
|
|
locations: [{line: 1, column: 12}]
|
|
|
|
- name: Valid arg types
|
|
input: |
|
|
input Input { id: ID }
|
|
enum Enum { A }
|
|
scalar Scalar
|
|
|
|
directive @A(a: Input, b: Scalar, c: Enum) on FIELD_DEFINITION
|
|
|
|
- name: Objects not allowed
|
|
input: |
|
|
type Object { id: ID }
|
|
directive @A(a: Object) on FIELD_DEFINITION
|
|
|
|
error:
|
|
message: 'cannot use Object as argument a because OBJECT is not a valid input type'
|
|
locations: [{line: 2, column: 14}]
|
|
|
|
- name: Union not allowed
|
|
input: |
|
|
type Object { id: ID }
|
|
union Union = Object
|
|
directive @A(a: Union) on FIELD_DEFINITION
|
|
|
|
error:
|
|
message: 'cannot use Union as argument a because UNION is not a valid input type'
|
|
locations: [{line: 3, column: 14}]
|
|
|
|
- name: Interface not allowed
|
|
input: |
|
|
interface Interface { id: ID }
|
|
directive @A(a: Interface) on FIELD_DEFINITION
|
|
|
|
error:
|
|
message: 'cannot use Interface as argument a because INTERFACE is not a valid input type'
|
|
locations: [{line: 2, column: 14}]
|
|
|
|
- name: Invalid location usage not allowed
|
|
input: |
|
|
directive @test on FIELD_DEFINITION
|
|
input I1 @test { f: String }
|
|
|
|
error:
|
|
message: 'Directive test is not applicable on INPUT_OBJECT.'
|
|
locations: [{line: 2, column: 11}]
|
|
|
|
- name: Valid location usage
|
|
input: |
|
|
directive @testInputField on INPUT_FIELD_DEFINITION
|
|
directive @testField on FIELD_DEFINITION
|
|
directive @inp on INPUT_OBJECT
|
|
input I1 @inp { f: String @testInputField }
|
|
type P { name: String @testField }
|
|
interface I { id: ID @testField }
|
|
|
|
|
|
entry points:
|
|
- name: multiple schema entry points
|
|
input: |
|
|
schema {
|
|
query: Query
|
|
}
|
|
schema {
|
|
query: Query
|
|
}
|
|
scalar Query
|
|
error:
|
|
message: "Cannot have multiple schema entry points, consider schema extensions instead."
|
|
locations: [{line: 4, column: 8}]
|
|
|
|
- name: Undefined schema entrypoint
|
|
input: |
|
|
schema {
|
|
query: Query
|
|
}
|
|
error:
|
|
message: "Schema root query refers to a type Query that does not exist."
|
|
locations: [{line: 2, column: 3}]
|
|
|
|
entry point extensions:
|
|
- name: Undefined schema entrypoint
|
|
input: |
|
|
schema {
|
|
query: Query
|
|
}
|
|
scalar Query
|
|
extend schema {
|
|
mutation: Mutation
|
|
}
|
|
error:
|
|
message: "Schema root mutation refers to a type Mutation that does not exist."
|
|
locations: [{line: 6, column: 3}]
|
|
|
|
type references:
|
|
- name: Field types
|
|
input: |
|
|
type User {
|
|
posts: Post
|
|
}
|
|
error:
|
|
message: "Undefined type Post."
|
|
locations: [{line: 2, column: 10}]
|
|
|
|
- name: Arg types
|
|
input: |
|
|
type User {
|
|
posts(foo: FooBar): String
|
|
}
|
|
error:
|
|
message: "Undefined type FooBar."
|
|
locations: [{line: 2, column: 14}]
|
|
|
|
- name: Directive arg types
|
|
input: |
|
|
directive @Foo(foo: FooBar) on FIELD_DEFINITION
|
|
|
|
error:
|
|
message: "Undefined type FooBar."
|
|
locations: [{line: 1, column: 21}]
|
|
|
|
- name: Invalid enum value
|
|
input: |
|
|
enum Enum { true }
|
|
|
|
error:
|
|
message: "ENUM Enum: non-enum value true."
|
|
locations: [{line: 1, column: 6}]
|