graphql 2.4.10 → 2.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/visitor.rb +35 -40
  3. data/lib/graphql/analysis.rb +12 -9
  4. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  5. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  6. data/lib/graphql/dashboard/statics/dashboard.css +3 -0
  7. data/lib/graphql/dashboard/statics/dashboard.js +78 -0
  8. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  9. data/lib/graphql/dashboard/statics/icon.png +0 -0
  10. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  11. data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +63 -0
  12. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +60 -0
  13. data/lib/graphql/dashboard.rb +142 -0
  14. data/lib/graphql/execution/interpreter/runtime.rb +1 -1
  15. data/lib/graphql/invalid_name_error.rb +1 -1
  16. data/lib/graphql/invalid_null_error.rb +5 -15
  17. data/lib/graphql/language/lexer.rb +7 -3
  18. data/lib/graphql/language/parser.rb +1 -1
  19. data/lib/graphql/schema/build_from_definition.rb +0 -1
  20. data/lib/graphql/schema/enum.rb +16 -1
  21. data/lib/graphql/schema/input_object.rb +1 -1
  22. data/lib/graphql/schema/loader.rb +0 -1
  23. data/lib/graphql/schema/member/has_dataloader.rb +4 -0
  24. data/lib/graphql/schema/resolver.rb +5 -1
  25. data/lib/graphql/schema.rb +51 -9
  26. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  27. data/lib/graphql/tracing/active_support_notifications_trace.rb +6 -2
  28. data/lib/graphql/tracing/appoptics_trace.rb +2 -0
  29. data/lib/graphql/tracing/appsignal_trace.rb +6 -0
  30. data/lib/graphql/tracing/data_dog_trace.rb +5 -0
  31. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  32. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  33. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  34. data/lib/graphql/tracing/new_relic_trace.rb +47 -23
  35. data/lib/graphql/tracing/perfetto_trace.rb +13 -2
  36. data/lib/graphql/tracing/prometheus_trace.rb +22 -0
  37. data/lib/graphql/tracing/scout_trace.rb +6 -0
  38. data/lib/graphql/tracing/sentry_trace.rb +5 -0
  39. data/lib/graphql/tracing/statsd_trace.rb +9 -0
  40. data/lib/graphql/tracing.rb +1 -0
  41. data/lib/graphql/version.rb +1 -1
  42. data/lib/graphql.rb +3 -0
  43. metadata +15 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8174a7314a4dc73aa720915044a1b068a39eccb981ca7553b7f894b60e94bdb
4
- data.tar.gz: 2bfb0e581036b944d2bd0f42b9ae580d990a848506b6ea20c9192c71c46e009d
3
+ metadata.gz: b105157510cb5779715118d5f28f49822a9b3b86b0faec0fdc86a2331904f667
4
+ data.tar.gz: 9230b70e18665505190c673579fa66b2906d04009f9e46d844990bafdba374da
5
5
  SHA512:
6
- metadata.gz: 5277ca8f41431b3854bbf85e64aa6c045701c803c18c927d21e2a89cdc2130a1c6bcb7c0e166fb3c7fcbdaac553f1bbf83bc00043ce8efd27b93dd8810b206a3
7
- data.tar.gz: 0564e407251fad40e9a3cec275a172980407b97659a8db85cb177ab2b03c5244b320661096eb6e49b3df87897b39c66f727312bb310516341d962013d5899d02
6
+ metadata.gz: e64decd9e23e3dcc23ced201998963ca0894e38161659a153d9c1ae918dce90c8ae365a3eb1debd753a78f65a1ffe3bf281ee0bb285cd1a0f6cd572cbb31455a
7
+ data.tar.gz: 4f0b3ac80a45a5db47e96abacc7fb935ed20c5a0ebe65ba2ca04e20c0bac58f1ec73e2e4af42c05307c76fd358c36bcfbd5529479201cf104540a50448298b80
@@ -10,7 +10,7 @@ module GraphQL
10
10
  #
11
11
  # @see {GraphQL::Analysis::Analyzer} AST Analyzers for queries
12
12
  class Visitor < GraphQL::Language::StaticVisitor
13
- def initialize(query:, analyzers:)
13
+ def initialize(query:, analyzers:, timeout:)
14
14
  @analyzers = analyzers
15
15
  @path = []
16
16
  @object_types = []
@@ -24,6 +24,11 @@ module GraphQL
24
24
  @types = query.types
25
25
  @response_path = []
26
26
  @skip_stack = [false]
27
+ @timeout_time = if timeout
28
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second) + timeout
29
+ else
30
+ Float::INFINITY
31
+ end
27
32
  super(query.selected_operation)
28
33
  end
29
34
 
@@ -72,21 +77,17 @@ module GraphQL
72
77
  module_eval <<-RUBY, __FILE__, __LINE__
73
78
  def call_on_enter_#{node_type}(node, parent)
74
79
  @analyzers.each do |a|
75
- begin
76
- a.on_enter_#{node_type}(node, parent, self)
77
- rescue AnalysisError => err
78
- @rescued_errors << err
79
- end
80
+ a.on_enter_#{node_type}(node, parent, self)
81
+ rescue AnalysisError => err
82
+ @rescued_errors << err
80
83
  end
81
84
  end
82
85
 
83
86
  def call_on_leave_#{node_type}(node, parent)
84
87
  @analyzers.each do |a|
85
- begin
86
- a.on_leave_#{node_type}(node, parent, self)
87
- rescue AnalysisError => err
88
- @rescued_errors << err
89
- end
88
+ a.on_leave_#{node_type}(node, parent, self)
89
+ rescue AnalysisError => err
90
+ @rescued_errors << err
90
91
  end
