forked from canada-ca/tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdepth_check.py
More file actions
64 lines (55 loc) · 1.94 KB
/
depth_check.py
File metadata and controls
64 lines (55 loc) · 1.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from typing import Dict
from graphql.language.ast import (
Document,
FragmentDefinition,
OperationDefinition,
Node,
FragmentSpread,
Field,
InlineFragment,
)
from backend import get_fragments, get_queries_and_mutations
class DepthLimitReached(Exception):
pass
def measure_depth(node: Node, fragments: Dict[str, FragmentDefinition]) -> int:
"""
A function which recursively measures the depth of a Graphene Query
:type node: Node
:param node: Graphql-core object used for query traversal/indexing
:type fragments: dict
:param fragments: The fragments of the query
:rtype: int
:return: The max depth of the node
"""
if isinstance(node, FragmentSpread):
fragment = fragments.get(node.name.value)
return measure_depth(node=fragment, fragments=fragments)
elif isinstance(node, Field):
if node.name.value.lower() in ["__schema", "__introspection"]:
return 0
if not node.selection_set:
return 1
depths = []
for selection in node.selection_set.selections:
depth = measure_depth(node=selection, fragments=fragments)
depths.append(depth)
return 1 + max(depths)
elif (
isinstance(node, FragmentDefinition)
or isinstance(node, OperationDefinition)
or isinstance(node, InlineFragment)
):
depths = []
for selection in node.selection_set.selections:
depth = measure_depth(node=selection, fragments=fragments)
depths.append(depth)
return max(depths)
else:
raise Exception("Unknown node")
def check_max_depth(max_depth: int, document: Document):
fragments = get_fragments(document.definitions)
queries = get_queries_and_mutations(document.definitions)
for query in queries:
depth = measure_depth(query, fragments)
if depth > max_depth:
raise DepthLimitReached("Query is too complex")