mongoid 7.6.0 → 7.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ff7d60d6b900150abc528548490b2b678708dfe05af7818255c48511bb0162a
4
- data.tar.gz: a17bd4adb82448f3577cec52a0fab82660227d5e8bce6a9058a499449375da04
3
+ metadata.gz: 7d6b4091f7d54b2e65649f2c41aa1ae9d79ba5d45eda1f25402a977921af378b
4
+ data.tar.gz: 11c42c8f504d870e6d49a823874855c88bec5cae51254b2e3246d4e6fe3b5992
5
5
  SHA512:
6
- metadata.gz: 52adb1bd5f193bf327925d8650bffb9ea9761395b0b7e691f6c18f3ea9a56cc94c6d4824dd7b29e2316ecbb916a338430f4e96dde248982f78b451fb580afe62
7
- data.tar.gz: 0a5147d6b5c686c8e103b41de6424ef6835097ca98abbc5d2b883f29f381cb090a5ad2c4a896d640dbe0216d49824a4eeca061b201d2e34e8d1228393440153d
6
+ metadata.gz: 42b67f419f6e4632f25d6b498e774627d0f7111c7d05cdab5d02fe9f33189448a7abb572b2c351d97d2ce97a22cf2cdc3e96e61b3163337a6d4e6f921c69522a
7
+ data.tar.gz: 48991d86f760c6f3a1b5cd87b8a19f501a1c7ebbb5cf07c5f9164c116e999ae0e4304b92b55225e7b3ca1252ee9675e4987f5998cd627f0fa1db451ddf524b50
@@ -95,6 +95,10 @@ module Mongoid
95
95
  [MONGOID_WRAPPING_LIBRARY] + options[:wrapping_libraries]
96
96
  else
97
97
  [MONGOID_WRAPPING_LIBRARY]
98
+ end.tap do |wrap|
99
+ if defined?(::Rails) && ::Rails.respond_to?(:version)
100
+ wrap << { name: 'Rails', version: ::Rails.version }
101
+ end
98
102
  end
99
103
  options[:wrapping_libraries] = wrap_lib
100
104
  end
@@ -163,6 +163,28 @@ module Mongoid
163
163
  true
164
164
  end
165
165
 
166
+ ALLOWED_TO_CRITERIA_METHODS = %i[
167
+ all all_in all_of and any_in any_of asc ascending
168
+ batch_size between
169
+ collation comment cursor_type
170
+ desc descending
171
+ elem_match eq exists extras
172
+ geo_spatial group gt gte
173
+ hint
174
+ in includes
175
+ limit lt lte
176
+ max_distance max_scan max_time_ms merge mod
177
+ ne near near_sphere nin no_timeout none none_of nor not not_in
178
+ offset only or order order_by
179
+ project
180
+ raw read reorder
181
+ scoped skip slice snapshot
182
+ text_search type
183
+ unscoped unwind
184
+ where with_size with_type without
185
+ ].freeze
186
+ private_constant :ALLOWED_TO_CRITERIA_METHODS
187
+
166
188
  # Convert this hash to a criteria. Will iterate over each keys in the
167
189
  # hash which must correspond to method on a criteria object. The hash
168
190
  # must also include a "klass" key.
@@ -174,7 +196,11 @@ module Mongoid
174
196
  def to_criteria
175
197
  criteria = Criteria.new(delete(:klass) || delete("klass"))
176
198
  each_pair do |method, args|
177
- criteria = criteria.__send__(method, args)
199
+ method_sym = method.to_sym
200
+ unless ALLOWED_TO_CRITERIA_METHODS.include?(method_sym)
201
+ raise ArgumentError, "Method '#{method}' is not allowed in to_criteria"
202
+ end
203
+ criteria = criteria.public_send(method_sym, args)
178
204
  end
179
205
  criteria
180
206
  end
@@ -5,5 +5,5 @@ module Mongoid
5
5
  #
6
6
  # Note that this file is automatically updated via `rake candidate:create`.
7
7
  # Manual changes to this file will be overwritten by that rake task.
8
- VERSION = '7.6.0'
8
+ VERSION = '7.6.1'
9
9
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
 
3
4
  require "spec_helper"
4
5
 
@@ -29,6 +30,34 @@ describe Mongoid::Clients::Factory do
29
30
  end
30
31
  end
31
32
 
33
+ shared_examples_for 'includes rails wrapping library' do
34
+ context 'when Rails is available' do
35
+ around do |example|
36
+ rails_was_defined = defined?(::Rails)
37
+
38
+ if !rails_was_defined || !::Rails.respond_to?(:version)
39
+ module ::Rails
40
+ def self.version
41
+ '6.1.0'
42
+ end
43
+ end
44
+ end
45
+
46
+ example.run
47
+
48
+ if !rails_was_defined
49
+ Object.send(:remove_const, :Rails) if defined?(::Rails)
50
+ end
51
+ end
52
+
53
+ it 'adds Rails as another wrapping library' do
54
+ expect(client.options[:wrapping_libraries]).to include(
55
+ {'name' => 'Rails', 'version' => '6.1.0'},
56
+ )
57
+ end
58
+ end
59
+ end
60
+
32
61
  describe ".create" do
