diff --git a/Rakefile b/Rakefile index c55bc22c7ae..d72a69c0509 100644 --- a/Rakefile +++ b/Rakefile @@ -264,6 +264,12 @@ TEST_METADATA = { 'rails5-mysql2' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ❌ 3.0 / ❌ 3.1 / ❌ 3.2 / ❌ 3.3 / ❌ jruby', 'rails6-mysql2' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ❌ 3.0 / ❌ 3.1 / ❌ 3.2 / ❌ 3.3 / ❌ jruby', 'rails61-mysql2' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ❌ jruby' + }, + 'appsec:graphql' => { + 'graphql-2.2' => '❌ 2.5 / ❌ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', + 'graphql-2.1' => '❌ 2.5 / ❌ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', + 'graphql-2.0' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', + 'graphql-1.13' => '❌ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby', } }.freeze # rubocop:enable Layout/HashAlignment @@ -505,7 +511,7 @@ namespace :spec do end namespace :appsec do - task all: [:main, :rack, :rails, :sinatra, :devise] + task all: [:main, :rack, :rails, :sinatra, :devise, :graphql] # Datadog AppSec main specs desc '' # "Explicitly hiding from `rake -T`" @@ -522,6 +528,7 @@ namespace :spec do :sinatra, :rails, :devise, + :graphql, ].each do |contrib| desc '' # "Explicitly hiding from `rake -T`" RSpec::Core::RakeTask.new(contrib) do |t, args| diff --git a/appraisal/ruby-3.2.rb b/appraisal/ruby-3.2.rb index 6b223997641..d1ae49625a5 100644 --- a/appraisal/ruby-3.2.rb +++ b/appraisal/ruby-3.2.rb @@ -135,7 +135,11 @@ '1.13', ].each do |v| appraise "graphql-#{v}" do + gem 'rails', '~> 6.1.0' gem 'graphql', "~> #{v}.0" + gem 'sprockets', '< 4' + gem 'lograge', '~> 0.11' + gem 'net-smtp' end end diff --git a/docker-compose.yml b/docker-compose.yml index aad1a38ca5c..1ad0e3dadad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -338,7 +338,7 @@ services: - MYSQL_PASSWORD=$TEST_MYSQL_PASSWORD - MYSQL_USER=$TEST_MYSQL_USER command: - - '--default-authentication-plugin=mysql_native_password' + - '--mysql_native_password=ON' expose: - "3306" ports: diff --git a/gemfiles/ruby_3.2_graphql_1.13.gemfile b/gemfiles/ruby_3.2_graphql_1.13.gemfile index 6cad3cef107..7f88d20e46e 100644 --- a/gemfiles/ruby_3.2_graphql_1.13.gemfile +++ b/gemfiles/ruby_3.2_graphql_1.13.gemfile @@ -36,7 +36,11 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "rails", "~> 6.1.0" gem "graphql", "~> 1.13.0" +gem "sprockets", "< 4" +gem "lograge", "~> 0.11" +gem "net-smtp" group :check do diff --git a/gemfiles/ruby_3.2_graphql_1.13.gemfile.lock b/gemfiles/ruby_3.2_graphql_1.13.gemfile.lock index a671b4fd458..717d0615e21 100644 --- a/gemfiles/ruby_3.2_graphql_1.13.gemfile.lock +++ b/gemfiles/ruby_3.2_graphql_1.13.gemfile.lock @@ -20,6 +20,65 @@ PATH GEM remote: https://rubygems.org/ specs: + actioncable (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (>= 2.7.1) + actionmailer (6.1.7.6) + actionpack (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.7.6) + actionview (= 6.1.7.6) + activesupport (= 6.1.7.6) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.6) + actionpack (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + nokogiri (>= 1.8.5) + actionview (6.1.7.6) + activesupport (= 6.1.7.6) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.6) + activesupport (= 6.1.7.6) + globalid (>= 0.3.6) + activemodel (6.1.7.6) + activesupport (= 6.1.7.6) + activerecord (6.1.7.6) + activemodel (= 6.1.7.6) + activesupport (= 6.1.7.6) + activestorage (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activesupport (= 6.1.7.6) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.6) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) appraisal (2.4.1) @@ -39,18 +98,25 @@ GEM concurrent-ruby (1.2.3) crack (0.4.5) rexml + crass (1.0.6) cri (2.15.11) + date (3.3.4) debase-ruby_core_source (3.3.1) debug_inspector (1.2.0) diff-lcs (1.5.0) docile (1.4.0) dogstatsd-ruby (5.6.1) + erubi (1.12.0) extlz4 (0.3.4) ffi (1.16.3) + globalid (1.2.1) + activesupport (>= 6.1) google-protobuf (3.25.2-aarch64-linux) google-protobuf (3.25.2-x86_64-linux) graphql (1.13.21) hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) json (2.7.1) json-schema (2.8.1) addressable (>= 2.4) @@ -60,9 +126,37 @@ GEM ffi (~> 1.0) libddwaf (1.14.0.0.0-x86_64-linux) ffi (~> 1.0) + lograge (0.14.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) + request_store (~> 1.0) + loofah (2.22.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) memory_profiler (0.9.14) method_source (1.0.0) + mini_mime (1.1.5) + minitest (5.22.3) msgpack (1.7.2) + net-imap (0.4.5) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.4.0) + net-protocol + nio4r (2.6.1) + nokogiri (1.15.5-aarch64-linux) + racc (~> 1.4) os (1.1.4) parallel (1.24.0) parser (3.3.0.5) @@ -77,12 +171,45 @@ GEM pry (~> 0.13) public_suffix (5.0.4) racc (1.7.3) + rack (2.2.9) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.6) + actioncable (= 6.1.7.6) + actionmailbox (= 6.1.7.6) + actionmailer (= 6.1.7.6) + actionpack (= 6.1.7.6) + actiontext (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activemodel (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + bundler (>= 1.15.0) + railties (= 6.1.7.6) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + method_source + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) rake (13.1.0) rake-compiler (1.2.6) rake redcarpet (3.6.0) regexp_parser (2.9.0) + request_store (1.5.1) + rack (>= 1.4) rexml (3.2.8) strscan (>= 3.0.9) rspec (3.12.0) @@ -135,8 +262,18 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) strscan (3.1.0) thor (1.3.0) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) warning (1.3.0) webmock (3.19.1) @@ -144,7 +281,11 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) yard (0.9.34) + zeitwerk (2.6.12) PLATFORMS aarch64-linux @@ -163,11 +304,14 @@ DEPENDENCIES google-protobuf (~> 3.0, != 3.7.1, != 3.7.0) graphql (~> 1.13.0) json-schema (< 3) + lograge (~> 0.11) memory_profiler (~> 0.9) + net-smtp os (~> 1.1) pimpmychangelog (>= 0.1.2) pry pry-stack_explorer + rails (~> 6.1.0) rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) redcarpet (~> 3.4) @@ -183,10 +327,11 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) + sprockets (< 4) warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.7.0) yard (~> 0.9) BUNDLED WITH - 2.3.26 + 2.3.27 diff --git a/gemfiles/ruby_3.2_graphql_2.0.gemfile b/gemfiles/ruby_3.2_graphql_2.0.gemfile index f86d1bfe65d..1dc494e0d7a 100644 --- a/gemfiles/ruby_3.2_graphql_2.0.gemfile +++ b/gemfiles/ruby_3.2_graphql_2.0.gemfile @@ -36,7 +36,11 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "rails", "~> 6.1.0" gem "graphql", "~> 2.0.0" +gem "sprockets", "< 4" +gem "lograge", "~> 0.11" +gem "net-smtp" group :check do diff --git a/gemfiles/ruby_3.2_graphql_2.0.gemfile.lock b/gemfiles/ruby_3.2_graphql_2.0.gemfile.lock index 79924f99aee..6c31713a452 100644 --- a/gemfiles/ruby_3.2_graphql_2.0.gemfile.lock +++ b/gemfiles/ruby_3.2_graphql_2.0.gemfile.lock @@ -20,6 +20,65 @@ PATH GEM remote: https://rubygems.org/ specs: + actioncable (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (>= 2.7.1) + actionmailer (6.1.7.6) + actionpack (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.7.6) + actionview (= 6.1.7.6) + activesupport (= 6.1.7.6) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.6) + actionpack (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + nokogiri (>= 1.8.5) + actionview (6.1.7.6) + activesupport (= 6.1.7.6) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.6) + activesupport (= 6.1.7.6) + globalid (>= 0.3.6) + activemodel (6.1.7.6) + activesupport (= 6.1.7.6) + activerecord (6.1.7.6) + activemodel (= 6.1.7.6) + activesupport (= 6.1.7.6) + activestorage (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activesupport (= 6.1.7.6) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.6) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) appraisal (2.4.1) @@ -39,18 +98,25 @@ GEM concurrent-ruby (1.2.3) crack (0.4.5) rexml + crass (1.0.6) cri (2.15.11) + date (3.3.4) debase-ruby_core_source (3.3.1) debug_inspector (1.2.0) diff-lcs (1.5.0) docile (1.4.0) dogstatsd-ruby (5.6.1) + erubi (1.12.0) extlz4 (0.3.4) ffi (1.16.3) + globalid (1.2.1) + activesupport (>= 6.1) google-protobuf (3.25.2-aarch64-linux) google-protobuf (3.25.2-x86_64-linux) graphql (2.0.28) hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) json (2.7.1) json-schema (2.8.1) addressable (>= 2.4) @@ -60,9 +126,37 @@ GEM ffi (~> 1.0) libddwaf (1.14.0.0.0-x86_64-linux) ffi (~> 1.0) + lograge (0.14.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) + request_store (~> 1.0) + loofah (2.22.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) memory_profiler (0.9.14) method_source (1.0.0) + mini_mime (1.1.5) + minitest (5.22.3) msgpack (1.7.2) + net-imap (0.4.5) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.4.0) + net-protocol + nio4r (2.6.1) + nokogiri (1.15.5-aarch64-linux) + racc (~> 1.4) os (1.1.4) parallel (1.24.0) parser (3.3.0.5) @@ -77,12 +171,45 @@ GEM pry (~> 0.13) public_suffix (5.0.4) racc (1.7.3) + rack (2.2.9) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.6) + actioncable (= 6.1.7.6) + actionmailbox (= 6.1.7.6) + actionmailer (= 6.1.7.6) + actionpack (= 6.1.7.6) + actiontext (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activemodel (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + bundler (>= 1.15.0) + railties (= 6.1.7.6) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + method_source + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) rake (13.1.0) rake-compiler (1.2.6) rake redcarpet (3.6.0) regexp_parser (2.9.0) + request_store (1.5.1) + rack (>= 1.4) rexml (3.2.8) strscan (>= 3.0.9) rspec (3.12.0) @@ -135,8 +262,18 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) strscan (3.1.0) thor (1.3.0) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) warning (1.3.0) webmock (3.19.1) @@ -144,7 +281,11 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) yard (0.9.34) + zeitwerk (2.6.12) PLATFORMS aarch64-linux @@ -163,11 +304,14 @@ DEPENDENCIES google-protobuf (~> 3.0, != 3.7.1, != 3.7.0) graphql (~> 2.0.0) json-schema (< 3) + lograge (~> 0.11) memory_profiler (~> 0.9) + net-smtp os (~> 1.1) pimpmychangelog (>= 0.1.2) pry pry-stack_explorer + rails (~> 6.1.0) rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) redcarpet (~> 3.4) @@ -183,10 +327,11 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) + sprockets (< 4) warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.7.0) yard (~> 0.9) BUNDLED WITH - 2.3.26 + 2.3.27 diff --git a/gemfiles/ruby_3.2_graphql_2.1.gemfile b/gemfiles/ruby_3.2_graphql_2.1.gemfile index aaa8267b197..371c34999a7 100644 --- a/gemfiles/ruby_3.2_graphql_2.1.gemfile +++ b/gemfiles/ruby_3.2_graphql_2.1.gemfile @@ -36,7 +36,11 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "rails", "~> 6.1.0" gem "graphql", "~> 2.1.0" +gem "sprockets", "< 4" +gem "lograge", "~> 0.11" +gem "net-smtp" group :check do diff --git a/gemfiles/ruby_3.2_graphql_2.1.gemfile.lock b/gemfiles/ruby_3.2_graphql_2.1.gemfile.lock index a17a5e38b3a..ba613c1681b 100644 --- a/gemfiles/ruby_3.2_graphql_2.1.gemfile.lock +++ b/gemfiles/ruby_3.2_graphql_2.1.gemfile.lock @@ -20,6 +20,65 @@ PATH GEM remote: https://rubygems.org/ specs: + actioncable (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (>= 2.7.1) + actionmailer (6.1.7.6) + actionpack (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.7.6) + actionview (= 6.1.7.6) + activesupport (= 6.1.7.6) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.6) + actionpack (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + nokogiri (>= 1.8.5) + actionview (6.1.7.6) + activesupport (= 6.1.7.6) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.6) + activesupport (= 6.1.7.6) + globalid (>= 0.3.6) + activemodel (6.1.7.6) + activesupport (= 6.1.7.6) + activerecord (6.1.7.6) + activemodel (= 6.1.7.6) + activesupport (= 6.1.7.6) + activestorage (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activesupport (= 6.1.7.6) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.6) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) appraisal (2.4.1) @@ -39,19 +98,26 @@ GEM concurrent-ruby (1.2.3) crack (0.4.5) rexml + crass (1.0.6) cri (2.15.11) + date (3.3.4) debase-ruby_core_source (3.3.1) debug_inspector (1.2.0) diff-lcs (1.5.0) docile (1.4.0) dogstatsd-ruby (5.6.1) + erubi (1.12.0) extlz4 (0.3.4) ffi (1.16.3) + globalid (1.2.1) + activesupport (>= 6.1) google-protobuf (3.25.2-aarch64-linux) google-protobuf (3.25.2-x86_64-linux) graphql (2.1.11) racc (~> 1.4) hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) json (2.7.1) json-schema (2.8.1) addressable (>= 2.4) @@ -61,9 +127,37 @@ GEM ffi (~> 1.0) libddwaf (1.14.0.0.0-x86_64-linux) ffi (~> 1.0) + lograge (0.14.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) + request_store (~> 1.0) + loofah (2.22.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) memory_profiler (0.9.14) method_source (1.0.0) + mini_mime (1.1.5) + minitest (5.22.3) msgpack (1.7.2) + net-imap (0.4.5) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.4.0) + net-protocol + nio4r (2.6.1) + nokogiri (1.15.5-aarch64-linux) + racc (~> 1.4) os (1.1.4) parallel (1.24.0) parser (3.3.0.5) @@ -78,12 +172,45 @@ GEM pry (~> 0.13) public_suffix (5.0.4) racc (1.7.3) + rack (2.2.9) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.6) + actioncable (= 6.1.7.6) + actionmailbox (= 6.1.7.6) + actionmailer (= 6.1.7.6) + actionpack (= 6.1.7.6) + actiontext (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activemodel (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + bundler (>= 1.15.0) + railties (= 6.1.7.6) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + method_source + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) rake (13.1.0) rake-compiler (1.2.6) rake redcarpet (3.6.0) regexp_parser (2.9.0) + request_store (1.5.1) + rack (>= 1.4) rexml (3.2.8) strscan (>= 3.0.9) rspec (3.12.0) @@ -136,8 +263,18 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) strscan (3.1.0) thor (1.3.0) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) warning (1.3.0) webmock (3.19.1) @@ -145,7 +282,11 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) yard (0.9.34) + zeitwerk (2.6.12) PLATFORMS aarch64-linux @@ -164,11 +305,14 @@ DEPENDENCIES google-protobuf (~> 3.0, != 3.7.1, != 3.7.0) graphql (~> 2.1.0) json-schema (< 3) + lograge (~> 0.11) memory_profiler (~> 0.9) + net-smtp os (~> 1.1) pimpmychangelog (>= 0.1.2) pry pry-stack_explorer + rails (~> 6.1.0) rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) redcarpet (~> 3.4) @@ -184,10 +328,11 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) + sprockets (< 4) warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.7.0) yard (~> 0.9) BUNDLED WITH - 2.3.26 + 2.3.27 diff --git a/gemfiles/ruby_3.2_graphql_2.2.gemfile b/gemfiles/ruby_3.2_graphql_2.2.gemfile index b5c96a33794..1fb8bc35f98 100644 --- a/gemfiles/ruby_3.2_graphql_2.2.gemfile +++ b/gemfiles/ruby_3.2_graphql_2.2.gemfile @@ -36,7 +36,11 @@ gem "rubocop-performance", "~> 1.9", require: false gem "rubocop-rspec", ["~> 2.20", "< 2.21"], require: false gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "rails", "~> 6.1.0" gem "graphql", "~> 2.2.0" +gem "sprockets", "< 4" +gem "lograge", "~> 0.11" +gem "net-smtp" group :check do diff --git a/gemfiles/ruby_3.2_graphql_2.2.gemfile.lock b/gemfiles/ruby_3.2_graphql_2.2.gemfile.lock index 1ac7b05dc61..ca1485a1b16 100644 --- a/gemfiles/ruby_3.2_graphql_2.2.gemfile.lock +++ b/gemfiles/ruby_3.2_graphql_2.2.gemfile.lock @@ -20,6 +20,65 @@ PATH GEM remote: https://rubygems.org/ specs: + actioncable (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (>= 2.7.1) + actionmailer (6.1.7.6) + actionpack (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.7.6) + actionview (= 6.1.7.6) + activesupport (= 6.1.7.6) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.6) + actionpack (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + nokogiri (>= 1.8.5) + actionview (6.1.7.6) + activesupport (= 6.1.7.6) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.6) + activesupport (= 6.1.7.6) + globalid (>= 0.3.6) + activemodel (6.1.7.6) + activesupport (= 6.1.7.6) + activerecord (6.1.7.6) + activemodel (= 6.1.7.6) + activesupport (= 6.1.7.6) + activestorage (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activesupport (= 6.1.7.6) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.6) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) appraisal (2.4.1) @@ -39,19 +98,26 @@ GEM concurrent-ruby (1.2.3) crack (0.4.5) rexml + crass (1.0.6) cri (2.15.11) + date (3.3.4) debase-ruby_core_source (3.3.1) debug_inspector (1.2.0) diff-lcs (1.5.0) docile (1.4.0) dogstatsd-ruby (5.6.1) + erubi (1.12.0) extlz4 (0.3.4) ffi (1.16.3) + globalid (1.2.1) + activesupport (>= 6.1) google-protobuf (3.25.2-aarch64-linux) google-protobuf (3.25.2-x86_64-linux) graphql (2.2.6) racc (~> 1.4) hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) json (2.7.1) json-schema (2.8.1) addressable (>= 2.4) @@ -61,9 +127,37 @@ GEM ffi (~> 1.0) libddwaf (1.14.0.0.0-x86_64-linux) ffi (~> 1.0) + lograge (0.14.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) + request_store (~> 1.0) + loofah (2.22.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.2) memory_profiler (0.9.14) method_source (1.0.0) + mini_mime (1.1.5) + minitest (5.22.3) msgpack (1.7.2) + net-imap (0.4.5) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.4.0) + net-protocol + nio4r (2.6.1) + nokogiri (1.15.5-aarch64-linux) + racc (~> 1.4) os (1.1.4) parallel (1.24.0) parser (3.3.0.5) @@ -78,12 +172,45 @@ GEM pry (~> 0.13) public_suffix (5.0.4) racc (1.7.3) + rack (2.2.9) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.6) + actioncable (= 6.1.7.6) + actionmailbox (= 6.1.7.6) + actionmailer (= 6.1.7.6) + actionpack (= 6.1.7.6) + actiontext (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activemodel (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + bundler (>= 1.15.0) + railties (= 6.1.7.6) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) + method_source + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) rake (13.1.0) rake-compiler (1.2.6) rake redcarpet (3.6.0) regexp_parser (2.9.0) + request_store (1.5.1) + rack (>= 1.4) rexml (3.2.8) strscan (>= 3.0.9) rspec (3.12.0) @@ -136,8 +263,18 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) strscan (3.1.0) thor (1.3.0) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) warning (1.3.0) webmock (3.19.1) @@ -145,7 +282,11 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) yard (0.9.34) + zeitwerk (2.6.12) PLATFORMS aarch64-linux @@ -164,11 +305,14 @@ DEPENDENCIES google-protobuf (~> 3.0, != 3.7.1, != 3.7.0) graphql (~> 2.2.0) json-schema (< 3) + lograge (~> 0.11) memory_profiler (~> 0.9) + net-smtp os (~> 1.1) pimpmychangelog (>= 0.1.2) pry pry-stack_explorer + rails (~> 6.1.0) rake (>= 10.5) rake-compiler (~> 1.1, >= 1.1.1) redcarpet (~> 3.4) @@ -184,10 +328,11 @@ DEPENDENCIES rubocop-rspec (~> 2.20, < 2.21) simplecov! simplecov-cobertura (~> 2.1.0) + sprockets (< 4) warning (~> 1) webmock (>= 3.10.0) webrick (>= 1.7.0) yard (~> 0.9) BUNDLED WITH - 2.3.26 + 2.3.27 diff --git a/lib/datadog/appsec/contrib/graphql/appsec_trace.rb b/lib/datadog/appsec/contrib/graphql/appsec_trace.rb index 72993b184fc..1624e72454a 100644 --- a/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +++ b/lib/datadog/appsec/contrib/graphql/appsec_trace.rb @@ -13,6 +13,23 @@ module GraphQL # We actually don't need to create any span/trace. module AppSecTrace def execute_multiplex(multiplex:) + return super unless Datadog::AppSec.enabled? + + unless Datadog::AppSec.active_scope + ready = false + + Datadog::AppSec.reconfigure_lock do + processor = Datadog::AppSec.processor + + if !processor.nil? && processor.ready? + Datadog::AppSec::Scope.activate_scope(active_trace, active_span, processor) + ready = true + end + end + end + + return super unless ready + gateway_multiplex = Gateway::Multiplex.new(multiplex) multiplex_return, multiplex_response = Instrumentation.gateway.push('graphql.multiplex', gateway_multiplex) do @@ -36,6 +53,24 @@ def execute_multiplex(multiplex:) multiplex_return end + + private + + def active_trace + # TODO: factor out tracing availability detection + + return unless defined?(Datadog::Tracing) + + Datadog::Tracing.active_trace + end + + def active_span + # TODO: factor out tracing availability detection + + return unless defined?(Datadog::Tracing) + + Datadog::Tracing.active_span + end end end end diff --git a/spec/datadog/appsec/contrib/graphql/appsec_trace_spec.rb b/spec/datadog/appsec/contrib/graphql/appsec_trace_spec.rb index 3846b4553e9..391a46d3865 100644 --- a/spec/datadog/appsec/contrib/graphql/appsec_trace_spec.rb +++ b/spec/datadog/appsec/contrib/graphql/appsec_trace_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true +require 'datadog/tracing/contrib/graphql/support/application' + require 'datadog/appsec/spec_helper' -require 'datadog/appsec/contrib/graphql/graphql_helper' require 'datadog/appsec/contrib/graphql/appsec_trace' RSpec.describe Datadog::AppSec::Contrib::GraphQL::AppSecTrace do @@ -38,7 +39,21 @@ include_context 'with GraphQL multiplex' it 'returns the correct result when given an valid multiplex' do - result = schema.multiplex(queries) + result = + if Gem::Version.new(::GraphQL::VERSION) < Gem::Version.new('2.0.0') + schema.multiplex( + queries.map do |query| + { + query: query.query_string, + operation_name: query.operation_name, + variables: query.variables + } + end + ) + else + schema.multiplex(queries) + end + expect(result.map(&:to_h)).to eq( [ { 'data' => { 'user' => { 'name' => 'Bits' } } }, @@ -50,7 +65,21 @@ it 'returns a partially correct result when given a multiplex with an invalid query' do queries << ::GraphQL::Query.new(schema, 'query test{ error(id: 10) { name } }') - result = schema.multiplex(queries) + result = + if Gem::Version.new(::GraphQL::VERSION) < Gem::Version.new('2.0.0') + schema.multiplex( + queries.map do |query| + { + query: query.query_string, + operation_name: query.operation_name, + variables: query.variables + } + end + ) + else + schema.multiplex(queries) + end + expect(result.map(&:to_h)).to eq( [ { 'data' => { 'user' => { 'name' => 'Bits' } } }, diff --git a/spec/datadog/appsec/contrib/graphql/gateway/multiplex_spec.rb b/spec/datadog/appsec/contrib/graphql/gateway/multiplex_spec.rb index 2c0b1e439b9..ba685db18ee 100644 --- a/spec/datadog/appsec/contrib/graphql/gateway/multiplex_spec.rb +++ b/spec/datadog/appsec/contrib/graphql/gateway/multiplex_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'datadog/appsec/spec_helper' -require 'datadog/appsec/contrib/graphql/graphql_helper' +require 'datadog/tracing/contrib/graphql/support/application' +require 'datadog/appsec/spec_helper' require 'datadog/appsec/contrib/graphql/gateway/multiplex' RSpec.describe Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex do diff --git a/spec/datadog/appsec/contrib/graphql/graphql_helper.rb b/spec/datadog/appsec/contrib/graphql/graphql_helper.rb deleted file mode 100644 index b4637c07d50..00000000000 --- a/spec/datadog/appsec/contrib/graphql/graphql_helper.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'graphql' - -class TestUserType < ::GraphQL::Schema::Object - field :id, ::GraphQL::Types::ID, null: false - field :name, ::GraphQL::Types::String, null: true - field :created_at, ::GraphQL::Types::String, null: false - field :updated_at, ::GraphQL::Types::String, null: false -end - -class TestGraphQLQuery < ::GraphQL::Schema::Object - field :user, TestUserType, null: false, description: 'Find an user by ID' do - argument :id, ::GraphQL::Types::ID, required: true - end - - def user(id:) - return OpenStruct.new(id: id, name: 'Caniche') if Integer(id) == 10 - - OpenStruct.new(id: id, name: 'Bits') - end - - field :userByName, TestUserType, null: false, description: 'Find an user by name' do - argument :name, ::GraphQL::Types::String, required: true - end - - # rubocop:disable Naming/MethodName - def userByName(name:) - return OpenStruct.new(id: 10, name: name) if name == 'Caniche' - - OpenStruct.new(id: 1, name: name) - end - # rubocop:enable Naming/MethodName -end - -class TestGraphQLSchema < ::GraphQL::Schema - query(TestGraphQLQuery) -end - -RSpec.shared_context 'with GraphQL schema' do - let(:operation) { Datadog::AppSec::Reactive::Operation.new('test') } - let(:schema) { TestGraphQLSchema } -end - -RSpec.shared_context 'with GraphQL multiplex' do - include_context 'with GraphQL schema' - - let(:first_query) { ::GraphQL::Query.new(schema, 'query test{ user(id: 1) { name } }') } - let(:second_query) { ::GraphQL::Query.new(schema, 'query test{ user(id: 10) { name } }') } - let(:third_query) { ::GraphQL::Query.new(schema, 'query { userByName(name: "Caniche") { id } }') } - let(:queries) { [first_query, second_query, third_query] } - let(:context) { { :dataloader => GraphQL::Dataloader.new(nonblocking: nil) } } - let(:multiplex) do - Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex.new( - ::GraphQL::Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: nil) - ) - end -end diff --git a/spec/datadog/appsec/contrib/graphql/integration_test_spec.rb b/spec/datadog/appsec/contrib/graphql/integration_test_spec.rb new file mode 100644 index 00000000000..0f2e9ed5831 --- /dev/null +++ b/spec/datadog/appsec/contrib/graphql/integration_test_spec.rb @@ -0,0 +1,84 @@ +require 'datadog/tracing/contrib/graphql/support/application' + +require 'datadog/tracing' +require 'datadog/appsec' + +RSpec.describe 'GraphQL integration tests' do + let(:appsec_enabled) { true } + let(:tracing_enabled) { true } + let(:appsec_ruleset) { :recommended } + + let(:block_testattack) do + { + 'version' => '2.2', + 'metadata' => { + 'rules_version' => '1.4.1' + }, + 'rules' => [ + { + id: 'custom-000-000', + name: 'Test Blocking GraphQL WAF', + tags: { + type: 'attack_tool', + category: 'attack_attempt', + cwe: '200', + capec: '1000/118/169', + tool_name: 'Datadog Canary Test', + confidence: '1' + }, + conditions: [ + { + parameters: { + inputs: [ + { + address: 'graphql.server.all_resolvers' + } + ], + options: { + enforce_word_boundary: true + }, + list: [ + '$testattack' + ] + }, + operator: 'phrase_match' + } + ], + transformers: [ + 'lowercase' + ], + on_match: [ + 'block' + ] + } + ] + } + end + + before do + Datadog.configure do |c| + c.tracing.enabled = tracing_enabled + c.tracing.instrument :graphql + + c.appsec.enabled = appsec_enabled + c.appsec.instrument :graphql + c.appsec.ruleset = appsec_ruleset + end + end + + after do + Datadog.configuration.reset! + Datadog.registry[:graphql].reset_configuration! + end + + context 'for an application' do + include_context 'GraphQL test application' + + context 'with a valid query' do + it do + post '/graphql', query: '{ user(id: 1) { name } }' + expect(last_response.body).to eq({ 'data' => { 'user' => { 'name' => 'Bits' } } }.to_json) + end + end + end +end diff --git a/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb b/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb index cd8715fd33f..bae28385837 100644 --- a/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb +++ b/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb @@ -1,7 +1,7 @@ # frozen_literal_string: true require 'datadog/tracing/contrib/graphql/test_helpers' -require 'datadog/appsec/contrib/graphql/graphql_helper' +require 'datadog/tracing/contrib/graphql/support/application' require 'datadog/appsec/spec_helper' require 'datadog/appsec/reactive/operation' @@ -17,8 +17,8 @@ describe '.publish' do it 'propagates multiplex attributes to the operation' do expect(operation).to receive(:publish).with('graphql.server.all_resolvers', expected_arguments) - - described_class.publish(operation, multiplex) + gateway_multiplex = Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex.new(multiplex) + described_class.publish(operation, gateway_multiplex) end end @@ -45,13 +45,14 @@ Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) described_class.subscribe(operation, waf_context) - result = described_class.publish(operation, multiplex) + gateway_multiplex = Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex.new(multiplex) + result = described_class.publish(operation, gateway_multiplex) expect(result).to be_nil end end it_behaves_like 'waf result' do - let(:gateway) { multiplex } + let(:gateway) { Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex.new(multiplex) } end end end diff --git a/spec/datadog/tracing/contrib/graphql/support/application.rb b/spec/datadog/tracing/contrib/graphql/support/application.rb new file mode 100644 index 00000000000..093251fa769 --- /dev/null +++ b/spec/datadog/tracing/contrib/graphql/support/application.rb @@ -0,0 +1,155 @@ +require 'datadog/tracing/contrib/support/spec_helper' + +require 'active_model/railtie' +require 'action_controller/railtie' +require 'action_mailer/railtie' +require 'action_view/railtie' +require 'active_job/railtie' +require 'action_cable/engine' +require 'sprockets/railtie' +require 'rails/test_unit/railtie' + +require 'logger' +require 'graphql' +require 'rack/test' + +require 'spec/datadog/tracing/contrib/rails/support/configuration' +require 'spec/datadog/tracing/contrib/rails/support/application' + +# logger +logger = Logger.new($stdout) +logger.level = Logger::INFO + +# Rails settings +ENV['RAILS_ENV'] = 'test' + +# switch Rails import according to installed +# version; this is controlled with Appraisals +logger.info "Testing against Rails #{Rails.version} with GraphQL #{::GraphQL::VERSION}" + +class TestUserType < ::GraphQL::Schema::Object + field :id, ::GraphQL::Types::ID, null: false + field :name, ::GraphQL::Types::String, null: true + field :created_at, ::GraphQL::Types::String, null: false + field :updated_at, ::GraphQL::Types::String, null: false +end + +class TestGraphQLQuery < ::GraphQL::Schema::Object + field :user, TestUserType, null: false, description: 'Find an user by ID' do + argument :id, ::GraphQL::Types::ID, required: true + end + + def user(id:) + return OpenStruct.new(id: id, name: 'Caniche') if Integer(id) == 10 + + OpenStruct.new(id: id, name: 'Bits') + end + + field :userByName, TestUserType, null: false, description: 'Find an user by name' do + argument :name, ::GraphQL::Types::String, required: true + end + + # rubocop:disable Naming/MethodName + def userByName(name:) + return OpenStruct.new(id: 10, name: name) if name == 'Caniche' + + OpenStruct.new(id: 1, name: name) + end + # rubocop:enable Naming/MethodName +end + +class TestGraphQLSchema < ::GraphQL::Schema + query(TestGraphQLQuery) +end + +def prepare_variables(variables_param) + case variables_param + when String + if variables_param.present? + JSON.parse(variables_param) || {} + else + {} + end + when Hash + variables_param + when ActionController::Parameters + variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables. + when nil + {} + else + raise ArgumentError, "Unexpected parameter: #{variables_param}" + end +end + +RSpec.shared_context 'with GraphQL schema' do + let(:operation) { Datadog::AppSec::Reactive::Operation.new('test') } + let(:schema) { TestGraphQLSchema } +end + +RSpec.shared_context 'with GraphQL multiplex' do + include_context 'with GraphQL schema' + + let(:first_query) { ::GraphQL::Query.new(schema, 'query test{ user(id: 1) { name } }') } + let(:second_query) { ::GraphQL::Query.new(schema, 'query test{ user(id: 10) { name } }') } + let(:third_query) { ::GraphQL::Query.new(schema, 'query { userByName(name: "Caniche") { id } }') } + let(:queries) { [first_query, second_query, third_query] } + let(:context) { { :dataloader => GraphQL::Dataloader.new(nonblocking: nil) } } + let(:multiplex) do + ::GraphQL::Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: nil) + end +end + +RSpec.shared_context 'GraphQL test application' do + let(:no_db) { true } + + include_context 'Rails test application' + include_context 'with GraphQL schema' + include Rack::Test::Methods + + let(:routes) do + { + [:post, '/graphql'] => 'graphql#execute' + } + end + let(:controllers) { [controller] } + + let(:controller) do + stub_const( + 'GraphqlController', + Class.new(ActionController::Base) do + # skip CSRF token check for non-GET requests + begin + if respond_to?(:skip_before_action) + skip_before_action :verify_authenticity_token + else + skip_before_filter :verify_authenticity_token + end + rescue ArgumentError # :verify_authenticity_token might not be defined + nil + end + + def execute + result = if params[:_json] + queries = params[:_json].map do |param| + { + query: param[:query], + operation_name: param[:operationName], + variables: prepare_variables(param[:variables]), + context: {} + } + end + TestGraphQLSchema.multiplex(queries) + else + TestGraphQLSchema.execute( + query: params[:query], + operation_name: params[:operationName], + variables: prepare_variables(params[:variables]), + context: {} + ) + end + render json: result + end + end + ) + end +end diff --git a/spec/datadog/tracing/contrib/rails/rails_helper.rb b/spec/datadog/tracing/contrib/rails/rails_helper.rb index 1fe3866197e..5781beb4175 100644 --- a/spec/datadog/tracing/contrib/rails/rails_helper.rb +++ b/spec/datadog/tracing/contrib/rails/rails_helper.rb @@ -1,7 +1,7 @@ require 'datadog/tracing/contrib/support/spec_helper' require 'logger' -require 'rails' +require 'rails/all' require 'spec/datadog/tracing/contrib/rails/support/configuration' require 'spec/datadog/tracing/contrib/rails/support/database' diff --git a/spec/datadog/tracing/contrib/rails/support/base.rb b/spec/datadog/tracing/contrib/rails/support/base.rb index 2c674c1174a..c659a012aea 100644 --- a/spec/datadog/tracing/contrib/rails/support/base.rb +++ b/spec/datadog/tracing/contrib/rails/support/base.rb @@ -1,5 +1,3 @@ -require 'rails/all' - require_relative 'controllers' require_relative 'models' require_relative 'log_configuration' diff --git a/spec/datadog/tracing/contrib/rails/support/models.rb b/spec/datadog/tracing/contrib/rails/support/models.rb index f55ade1ec75..6c9613c0b25 100644 --- a/spec/datadog/tracing/contrib/rails/support/models.rb +++ b/spec/datadog/tracing/contrib/rails/support/models.rb @@ -1,10 +1,12 @@ RSpec.shared_context 'Rails models' do let(:application_record) do - stub_const( - 'ApplicationRecord', - Class.new(ActiveRecord::Base) do - self.abstract_class = true - end - ) + unless (defined? no_db) && no_db + stub_const( + 'ApplicationRecord', + Class.new(ActiveRecord::Base) do + self.abstract_class = true + end + ) + end end end diff --git a/spec/datadog/tracing/contrib/rails/support/rails6.rb b/spec/datadog/tracing/contrib/rails/support/rails6.rb index 37ccb8d4c8c..1cf229ce59a 100644 --- a/spec/datadog/tracing/contrib/rails/support/rails6.rb +++ b/spec/datadog/tracing/contrib/rails/support/rails6.rb @@ -1,5 +1,3 @@ -require 'rails/all' - if ENV['USE_SIDEKIQ'] require 'sidekiq/testing' require 'datadog/tracing/contrib/sidekiq/server_tracer' @@ -111,7 +109,7 @@ def initialize(files, dirs = {}, &block) append_controllers! # Force connection to initialize, and dump some spans - application_record.connection + application_record.connection unless (defined? no_db) && no_db # Skip default Rails exception page rendering. # This avoid polluting the trace under test @@ -177,11 +175,13 @@ def reset_rails_configuration! # TODO: Remove this side-effect on missing log entries Lograge.remove_existing_log_subscriptions if defined?(::Lograge) - reset_class_variable(ActiveRecord::Railtie::Configuration, :@@options) + if Module.const_defined?(:ActiveRecord) + reset_class_variable(ActiveRecord::Railtie::Configuration, :@@options) - # After `deep_dup`, the sentinel `NULL_OPTION` is inadvertently changed. We restore it here. - if Rails::VERSION::MINOR < 1 - ActiveRecord::Railtie.config.action_view.finalize_compiled_template_methods = ActionView::Railtie::NULL_OPTION + # After `deep_dup`, the sentinel `NULL_OPTION` is inadvertently changed. We restore it here. + if Rails::VERSION::MINOR < 1 + ActiveRecord::Railtie.config.action_view.finalize_compiled_template_methods = ActionView::Railtie::NULL_OPTION + end end reset_class_variable(ActiveSupport::Dependencies, :@@autoload_paths)