Skip to content

Development

Nikita Stupin edited this page Oct 27, 2020 · 19 revisions

Testing

To run unit tests:

$ cd clairvoyance
$ python3 -m unittest tests/*_test.py

How clairvoyance works?

Let's assume that we have Apollo Server as our target and introspection is disabled. What "features" of Apollo Server can we use in order to obtain schema?

Please note that examples shown on fields but same techniques apply to arguments as well.

Suggestions

If we supply invalid field which is similar to valid field, underlying graphql-js library will kindly give us list of suggestions with valid fields.

POST / HTTP/1.1
Host: localhost:64148
Content-Type: application/json
Content-Length: 21

{"query": "{ star }"}
HTTP/1.1 400 Bad Request
...
Keep-Alive: timeout=5

{"errors":[{"message":"Cannot query field \"star\" on type \"Root\". Did you mean \"starship\"?","locations":[{"line":1,"column":3}]}]}

More information about this behaviour can be found in How apollo-server suggestions works? issue.

Valid fields cause specific errors or do not cause errors at all

POST / HTTP/1.1
Host: localhost:64148
Content-Type: application/json
Content-Length: 29

{"query": "{ vehicle }"}
HTTP/1.1 400 Bad Request
...
Keep-Alive: timeout=5

{"errors":[{"message":"Field \"vehicle\" of type \"Vehicle\" must have a selection of subfields. Did you mean \"vehicle { ... }\"?","locations":[{"line":1,"column":3}]}]}

So we can understand if field is valid even without suggestions.

Supplying multiple fields

If we supply multiple fields, we'll get error for each field.

POST / HTTP/1.1
Host: localhost:64148
Content-Type: application/json
Content-Length: 27

{"query": "{ star spice }"}
HTTP/1.1 400 Bad Request
...
Keep-Alive: timeout=5

{"errors":[{"message":"Cannot query field \"star\" on type \"Root\". Did you mean \"starship\"?","locations":[{"line":1,"column":3}]},{"message":"Cannot query field \"spice\" on type \"Root\". Did you mean \"species\"?","locations":[{"line":1,"column":8}]}]}

This allows us to speed up the process of probing for fields and arguments (up to several thousand words per second with single thread).

Modules description

__main__.py

This module contains code needed for running clairvoyance from command line (e.g. python3 -m clairvoyance).

As of 24 Oct 2020 it also contains code for running clairvoyance() on each of types. This part should be moved to oracle.py or another module.

oracle.py

This module contains code for creating schema. There are two main types of functions:

  • Those starting with probe_ perform HTTP request, do basic response analysis and call functions starting with get_.
  • Functions with get_ in turn works offline and tries to extract valid fields / args / ... from error messages.

clairvoyance() function used to manage the process of step-by-step schema construction (probe_* and get_* functions).

graphql.py

This module contains classes for various GraphQL concepts such as Schema, Type, Field, InputValue, TypeRef. Each of them has methods for converting to / from JSON.

There is also Config class which holds GraphQL endpoint configuration (e.g. URL, headers, bucket size).

Clone this wiki locally