Skip to content

Commit

Permalink
built-ins: Add new GraphQL builtins.
Browse files Browse the repository at this point in the history
This commit vendors in github.com/vektah/gqlparser, and provides the
implementation for the following graphql built-ins:

 - graphql.parse
 - graphql.parse_and_verify
 - graphql.parse_query
 - graphql.parse_schema
 - graphql.is_valid

The test suite is comprised of the classic "Star Wars" examples from the
official GraphQL docs, along with a host of syntax examples ported over
from the underlying GraphQL parser's test suite.

AST objects returned by the parse_x APIs are currently pruned for brevity.

Fixes #4283

Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
  • Loading branch information
philipaconrad authored and tsandall committed May 27, 2022
1 parent 643eacd commit 1fde1ad
Show file tree
Hide file tree
Showing 85 changed files with 11,442 additions and 0 deletions.
84 changes: 84 additions & 0 deletions ast/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@ var DefaultBuiltins = [...]*Builtin{
// HTTP
HTTPSend,

// GraphQL
GraphQLParse,
GraphQLParseAndVerify,
GraphQLParseQuery,
GraphQLParseSchema,
GraphQLIsValid,

// Rego
RegoParseModule,
RegoMetadataChain,
Expand Down Expand Up @@ -2405,6 +2412,83 @@ var HTTPSend = &Builtin{
),
}

/**
* GraphQL
*/

// GraphQLParse returns a pair of AST objects from parsing/validation.
var GraphQLParse = &Builtin{
Name: "graphql.parse",
Description: "Returns AST objects for a given GraphQL query and schema after validating the query against the schema. Returns undefined if errors were encountered during parsing or validation.",
Decl: types.NewFunction(
types.Args(
types.Named("query", types.S),
types.Named("schema", types.S),
),
types.Named("output", types.NewArray([]types.Type{
types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)),
types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)),
}, nil)).Description("`output` is of the form `[query_ast, schema_ast]`. If the GraphQL query is valid given the provided schema, then `query_ast` and `schema_ast` are objects describing the ASTs for the query and schema."),
),
}

// GraphQLParseAndVerify returns a boolean and a pair of AST object from parsing/validation.
var GraphQLParseAndVerify = &Builtin{
Name: "graphql.parse_and_verify",
Description: "Returns a boolean indicating success or failure alongside the parsed ASTs for a given GraphQL query and schema after validating the query against the schema.",
Decl: types.NewFunction(
types.Args(
types.Named("query", types.S),
types.Named("schema", types.S),
),
types.Named("output", types.NewArray([]types.Type{
types.B,
types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)),
types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)),
}, nil)).Description(" `output` is of the form `[valid, query_ast, schema_ast]`. If the query is valid given the provided schema, then `valid` is `true`, and `query_ast` and `schema_ast` are objects describing the ASTs for the GraphQL query and schema. Otherwise, `valid` is `false` and `query_ast` and `schema_ast` are `{}`."),
),
}

// GraphQLParseQuery parses the input GraphQL query and returns a JSON
// representation of its AST.
var GraphQLParseQuery = &Builtin{
Name: "graphql.parse_query",
Description: "Returns an AST object for a GraphQL query.",
Decl: types.NewFunction(
types.Args(
types.Named("query", types.S),
),
types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.A, types.A))).Description("AST object for the GraphQL query."),
),
}

// GraphQLParseSchema parses the input GraphQL schema and returns a JSON
// representation of its AST.
var GraphQLParseSchema = &Builtin{
Name: "graphql.parse_schema",
Description: "Returns an AST object for a GraphQL schema.",
Decl: types.NewFunction(
types.Args(
types.Named("schema", types.S),
),
types.Named("output", types.NewObject(nil, types.NewDynamicProperty(types.A, types.A))).Description("AST object for the GraphQL schema."),
),
}

// GraphQLIsValid returns true if a GraphQL query is valid with a given
// schema, and returns false for all other inputs.
var GraphQLIsValid = &Builtin{
Name: "graphql.is_valid",
Description: "Checks that a GraphQL query is valid against a given schema.",
Decl: types.NewFunction(
types.Args(
types.Named("query", types.S),
types.Named("schema", types.S),
),
types.Named("output", types.B).Description("`true` if the query is valid under the given schema. `false` otherwise."),
),
}

/**
* Rego
*/
Expand Down
122 changes: 122 additions & 0 deletions builtin_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@
"graph.reachable_paths",
"walk"
],
"graphql": [
"graphql.is_valid",
"graphql.parse",
"graphql.parse_and_verify",
"graphql.parse_query",
"graphql.parse_schema"
],
"http": [
"http.send"
],
Expand Down Expand Up @@ -3776,6 +3783,121 @@
},
"wasm": false
},
"graphql.is_valid": {
"args": [
{
"description": "",
"name": "query",
"type": "string"
},
{
"description": "",
"name": "schema",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Checks that a GraphQL query is valid against a given schema.",
"introduced": "edge",
"result": {
"description": "`true` if the query is valid under the given schema. `false` otherwise.",
"name": "output",
"type": "boolean"
},
"wasm": false
},
"graphql.parse": {
"args": [
{
"description": "",
"name": "query",
"type": "string"
},
{
"description": "",
"name": "schema",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Returns AST objects for a given GraphQL query and schema after validating the query against the schema. Returns undefined if errors were encountered during parsing or validation.",
"introduced": "edge",
"result": {
"description": "`output` is of the form `[query_ast, schema_ast]`. If the GraphQL query is valid given the provided schema, then `query_ast` and `schema_ast` are objects describing the ASTs for the query and schema.",
"name": "output",
"type": "array\u003cobject[any: any], object[any: any]\u003e"
},
"wasm": false
},
"graphql.parse_and_verify": {
"args": [
{
"description": "",
"name": "query",
"type": "string"
},
{
"description": "",
"name": "schema",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Returns a boolean indicating success or failure alongside the parsed ASTs for a given GraphQL query and schema after validating the query against the schema.",
"introduced": "edge",
"result": {
"description": " `output` is of the form `[valid, query_ast, schema_ast]`. If the query is valid given the provided schema, then `valid` is `true`, and `query_ast` and `schema_ast` are objects describing the ASTs for the GraphQL query and schema. Otherwise, `valid` is `false` and `query_ast` and `schema_ast` are `{}`.",
"name": "output",
"type": "array\u003cboolean, object[any: any], object[any: any]\u003e"
},
"wasm": false
},
"graphql.parse_query": {
"args": [
{
"description": "",
"name": "query",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Returns an AST object for a GraphQL query.",
"introduced": "edge",
"result": {
"description": "AST object for the GraphQL query.",
"name": "output",
"type": "object[any: any]"
},
"wasm": false
},
"graphql.parse_schema": {
"args": [
{
"description": "",
"name": "schema",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Returns an AST object for a GraphQL schema.",
"introduced": "edge",
"result": {
"description": "AST object for the GraphQL schema.",
"name": "output",
"type": "object[any: any]"
},
"wasm": false
},
"gt": {
"args": [
{
Expand Down
146 changes: 146 additions & 0 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,152 @@
"type": "function"
}
},
{
"name": "graphql.is_valid",
"decl": {
"args": [
{
"type": "string"
},
{
"type": "string"
}
],
"result": {
"type": "boolean"
},
"type": "function"
}
},
{
"name": "graphql.parse",
"decl": {
"args": [
{
"type": "string"
},
{
"type": "string"
}
],
"result": {
"static": [
{
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
},
{
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
}
],
"type": "array"
},
"type": "function"
}
},
{
"name": "graphql.parse_and_verify",
"decl": {
"args": [
{
"type": "string"
},
{
"type": "string"
}
],
"result": {
"static": [
{
"type": "boolean"
},
{
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
},
{
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
}
],
"type": "array"
},
"type": "function"
}
},
{
"name": "graphql.parse_query",
"decl": {
"args": [
{
"type": "string"
}
],
"result": {
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
},
"type": "function"
}
},
{
"name": "graphql.parse_schema",
"decl": {
"args": [
{
"type": "string"
}
],
"result": {
"dynamic": {
"key": {
"type": "any"
},
"value": {
"type": "any"
}
},
"type": "object"
},
"type": "function"
}
},
{
"name": "gt",
"decl": {
Expand Down
2 changes: 2 additions & 0 deletions docs/content/policy-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,8 @@ all_paths[entity_name]
```live:graph/reachable_paths/example:output
```

{{< builtin-table cat=graphql title="GraphQL" >}}

{{< builtin-table cat=http title=HTTP >}}

{{< danger >}}
Expand Down

0 comments on commit 1fde1ad

Please sign in to comment.