Skip to content

Commit 6eca16b

Browse files
authored
Merge commit from fork
[1.13] fix CVE 2025 27407
2 parents ce315de + 54d98a6 commit 6eca16b

File tree

11 files changed

+198
-21
lines changed

11 files changed

+198
-21
lines changed

.rubocop.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require:
22
- ./cop/development/none_without_block_cop
3+
- ./cop/development/no_eval_cop
34
- ./cop/development/no_focus_cop
45
- ./lib/graphql/rubocop/graphql/default_null_true
56
- ./lib/graphql/rubocop/graphql/default_required_true
@@ -52,6 +53,10 @@ Development/NoneWithoutBlockCop:
5253
- "lib/**/*"
5354
- "spec/**/*"
5455

56+
Development/NoEvalCop:
57+
Include:
58+
- "lib/**/*"
59+
5560
Development/NoFocusCop:
5661
Include:
5762
- "spec/**/*"

benchmark/run.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def self.profile_large_introspection
8282
graphql_name("Object#{n}")
8383
20.times do |n2|
8484
field :"field#{n2}", String do
85-
argument :arg, String
85+
argument :input, input_obj_t
8686
end
8787
end
8888
end

cop/development/no_eval_cop.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
require 'rubocop'
3+
4+
module Cop
5+
module Development
6+
class NoEvalCop < RuboCop::Cop::Base
7+
MSG_TEMPLATE = "Don't use `%{eval_method_name}` which accepts strings and may result evaluating unexpected code. Use `%{exec_method_name}` instead, and pass a block."
8+
9+
def on_send(node)
10+
case node.method_name
11+
when :module_eval, :class_eval, :instance_eval
12+
message = MSG_TEMPLATE % { eval_method_name: node.method_name, exec_method_name: node.method_name.to_s.sub("eval", "exec").to_sym }
13+
add_offense node, message: message
14+
end
15+
end
16+
end
17+
end
18+
end

lib/graphql/language/nodes.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ def merge!(new_options)
133133
end
134134

135135
class << self
136+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
137+
136138
# Add a default `#visit_method` and `#children_method_name` using the class name
137139
def inherited(child_class)
138140
super
@@ -276,6 +278,7 @@ def initialize_node #{arguments.join(", ")}
276278
RUBY
277279
end
278280
end
281+
# rubocop:enable Development/NoEvalCop
279282
end
280283
end
281284

lib/graphql/schema/argument.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def from_resolver?
5252
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
5353
arg_name ||= name
5454
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
55+
NameValidator.validate!(@name)
5556
@type_expr = type_expr || type
5657
@description = desc || description
5758
@null = required != true
@@ -85,11 +86,8 @@ def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type
8586
end
8687

8788
if definition_block
88-
if definition_block.arity == 1
89-
instance_exec(self, &definition_block)
90-
else
91-
instance_eval(&definition_block)
92-
end
89+
# `self` will still be self, it will also be the first argument to the block:
90+
instance_exec(self, &definition_block)
9391
end
9492
end
9593

lib/graphql/schema/build_from_definition.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -427,17 +427,18 @@ def build_fields(owner, field_definitions, type_resolver, default_resolve:)
427427

428428
# Don't do this for interfaces
429429
if default_resolve
430-
owner.class_eval <<-RUBY, __FILE__, __LINE__
431-
# frozen_string_literal: true
432-
def #{resolve_method_name}(**args)
433-
field_instance = self.class.get_field("#{field_definition.name}")
434-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
435-
end
436-
RUBY
430+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
437431
end
438432
end
439433
end
440434

435+
def define_field_resolve_method(owner, method_name, field_name)
436+
owner.define_method(method_name) { |**args|
437+
field_instance = self.class.get_field(field_name)
438+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
439+
}
440+
end
441+
441442
def build_resolve_type(lookup_hash, directives, missing_type_handler)
442443
resolve_type_proc = nil
443444
resolve_type_proc = ->(ast_node) {

lib/graphql/schema/enum_value.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil,
5555
end
5656

5757
if block_given?
58-
instance_eval(&block)
58+
instance_exec(self, &block)
5959
end
6060
end
6161

lib/graphql/schema/field.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, functio
232232

233233
@underscored_name = -Member::BuildType.underscore(name_s)
234234
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
235+
NameValidator.validate!(@name)
235236
@description = description
236237
if field.is_a?(GraphQL::Schema::Field)
237238
raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."

lib/graphql/schema/input_object.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,7 @@ class << self
138138
def argument(*args, **kwargs, &block)
139139
argument_defn = super(*args, **kwargs, &block)
140140
# Add a method access
141-
method_name = argument_defn.keyword
142-
class_eval <<-RUBY, __FILE__, __LINE__
143-
def #{method_name}
144-
self[#{method_name.inspect}]
145-
end
146-
RUBY
141+
define_accessor_method(argument_defn.keyword)
147142
argument_defn
148143
end
149144

@@ -253,6 +248,13 @@ def coerce_result(value, ctx)
253248

254249
result
255250
end
251+
252+
private
253+
254+
def define_accessor_method(method_name)
255+
define_method(method_name) { self[method_name] }
256+
alias_method(method_name, method_name)
257+
end
256258
end
257259

258260
private

lib/graphql/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# frozen_string_literal: true
22
module GraphQL
3-
VERSION = "1.13.23"
3+
VERSION = "1.13.24"
44
end

0 commit comments

Comments
 (0)