33
62
 
34
63
  context "when provided a name" do
@@ -116,6 +145,8 @@ describe Mongoid::Clients::Factory do
116
145
  ]
117
146
  end
118
147
  end
148
+
149
+ it_behaves_like 'includes rails wrapping library'
119
150
  end
120
151
  end
121
152
 
@@ -467,4 +467,240 @@ describe Mongoid::Extensions::Hash do
467
467
 
468
468
  it_behaves_like 'unsatisfiable criteria method'
469
469
  end
470
+
471
+ describe '#to_criteria' do
472
+ subject(:criteria) { hash.to_criteria }
473
+
474
+ context 'when klass is specified' do
475
+ let(:hash) do
476
+ { klass: Band, where: { name: 'Songs Ohia' } }
477
+ end
478
+
479
+ it 'returns a criteria' do
480
+ expect(criteria).to be_a(Mongoid::Criteria)
481
+ end
482
+
483
+ it 'sets the klass' do
484
+ expect(criteria.klass).to eq(Band)
485
+ end
486
+
487
+ it 'sets the selector' do
488
+ expect(criteria.selector).to eq({ 'name' => 'Songs Ohia' })
489
+ end
490
+ end
491
+
492
+ context 'when klass is missing' do
493
+ let(:hash) do
494
+ { where: { name: 'Songs Ohia' } }
495
+ end
496
+
497
+ it 'returns a criteria' do
498
+ expect(criteria).to be_a(Mongoid::Criteria)
499
+ end
500
+
501
+ it 'has klass nil' do
502
+ expect(criteria.klass).to be_nil
503
+ end
504
+
505
+ it 'sets the selector' do
506
+ expect(criteria.selector).to eq({ 'name' => 'Songs Ohia' })
507
+ end
508
+ end
509
+
510
+ context 'with allowed methods' do
511
+ context 'when using multiple query methods' do
512
+ let(:hash) do
513
+ {
514
+ klass: Band,
515
+ where: { active: true },
516
+ limit: 10,
517
+ skip: 5,
518
+ order_by: { name: 1 }
519
+ }
520
+ end
521
+
522
+ it 'applies all methods successfully' do
523
+ expect(criteria.selector).to eq({ 'active' => true })
524
+ expect(criteria.options[:limit]).to eq(10)
525
+ expect(criteria.options[:skip]).to eq(5)
526
+ expect(criteria.options[:sort]).to eq({ 'name' => 1 })
527
+ end
528
+ end
529
+
530
+ context 'when using query selector methods' do
531
+ let(:hash) do
532
+ {
533
+ klass: Band,
534
+ gt: { members: 2 },
535
+ in: { genre: ['rock', 'metal'] }
536
+ }
537
+ end
538
+
539
+ it 'applies selector methods' do
540
+ expect(criteria.selector['members']).to eq({ '$gt' => 2 })
541
+ expect(criteria.selector['genre']).to eq({ '$in' => ['rock', 'metal'] })
542
+ end
543
+ end
544
+
545
+ context 'when using aggregation methods' do
546
+ let(:hash) do
547
+ {
548
+ klass: Band,
549
+ project: { name: 1, members: 1 }
550
+ }
551
+ end
552
+
553
+ it 'applies aggregation methods' do
554
+ expect { criteria }.not_to raise_error
555
+ end
556
+ end
557
+ end
558
+
559
+ context 'with disallowed methods' do
560
+ context 'when attempting to call create' do
561
+ let(:hash) do
562
+ { klass: Band, create: { name: 'Malicious' } }
563
+ end
564
+
565
+ it 'raises ArgumentError' do
566
+ expect { criteria }.to raise_error(ArgumentError, "Method 'create' is not allowed in to_criteria")
567
+ end
568
+ end
569
+
570
+ context 'when attempting to call create!' do
571
+ let(:hash) do
572
+ { klass: Band, 'create!': { name: 'Malicious' } }
573
+ end
574
+
575
+ it 'raises ArgumentError' do
576
+ expect { criteria }.to raise_error(ArgumentError, "Method 'create!' is not allowed in to_criteria")
577
+ end
578
+ end
579
+
580
+ context 'when attempting to call build' do
581
+ let(:hash) do
582
+ { klass: Band, build: { name: 'Malicious' } }
583
+ end
584
+
585
+ it 'raises ArgumentError' do
586
+ expect { criteria }.to raise_error(ArgumentError, "Method 'build' is not allowed in to_criteria")
587
+ end
588
+ end
589
+
590
+ context 'when attempting to call find' do
591
+ let(:hash) do
592
+ { klass: Band, find: 'some_id' }
593
+ end
594
+
595
+ it 'raises ArgumentError' do
596
+ expect { criteria }.to raise_error(ArgumentError, "Method 'find' is not allowed in to_criteria")
597
+ end
598
+ end
599
+
600
+ context 'when attempting to call execute_or_raise' do
601
+ let(:hash) do
602
+ { klass: Band, execute_or_raise: ['id1', 'id2'] }
603
+ end
604
+
605
+ it 'raises ArgumentError' do
606
+ expect { criteria }.to raise_error(ArgumentError, "Method 'execute_or_raise' is not allowed in to_criteria")
607
+ end
608
+ end
609
+
610
+ context 'when attempting to call new' do
611
+ let(:hash) do
612
+ { klass: Band, new: { name: 'Test' } }
613
+ end
614
+
615
+ it 'raises ArgumentError' do
616
+ expect { criteria }.to raise_error(ArgumentError, "Method 'new' is not allowed in to_criteria")
617
+ end
618
+ end
619
+
620
+ context 'when allowed method is combined with disallowed method' do
621
+ let(:hash) do
622
+ {
623
+ klass: Band,
624
+ where: { active: true },
625
+ create: { name: 'Malicious' }
626
+ }
627
+ end
628
+
629
+ it 'raises ArgumentError before executing any methods' do
630
+ expect { criteria }.to raise_error(ArgumentError, "Method 'create' is not allowed in to_criteria")
631
+ end
632
+ end
633
+ end
634
+
635
+ context 'security validation' do
636
+ # This test ensures that ALL public methods not in the allowlist are blocked
637
+ it 'blocks all dangerous public methods' do
638
+ dangerous_methods = %i[
639
+ build create create! new
640
+ find find_or_create_by find_or_create_by! find_or_initialize_by
641
+ first_or_create first_or_create! first_or_initialize
642
+ execute_or_raise multiple_from_db for_ids
643
+ documents= inclusions= scoping_options=
644
+ initialize freeze as_json
645
+ ]
646
+
647
+ dangerous_methods.each do |method|
648
+ hash = { klass: Band, method => 'arg' }
649
+ expect { hash.to_criteria }.to raise_error(
650
+ ArgumentError,
651
+ "Method '#{method}' is not allowed in to_criteria"
652
+ ), "Expected method '#{method}' to be blocked but it was allowed"
653
+ end
654
+ end
655
+
656
+ it 'blocks dangerous inherited methods from Object' do
657
+ # Critical security test: block send, instance_eval, etc.
658
+ inherited_dangerous = %i[
659
+ send __send__ instance_eval instance_exec
660
+ instance_variable_set method
661
+ ]
662
+
663
+ inherited_dangerous.each do |method|
664
+ hash = { klass: Band, method => 'arg' }
665
+ expect { hash.to_criteria }.to raise_error(
666
+ ArgumentError,
667
+ "Method '#{method}' is not allowed in to_criteria"
668
+ ), "Expected inherited method '#{method}' to be blocked"
669
+ end
670
+ end
671
+
672
+ it 'blocks Enumerable execution methods' do
673
+ # to_criteria should build queries, not execute them
674
+ enumerable_methods = %i[each map select count sum]
675
+
676
+ enumerable_methods.each do |method|
677
+ hash = { klass: Band, method => 'arg' }
678
+ expect { hash.to_criteria }.to raise_error(
679
+ ArgumentError,
680
+ "Method '#{method}' is not allowed in to_criteria"
681
+ ), "Expected Enumerable method '#{method}' to be blocked"
682
+ end
683
+ end
684
+
685
+ it 'allows all whitelisted methods' do
686
+ # Sample of allowed methods from each category
687
+ allowed_sample = {
688
+ where: { name: 'Test' }, # Query selector
689
+ limit: 10, # Query option
690
+ skip: 5, # Query option
691
+ gt: { age: 18 }, # Query selector
692
+ in: { status: ['active'] }, # Query selector
693
+ ascending: :name, # Sorting
694
+ includes: :notes, # Eager loading
695
+ merge: { klass: Band }, # Merge
696
+ }
697
+
698
+ allowed_sample.each do |method, args|
699
+ hash = { klass: Band, method => args }
700
+ expect { hash.to_criteria }.not_to raise_error,
701
+ "Expected method '#{method}' to be allowed but it was blocked"
702
+ end
703
+ end
704
+ end
705
+ end
470
706
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.6.0
4
+ version: 7.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - The MongoDB Ruby Team
@@ -1130,7 +1130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1130
1130
  - !ruby/object:Gem::Version
1131
1131
  version: 1.3.6
1132
1132
  requirements: []
1133
- rubygems_version: 4.0.1
1133
+ rubygems_version: 4.0.4
1134
1134
  specification_version: 4
1135
1135
  summary: Elegant Persistence in Ruby for MongoDB.
1136
1136
  test_files: