GraphQL Schema support
This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
We currently support scanning GraphQL endpoints, but need a HAR file or Postman collection in order to scan it. In order to expand our support for GraphQL, we need to be able to support defining GraphQL endpoints through a GraphQL schema. We should support defining the endpoints via the GraphQL SDL, by allowing them to provide the path to a schema file.
Proposal
Open Questions:
- Can we implement this w/o some form of parameter dependency resolution.
- Should we create multiple exchanges per item? For example if their are optional inputs.
The GraphQL endpoint can also provide the full schema. This schema defines all of the things API Security will want to test, both for DAST and API Fuzzing. The proposed method of supporting the GraphQL schema for automatic testing is the following:
- Add a new variable
_GRAPHQL
, allowing the user to provide a GraphQL endpoint address or schema file - Refactor the IReader readers to produce Operation+Request instead of just Request.
- Create a new IReader for GraphQL that provides each query/mutation as an
Operation
Refactor Readers to produce Operations and Request pairs
The current reader implementation produces Request
instances which are then converted into Operation
instances by the RunnerService
. Unfortunately that causes information loss for API specifications that include information about the parameters such as type or constraints.
This work will be required prior to creating the GraphQlSchemaReader
.
Proposed new IReader
interface:
namespace Peach.Web.Runner.Interfaces
{
public interface IReader
{
IEnumerable<(Operation Operation, Request Request)> GetOperations(IRunnerOptions runnerOptions);
}
}
Questions:
- For existing readers, do they use
WebApiService.OperationFromRequest
to create the Operation to pair with the Request they are already returning?
GraphQlSChemaReader (Peach.Web.Runner.Services.Readers)
Implement a new reader that creates a series of exchanges that provide coverage of all parameterized queries and mutations.
- Use our existing GraphQL.NET dependency to parse schema
- When schema is provided as a file, read file parse schema
- When schema is provided as a url:
- Get schema by running the query provided below
- Make sure to use overrides when making this request so it's authenticated
- The example query assumes max 10 levels of nested types. What do we do if the target schema is deeper? Should we pick a limit and say anything beyond that is not supported? Can we detect if there are more types that we didn't receive and issue a new query to get them?
- Extract schema from query result
- Get schema by running the query provided below
- Iterate over the
Queries
andMutations
section of theSchema
instance, generating (Operation, Request) pairs- Generate an
Operation
with aGraphQLBody
- Option: Create a GraphQL AST doc directly, or create a GraphQL query and parse it.
- We have some concern that building the AST may be complex or fiddly, but initial investigation suggests it won't be too bad. It would be nice to have a library that was specifically designed to dynamically build GraphQL queries, but the only ones we can find assume that there is a statically-typed model.
- If we end up parsing a request, we need to ensure that we still end up with the correct type information
- Option: Create a GraphQL AST doc directly, or create a GraphQL query and parse it.
- Convert the
Operation
into aRequest
- Is
WebApiService.OperationIntoRequest
sufficient for this?
- Is
- Generate an
Interpreting the schema response
- Interesting part is
data
,__schema
,types
object- Query root name is
__schema
[queryType
][name
] - Mutation root name is
__schema
[mutationType
][name
] - Queries are listed as
types
[query root][fields
] - Mutations as
types
[mutation root][fields
]
- Query root name is
- So far unable to find a way to read json response into the
Schema
instance- might need to construct by hand
Testing
Implementation Checklist
-
Mike: Review Herb's feedback -
David: Get GraphQlIntegrationTests.GraphQlPathOfSlash
test to pass -
Complete work on GraphqlController.Validate
-
Mike: Hook up the GraphqlController.Validate
method to call theGraphQlReader
and return a correct validation response. -
Do we need to hook up GraphQlOptionValidationErrorCode.ErrorOnValidation to workerentry? -
Update worker-entry and add test to support GraphQL validation -
Need tests, especially for unexpected exceptions which are not well handled yet.
-
-
[ ] David: Do we need to perform overrides on the GraphQL introspection query (yes probably)?- Yes, but we will do this along with other readers during #357052
-
David: Add good error message when we are unable to run an introspection query on the target -
David: Add proper error handling to the introspection query run -
Mike: Add ReaderErrorContext to GraphQlReader -
GetOperations -
GetGraphQlOperations -
Rest of in scope methods(moved to non-essentials)
-
-
David: Implement unsupported types in GraphQlValueElement.cs
-
ListValue
-
ObjectValue
-
GuidValue
-
-
Mike: Verify new worker-entry tests for GraphQL are passing -
Mike: Add variable prefix to exception messages in GraphQlReader.GetOperations -
Non-essentials (can push this week w/o) -
Do we need additional error handling around LoadJsonDocument in GraphQlReader.GetOperations -
Should we mark subscriptions as excluded? (perhaps this is a follow on issue) -
Mike: Investigate all of the network errors from the Python GraphQL example -
Add ReaderErrorContext to rest of in scope GraphQlReader methods -
Investigate if we need to support other types from this list of GraphQL.NET types. We probably do not need too. -
Investigate why the ReaderException exception message is not being displayed in the worker-entry console output
-
-
Documentation -
Document usage of new variables and graphql schema support -
Add section on getting a copy of the GraphQL Schema in JSON format-
Move this to it's own issue
-
-
Update documentation with new variable _SCHEMA
-
Mike: Update Example GraphQL project
-
Appendix
Utilities
GitLab GraphQL Explorer
Example of variables separate from query inputs
Schema Query
This is the query used by the interactive GraphQL web thing:
Click this to show/hide query.
query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}