91
92
  end
92
93
 
@@ -94,6 +95,7 @@ module GraphQL
94
95
  end
95
96
 
96
97
  def on_operation_definition(node, parent)
98
+ check_timeout
97
99
  object_type = @schema.root_type_for_operation(node.operation_type)
98
100
  @object_types.push(object_type)
99
101
  @path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
@@ -104,31 +106,27 @@ module GraphQL
104
106
  @path.pop
105
107
  end
106
108
 
107
- def on_fragment_definition(node, parent)
108
- on_fragment_with_type(node) do
109
- @path.push("fragment #{node.name}")
110
- @in_fragment_def = false
111
- call_on_enter_fragment_definition(node, parent)
112
- super
113
- @in_fragment_def = false
114
- call_on_leave_fragment_definition(node, parent)
115
- end
116
- end
117
-
118
109
  def on_inline_fragment(node, parent)
119
- on_fragment_with_type(node) do
120
- @path.push("...#{node.type ? " on #{node.type.name}" : ""}")
121
- @skipping = @skip_stack.last || skip?(node)
122
- @skip_stack << @skipping
123
-
124
- call_on_enter_inline_fragment(node, parent)
125
- super
126
- @skipping = @skip_stack.pop
127
- call_on_leave_inline_fragment(node, parent)
110
+ check_timeout
111
+ object_type = if node.type
112
+ @types.type(node.type.name)
113
+ else
114
+ @object_types.last
128
115
  end
116
+ @object_types.push(object_type)
117
+ @path.push("...#{node.type ? " on #{node.type.name}" : ""}")
118
+ @skipping = @skip_stack.last || skip?(node)
119
+ @skip_stack << @skipping
120
+ call_on_enter_inline_fragment(node, parent)
121
+ super
122
+ @skipping = @skip_stack.pop
123
+ call_on_leave_inline_fragment(node, parent)
124
+ @object_types.pop
125
+ @path.pop
129
126
  end
130
127
 
131
128
  def on_field(node, parent)
129
+ check_timeout
132
130
  @response_path.push(node.alias || node.name)
133
131
  parent_type = @object_types.last
134
132
  # This could be nil if the previous field wasn't found:
@@ -156,6 +154,7 @@ module GraphQL
156
154
  end
157
155
 
158
156
  def on_directive(node, parent)
157
+ check_timeout
159
158
  directive_defn = @schema.directives[node.name]
160
159
  @directive_definitions.push(directive_defn)
161
160
  call_on_enter_directive(node, parent)
@@ -165,6 +164,7 @@ module GraphQL
165
164
  end
166
165
 
167
166
  def on_argument(node, parent)
167
+ check_timeout
168
168
  argument_defn = if (arg = @argument_definitions.last)
169
169
  arg_type = arg.type.unwrap
170
170
  if arg_type.kind.input_object?
@@ -190,6 +190,7 @@ module GraphQL
190
190
  end
191
191
 
192
192
  def on_fragment_spread(node, parent)
193
+ check_timeout
193
194
  @path.push("... #{node.name}")
194
195
  @skipping = @skip_stack.last || skip?(node)
195
196
  @skip_stack << @skipping
@@ -267,16 +268,10 @@ module GraphQL
267
268
  !dir.empty? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
268
269
  end
269
270
 
270
- def on_fragment_with_type(node)
271
- object_type = if node.type
272
- @types.type(node.type.name)
273
- else
274
- @object_types.last
271
+ def check_timeout
272
+ if Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second) > @timeout_time
273
+ raise GraphQL::Analysis::TimeoutError
275
274
  end
276
- @object_types.push(object_type)
277
- yield(node)
278
- @object_types.pop
279
- @path.pop
280
275
  end
281
276
  end
282
277
  end
@@ -6,11 +6,16 @@ require "graphql/analysis/query_complexity"
6
6
  require "graphql/analysis/max_query_complexity"
7
7
  require "graphql/analysis/query_depth"
8
8
  require "graphql/analysis/max_query_depth"
9
- require "timeout"
10
-
11
9
  module GraphQL
12
10
  module Analysis
13
11
  AST = self
12
+
13
+ class TimeoutError < AnalysisError
14
+ def initialize(...)
15
+ super("Timeout on validation of query")
16
+ end
17
+ end
18
+
14
19
  module_function
15
20
  # Analyze a multiplex, and all queries within.
16
21
  # Multiplex analyzers are ran for all queries, keeping state.
@@ -61,13 +66,11 @@ module GraphQL
61
66
  if !analyzers_to_run.empty?
62
67
  visitor = GraphQL::Analysis::Visitor.new(
63
68
  query: query,
64
- analyzers: analyzers_to_run
69
+ analyzers: analyzers_to_run,
70
+ timeout: query.validate_timeout_remaining,
65
71
  )
66
72
 
67
- # `nil` or `0` causes no timeout
68
- Timeout::timeout(query.validate_timeout_remaining) do
69
- visitor.visit
70
- end
73
+ visitor.visit
71
74
 
72
75
  if !visitor.rescued_errors.empty?
73
76
  return visitor.rescued_errors
@@ -79,8 +82,8 @@ module GraphQL
79
82
  []
80
83
  end
81
84
  end
82
- rescue Timeout::Error
83
- [GraphQL::AnalysisError.new("Timeout on validation of query")]
85
+ rescue TimeoutError => err
86
+ [err]
84
87
  rescue GraphQL::UnauthorizedError, GraphQL::ExecutionError
85
88
  # This error was raised during analysis and will be returned the client before execution
86
89
  []