sentry-raven 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.craft.yml +14 -0
  3. data/.github/workflows/test.yml +77 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +44 -9
  6. data/.scripts/bump-version.sh +9 -0
  7. data/Gemfile +17 -25
  8. data/README.md +3 -2
  9. data/changelog.md +12 -0
  10. data/lib/raven/backtrace.rb +7 -5
  11. data/lib/raven/base.rb +4 -2
  12. data/lib/raven/breadcrumbs.rb +1 -1
  13. data/lib/raven/breadcrumbs/activesupport.rb +10 -10
  14. data/lib/raven/breadcrumbs/logger.rb +3 -3
  15. data/lib/raven/cli.rb +2 -2
  16. data/lib/raven/client.rb +9 -4
  17. data/lib/raven/configuration.rb +15 -5
  18. data/lib/raven/event.rb +4 -2
  19. data/lib/raven/instance.rb +4 -3
  20. data/lib/raven/integrations/delayed_job.rb +13 -14
  21. data/lib/raven/integrations/rack-timeout.rb +2 -3
  22. data/lib/raven/integrations/rack.rb +3 -2
  23. data/lib/raven/integrations/rails.rb +1 -0
  24. data/lib/raven/integrations/rails/active_job.rb +5 -4
  25. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
  26. data/lib/raven/interface.rb +2 -2
  27. data/lib/raven/interfaces/stack_trace.rb +1 -1
  28. data/lib/raven/linecache.rb +5 -2
  29. data/lib/raven/logger.rb +3 -2
  30. data/lib/raven/processor/cookies.rb +16 -6
  31. data/lib/raven/processor/post_data.rb +2 -0
  32. data/lib/raven/processor/removecircularreferences.rb +1 -0
  33. data/lib/raven/processor/sanitizedata.rb +65 -17
  34. data/lib/raven/processor/utf8conversion.rb +2 -0
  35. data/lib/raven/transports.rb +4 -0
  36. data/lib/raven/transports/http.rb +5 -5
  37. data/lib/raven/utils/exception_cause_chain.rb +1 -0
  38. data/lib/raven/utils/real_ip.rb +1 -1
  39. data/lib/raven/version.rb +2 -2
  40. metadata +5 -3
  41. data/.travis.yml +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c812e5ab292c9f9351064bfc75f13bf3f6fff8ea1163a79a0e7da2e5efa9afb
4
- data.tar.gz: 2fb7356fa0b26ee6f8a09a8ab023a21dcee132aa75fd3d1d87fd5f528a1c3366
3
+ metadata.gz: 765b22e2ec433b8ab12697da42d40ba6c0f2f95956bd6ce93b0923b9160f386f
4
+ data.tar.gz: b4f97a6effa6828a10cb7844001852db042627dfe375aae61e93b92d10eb2ba7
5
5
  SHA512:
6
- metadata.gz: b406e28322db6c9e96db35d108521f617c484cdef0367a6ea246709356d61b5917795289c3caf1cc7324f3228fba349a8b3f9a2b45aeaef0d01872848540db2a
7
- data.tar.gz: f079139a9cf52c7344d28d55eec1fc108c237c76c23df7880122e66851d858bce86da817887d5a83f35c9732c619328178bfdd6f8cb6742c84024f0445710fed
6
+ metadata.gz: 25c1a39ce4a97b7e40fa66fc1dd1eb7ae4ef96a6e0956f7600db04717eb8c9f147d83317513ba072db31a4390b678b9c56f406f6ba02377f11b4810a3fef5128
7
+ data.tar.gz: 17adf7a479a1539a9fdc81003b2204c0334334cb54482812339af18cd7a75eb9830e22389fc0eed7e304787b993f8aaca92bb1d1c2f414e88a61858acadf08aa
@@ -0,0 +1,14 @@
1
+ minVersion: '0.9.0'
2
+ github:
3
+ owner: getsentry
4
+ repo: raven-ruby
5
+ changelogPolicy: simple
6
+ preReleaseCommand: ruby .scripts/bump-version.sh
7
+ statusProvider:
8
+ name: github
9
+ targets:
10
+ - name: github
11
+ - name: registry
12
+ type: sdk
13
+ config:
14
+ canonical: 'gem:sentry-raven'
@@ -0,0 +1,77 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - release/**
8
+ pull_request:
9
+ jobs:
10
+ test:
11
+ name: Test on ruby ${{ matrix.ruby_version }} and rails ${{ matrix.rails_version }}
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ matrix:
15
+ rails_version: [0, 4.2, 5.2, 6.0]
16
+ ruby_version: [2.3, 2.4, 2.5, 2.6, 2.7, jruby, head]
17
+ os: [ubuntu-latest]
18
+ include:
19
+ - ruby_version: head
20
+ rails_version: 0
21
+ - ruby_version: 2.7
22
+ rails_version: 6.0
23
+ env: RUBYOPT="--enable-frozen-string-literal --debug=frozen-string-literal"
24
+ exclude:
25
+ - ruby_version: 2.3
26
+ rails_version: 6.0
27
+ - ruby_version: 2.4
28
+ rails_version: 6.0
29
+ - ruby_version: 2.7
30
+ rails_version: 4.2
31
+ - ruby_version: head
32
+ rails_version: 4.2
33
+ - ruby_version: head
34
+ rails_version: 5.2
35
+ - ruby_version: head
36
+ rails_version: 6.0
37
+
38
+ steps:
39
+ - uses: actions/checkout@v1
40
+
41
+ - name: Set up Ruby ${{ matrix.ruby_version }}
42
+ uses: ruby/setup-ruby@v1
43
+ with:
44
+ bundler: 1
45
+ ruby-version: ${{ matrix.ruby_version }}
46
+
47
+ - name: Build with Rails ${{ matrix.rails_version }}
48
+ env:
49
+ RAILS_VERSION: ${{ matrix.rails_version }}
50
+ run: |
51
+ bundle install --jobs 4 --retry 3
52
+ bundle exec rake
53
+
54
+ job_zeus:
55
+ name: Zeus
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v2
59
+ - uses: actions/setup-node@v1
60
+ - name: Set up Ruby
61
+ uses: ruby/setup-ruby@v1
62
+ with:
63
+ ruby-version: 2.6 # Not needed with a .ruby-version file
64
+ - run: bundle install
65
+ - name: Install Zeus
66
+ run: |
67
+ yarn global add @zeus-ci/cli
68
+ echo "::add-path::$(yarn global bin)"
69
+ - name: Upload to Zeus
70
+ env:
71
+ ZEUS_API_TOKEN: ${{ secrets.ZEUS_API_TOKEN }}
72
+ ZEUS_HOOK_BASE: ${{ secrets.ZEUS_HOOK_BASE }}
73
+ run: |
74
+ zeus job update -b $GITHUB_RUN_ID -j $GITHUB_RUN_NUMBER -r $GITHUB_SHA
75
+ gem build sentry-raven.gemspec
76
+ zeus upload -b $GITHUB_RUN_ID -j $GITHUB_RUN_NUMBER -t "application/tar+gem" ./*.gem
77
+ zeus job update --status=passed -b $GITHUB_RUN_ID -j $GITHUB_RUN_NUMBER -r $GITHUB_SHA
data/.gitignore CHANGED
@@ -11,3 +11,5 @@ Gemfile.lock
11
11
  .ruby-gemset
12
12
  .idea
13
13
  *.rdb
14
+
15
+ examples/**/node_modules
@@ -13,33 +13,45 @@ Metrics/ClassLength:
13
13
  Metrics/AbcSize:
14
14
  Max: 40
15
15
 
16
+ Metrics/BlockLength:
17
+ Enabled: false
18
+
16
19
  Metrics/CyclomaticComplexity:
17
20
  Max: 12
18
21
 
19
22
  Metrics/PerceivedComplexity:
20
23
  Max: 11
21
24
 
22
- Metrics/LineLength:
23
- Max: 155
24
-
25
25
  Metrics/MethodLength:
26
26
  Max: 30
27
27
 
28
- Style/SignalException:
28
+ Style/SymbolArray:
29
+ Enabled: false
30
+
31
+ Style/PercentLiteralDelimiters:
32
+ Enabled: false
33
+
34
+ Style/FrozenStringLiteralComment:
29
35
  Enabled: false
30
36
 
31
- Performance/Casecmp:
37
+ Style/SignalException:
32
38
  Enabled: false
33
39
 
34
40
  Style/ClassAndModuleChildren:
35
41
  Enabled: false
36
42
 
43
+ Style/RescueStandardError:
44
+ Enabled: false
45
+
37
46
  Style/ParallelAssignment:
38
47
  Enabled: false
39
48
 
40
49
  Style/Documentation:
41
50
  Enabled: false
42
51
 
52
+ Style/CommentedKeyword:
53
+ Enabled: false
54
+
43
55
  Style/RescueModifier:
44
56
  Enabled: false
45
57
 
@@ -52,10 +64,11 @@ Style/CaseEquality:
52
64
  Style/DoubleNegation:
53
65
  Enabled: false
54
66
 
55
- Style/FileName:
56
- Exclude:
57
- - 'lib/sentry-raven-without-integrations.rb'
58
- - 'lib/sentry-raven.rb'
67
+ Style/GuardClause:
68
+ Enabled: false
69
+
70
+ Style/RedundantBegin:
71
+ Enabled: false
59
72
 
60
73
  Style/NumericLiterals:
61
74
  Exclude:
@@ -64,6 +77,9 @@ Style/NumericLiterals:
64
77
  Style/HashSyntax:
65
78
  EnforcedStyle: hash_rockets
66
79
 
80
+ Style/IfUnlessModifier:
81
+ Enabled: false
82
+
67
83
  Lint/RescueException:
68
84
  Exclude:
69
85
  - 'lib/raven/base.rb'
@@ -72,3 +88,22 @@ Lint/RescueException:
72
88
  - 'lib/raven/integrations/rack.rb'
73
89
  - 'lib/raven/integrations/sidekiq.rb'
74
90
  - 'spec/raven/event_spec.rb'
91
+
92
+ Lint/SuppressedException:
93
+ Enabled: false
94
+
95
+ Lint/AssignmentInCondition:
96
+ Enabled: false
97
+
98
+ Layout/LineLength:
99
+ Max: 155
100
+
101
+ Naming/FileName:
102
+ Exclude:
103
+ - 'lib/sentry-raven-without-integrations.rb'
104
+ - 'lib/sentry-raven.rb'
105
+ - 'lib/raven/integrations/rack-timeout.rb'
106
+
107
+ Naming/MethodParameterName:
108
+ Enabled: false
109
+
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ file_names = ['lib/raven/version.rb']
4
+
5
+ file_names.each do |file_name|
6
+ text = File.read(file_name)
7
+ new_contents = text.gsub(/\d.\d.\d/, ARGV[1])
8
+ File.open(file_name, "w") {|file| file.puts new_contents }
9
+ end
data/Gemfile CHANGED
@@ -2,37 +2,29 @@ source "https://rubygems.org/"
2
2
 
3
3
  gemspec
4
4
 
5
- if ENV["RAILS_VERSION"] && (ENV["RAILS_VERSION"].to_i == 4)
6
- gem "rails", "< 5"
7
- gem "rspec-rails", "> 3"
8
- elsif ENV["RAILS_VERSION"] && (ENV["RAILS_VERSION"].to_i == 0)
9
- # no-op. No Rails.
10
- else
11
- gem "rails", "< 6"
12
- gem "rspec-rails", "> 3"
13
- end
5
+ rails_version = ENV["RAILS_VERSION"].to_f
14
6
 
15
- if RUBY_VERSION < '2.0'
16
- gem "mime-types", "< 3.0.0"
17
- gem "nokogiri", "~> 1.6.8"
18
- gem "rack", "~> 1.6.8"
19
- gem "sidekiq", "< 3.2"
20
- gem "rack-timeout", "0.3.0"
21
- else
22
- gem "rack"
23
- gem "sidekiq"
24
- gem "rack-timeout"
7
+ if rails_version != 0
8
+ gem "rails", "~> #{rails_version}"
9
+ gem "rspec-rails", "~> 4.0"
25
10
  end
11
+
12
+ gem "sidekiq"
13
+
14
+ gem "rack"
15
+ gem "rack-timeout"
16
+
26
17
  gem "pry"
27
- gem "pry-coolline"
28
18
  gem "benchmark-ips"
29
- gem "benchmark-ipsa" if RUBY_VERSION > '2.0'
19
+ gem "benchmark-ipsa"
30
20
  gem "ruby-prof", platform: :mri
31
21
  gem "rake", "> 12"
32
- gem "rubocop", "~> 0.41.1" # Last version that supported 1.9, upgrade to 0.50 after we drop 1.9
33
- gem "rspec", "> 3"
34
- gem "capybara" # rspec system tests
22
+ gem "rubocop", "~> 0.81.0"
23
+ gem "rspec", "~> 3.9.0"
24
+ gem "capybara", "~> 3.15.0" # rspec system tests
35
25
  gem "puma" # rspec system tests
36
26
 
37
27
  gem "timecop"
38
- gem "test-unit", platform: :mri if RUBY_VERSION > '2.2'
28
+ gem "test-unit"
29
+ gem "simplecov"
30
+ gem "codecov"
data/README.md CHANGED
@@ -8,7 +8,8 @@
8
8
  # Raven-Ruby, the Ruby Client for Sentry
9
9
 
10
10
  [![Gem Version](https://img.shields.io/gem/v/sentry-raven.svg)](https://rubygems.org/gems/sentry-raven)
11
- [![Build Status](https://img.shields.io/travis/getsentry/raven-ruby/master.svg)](https://travis-ci.org/getsentry/raven-ruby)
11
+ ![Build Status](https://github.com/getsentry/raven-ruby/workflows/Test/badge.svg)
12
+ [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/raven-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/raven-ruby/branch/master)
12
13
  [![Gem](https://img.shields.io/gem/dt/sentry-raven.svg)](https://rubygems.org/gems/sentry-raven/)
13
14
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-raven&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-raven&package-manager=bundler&version-scheme=semver)
14
15
 
@@ -19,7 +20,7 @@ The official Ruby-language client and integration layer for the [Sentry](https:/
19
20
 
20
21
  ## Requirements
21
22
 
22
- We test on Ruby 2.3, 2.4, 2.5, 2.6 and 2.7 at the latest patchlevel/teeny version. We also support JRuby 9.0. Our Rails integration works with Rails 4.2+ (including Rails 5).
23
+ We test on Ruby 2.3, 2.4, 2.5, 2.6 and 2.7 at the latest patchlevel/teeny version. We also support JRuby 9.0. Our Rails integration works with Rails 4.2+, including Rails 5 and Rails 6.
23
24
 
24
25
  ## Getting Started
25
26
 
@@ -1,3 +1,15 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 3.0.1
6
+
7
+ * fix: Improve SanitizeData processor (#984)
8
+ * fix: Masking cookies as key/pair instead of a single string (#983)
9
+ * fix: Transports classes' requiring issue (#986)
10
+ * fix: Frozen string issues (#977)
11
+ * feat: Officially support Rails 6 (#982)
12
+
1
13
  3.0.0
2
14
  ----
3
15
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## Inspired by Rails' and Airbrake's backtrace parsers.
2
4
 
3
5
  module Raven
@@ -5,16 +7,16 @@ module Raven
5
7
  class Backtrace
6
8
  # Handles backtrace parsing line by line
7
9
  class Line
8
- RB_EXTENSION = ".rb".freeze
10
+ RB_EXTENSION = ".rb"
9
11
  # regexp (optional leading X: on windows, or JRuby9000 class-prefix)
10
12
  RUBY_INPUT_FORMAT = /
11
13
  ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
12
14
  (\d+)
13
15
  (?: :in \s `([^']+)')?$
14
- /x
16
+ /x.freeze
15
17
 
16
18
  # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
17
- JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/
19
+ JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
18
20
 
19
21
  # The file portion of the line (such as app/models/user.rb)
20
22
  attr_reader :file
@@ -74,7 +76,7 @@ module Raven
74
76
 
75
77
  def self.in_app_pattern
76
78
  @in_app_pattern ||= begin
77
- project_root = Raven.configuration.project_root && Raven.configuration.project_root.to_s
79
+ project_root = Raven.configuration.project_root&.to_s
78
80
  Regexp.new("^(#{project_root}/)?#{Raven.configuration.app_dirs_pattern || APP_DIRS_PATTERN}")
79
81
  end
80
82
  end
@@ -84,7 +86,7 @@ module Raven
84
86
  attr_writer :file, :number, :method, :module_name
85
87
  end
86
88
 
87
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/
89
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
88
90
 
89
91
  # holder for an Array of Backtrace::Line instances
90
92
  attr_reader :lines
@@ -85,12 +85,13 @@ module Raven
85
85
 
86
86
  def load_integration(integration)
87
87
  require "raven/integrations/#{integration}"
88
- rescue Exception => error
89
- logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
88
+ rescue Exception => e
89
+ logger.warn "Unable to load raven/integrations/#{integration}: #{e}"
90
90
  end
91
91
 
92
92
  def safely_prepend(module_name, opts = {})
93
93
  return if opts[:to].nil? || opts[:from].nil?
94
+
94
95
  if opts[:to].respond_to?(:prepend, true)
95
96
  opts[:to].send(:prepend, opts[:from].const_get(module_name))
96
97
  else
@@ -101,6 +102,7 @@ module Raven
101
102
  def sys_command(command)
102
103
  result = `#{command} 2>&1` rescue nil
103
104
  return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
105
+
104
106
  result.strip
105
107
  end
106
108
  end
@@ -64,7 +64,7 @@ module Raven
64
64
  end
65
65
 
66
66
  def empty?
67
- !members.any?
67
+ members.none?
68
68
  end
69
69
 
70
70
  def to_hash
@@ -1,19 +1,19 @@
1
1
  module Raven
2
2
  module ActiveSupportBreadcrumbs
3
3
  class << self
4
- def add(name, started, _finished, _unique_id, data)
5
- Raven.breadcrumbs.record do |crumb|
6
- crumb.data = data
7
- crumb.category = name
8
- crumb.timestamp = started.to_i
9
- end
4
+ def add(name, started, _finished, _unique_id, data)
5
+ Raven.breadcrumbs.record do |crumb|
6
+ crumb.data = data
7
+ crumb.category = name
8
+ crumb.timestamp = started.to_i
10
9
  end
10
+ end
11
11
 
12
- def inject
13
- ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
14
- add(name, started, finished, unique_id, data)
15
- end
12
+ def inject
13
+ ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
14
+ add(name, started, finished, unique_id, data)
16
15
  end
16
+ end
17
17
  end
18
18
  end
19
19
  end
@@ -4,13 +4,13 @@ module Raven
4
4
  module BreadcrumbLogger
5
5
  LEVELS = {
6
6
  ::Logger::DEBUG => 'debug',
7
- ::Logger::INFO => 'info',
8
- ::Logger::WARN => 'warn',
7
+ ::Logger::INFO => 'info',
8
+ ::Logger::WARN => 'warn',
9
9
  ::Logger::ERROR => 'error',
10
10
  ::Logger::FATAL => 'fatal'
11
11
  }.freeze
12
12
 
13
- EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/
13
+ EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/.freeze
14
14
 
15
15
  def self.parse_exception(message)
16
16
  lines = message.split(/\n\s*/)
@@ -29,8 +29,8 @@ module Raven
29
29
 
30
30
  begin
31
31
  1 / 0
32
- rescue ZeroDivisionError => exception
33
- evt = instance.capture_exception(exception)
32
+ rescue ZeroDivisionError => e
33
+ evt = instance.capture_exception(e)
34
34
  end
35
35
 
36
36
  if evt && !(evt.is_a? Thread)
@@ -1,14 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'base64'
3
4
  require 'json'
4
5
  require 'zlib'
5
6
 
7
+ require "raven/transports"
8
+
6
9
  module Raven
7
10
  # Encodes events and sends them to the Sentry server.
8
11
  class Client
9
- PROTOCOL_VERSION = '5'.freeze
10
- USER_AGENT = "raven-ruby/#{Raven::VERSION}".freeze
11
- CONTENT_TYPE = 'application/json'.freeze
12
+ PROTOCOL_VERSION = '5'
13
+ USER_AGENT = "raven-ruby/#{Raven::VERSION}"
14
+ CONTENT_TYPE = 'application/json'
12
15
 
13
16
  attr_accessor :configuration
14
17
 
@@ -120,7 +123,9 @@ module Raven
120
123
  configuration.logger.warn "Not sending event due to previous failure(s)."
121
124
  end
122
125
  configuration.logger.warn("Failed to submit event: #{get_log_message(event)}")
123
- configuration.transport_failure_callback.call(event) if configuration.transport_failure_callback
126
+
127
+ # configuration.transport_failure_callback can be false & nil
128
+ configuration.transport_failure_callback.call(event) if configuration.transport_failure_callback # rubocop:disable Style/SafeNavigation
124
129
  end
125
130
  end
126
131
 
@@ -236,6 +236,7 @@ module Raven
236
236
 
237
237
  def server=(value)
238
238
  return if value.nil?
239
+
239
240
  uri = URI.parse(value)
240
241
  uri_path = uri.path.split('/')
241
242
 
@@ -253,13 +254,14 @@ module Raven
253
254
 
254
255
  # For anyone who wants to read the base server string
255
256
  @server = "#{scheme}://#{host}"
256
- @server << ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
257
- @server << path
257
+ @server += ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
258
+ @server += path
258
259
  end
259
260
  alias dsn= server=
260
261
 
261
262
  def encoding=(encoding)
262
263
  raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
264
+
263
265
  @encoding = encoding
264
266
  end
265
267
 
@@ -267,6 +269,7 @@ module Raven
267
269
  unless value == false || value.respond_to?(:call)
268
270
  raise(ArgumentError, "async must be callable (or false to disable)")
269
271
  end
272
+
270
273
  @async = value
271
274
  end
272
275
 
@@ -274,6 +277,7 @@ module Raven
274
277
  unless value == false || value.respond_to?(:call)
275
278
  raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
276
279
  end
280
+
277
281
  @transport_failure_callback = value
278
282
  end
279
283
 
@@ -281,6 +285,7 @@ module Raven
281
285
  unless value == false || value.respond_to?(:call)
282
286
  raise ArgumentError, "should_capture must be callable (or false to disable)"
283
287
  end
288
+
284
289
  @should_capture = value
285
290
  end
286
291
 
@@ -288,6 +293,7 @@ module Raven
288
293
  unless value == false || value.respond_to?(:call)
289
294
  raise ArgumentError, "before_send must be callable (or false to disable)"
290
295
  end
296
+
291
297
  @before_send = value
292
298
  end
293
299
 
@@ -351,8 +357,8 @@ module Raven
351
357
  detect_release_from_git ||
352
358
  detect_release_from_capistrano ||
353
359
  detect_release_from_heroku
354
- rescue => ex
355
- logger.error "Error detecting release: #{ex.message}"
360
+ rescue => e
361
+ logger.error "Error detecting release: #{e.message}"
356
362
  end
357
363
 
358
364
  def excluded_exception?(incoming_exception)
@@ -418,18 +424,21 @@ module Raven
418
424
 
419
425
  def capture_in_current_environment?
420
426
  return true unless environments.any? && !environments.include?(current_environment)
427
+
421
428
  @errors << "Not configured to send/capture in environment '#{current_environment}'"
422
429
  false
423
430
  end
424
431
 
425
432
  def capture_allowed_by_callback?(message_or_exc)
426
- return true if !should_capture || message_or_exc.nil? || should_capture.call(*[message_or_exc])
433
+ return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
434
+
427
435
  @errors << "should_capture returned false"
428
436
  false
429
437
  end
430
438
 
431
439
  def valid?
432
440
  return true if %w(server host path public_key project_id).all? { |k| public_send(k) }
441
+
433
442
  if server
434
443
  %w(server host path public_key project_id).map do |key|
435
444
  @errors << "No #{key} specified" unless public_send(key)
@@ -442,6 +451,7 @@ module Raven
442
451
 
443
452
  def sample_allowed?
444
453
  return true if sample_rate == 1.0
454
+
445
455
  if Random::DEFAULT.rand >= sample_rate
446
456
  @errors << "Excluded by random sample"
447
457
  false
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'socket'
3
4
  require 'securerandom'
4
5
 
@@ -76,7 +77,7 @@ module Raven
76
77
  end
77
78
 
78
79
  def message
79
- @interfaces[:logentry] && @interfaces[:logentry].unformatted_message
80
+ @interfaces[:logentry]&.unformatted_message
80
81
  end
81
82
 
82
83
  def message=(args)
@@ -96,12 +97,13 @@ module Raven
96
97
  end
97
98
 
98
99
  def level=(new_level) # needed to meet the Sentry spec
99
- @level = new_level == "warn" || new_level == :warn ? :warning : new_level
100
+ @level = new_level.to_s == "warn" ? :warning : new_level
100
101
  end
101
102
 
102
103
  def interface(name, value = nil, &block)
103
104
  int = Interface.registered[name]
104
105
  raise(Error, "Unknown interface: #{name}") unless int
106
+
105
107
  @interfaces[int.sentry_alias] = int.new(value, &block) if value || block
106
108
  @interfaces[int.sentry_alias]
107
109
  end
@@ -51,6 +51,7 @@ module Raven
51
51
  # Tell the log that the client is good to go
52
52
  def report_status
53
53
  return if configuration.silence_ready
54
+
54
55
  if configuration.capture_allowed?
55
56
  logger.info "Raven #{VERSION} ready to catch errors"
56
57
  else
@@ -111,15 +112,15 @@ module Raven
111
112
  message_or_exc = obj.is_a?(String) ? "message" : "exception"
112
113
  options[:configuration] = configuration
113
114
  options[:context] = context
114
- if (evt = Event.send("from_" + message_or_exc, obj, options))
115
+ if evt = Event.send("from_" + message_or_exc, obj, options)
115
116
  yield evt if block_given?
116
117
  if configuration.async?
117
118
  begin
118
119
  # We have to convert to a JSON-like hash, because background job
119
120
  # processors (esp ActiveJob) may not like weird types in the event hash
120
121
  configuration.async.call(evt.to_json_compatible)
121
- rescue => ex
122
- logger.error("async event sending failed: #{ex.message}")
122
+ rescue => e
123
+ logger.error("async event sending failed: #{e.message}")
123
124
  send_event(evt, make_hint(obj))
124
125
  end
125
126
  else
@@ -8,19 +8,18 @@ module Delayed
8
8
  begin
9
9
  # Forward the call to the next callback in the callback chain
10
10
  block.call(job, *args)
11
-
12
- rescue Exception => exception
11
+ rescue Exception => e
13
12
  # Log error to Sentry
14
13
  extra = {
15
14
  :delayed_job => {
16
- :id => job.id.to_s,
17
- :priority => job.priority,
18
- :attempts => job.attempts,
19
- :run_at => job.run_at,
20
- :locked_at => job.locked_at,
21
- :locked_by => job.locked_by,
22
- :queue => job.queue,
23
- :created_at => job.created_at
15
+ :id => job.id.to_s,
16
+ :priority => job.priority,
17
+ :attempts => job.attempts,
18
+ :run_at => job.run_at,
19
+ :locked_at => job.locked_at,
20
+ :locked_by => job.locked_by,
21
+ :queue => job.queue,
22
+ :created_at => job.created_at
24
23
  }
25
24
  }
26
25
  # last_error can be nil
@@ -32,16 +31,16 @@ module Delayed
32
31
  if job.respond_to?('payload_object') && job.payload_object.respond_to?('job_data')
33
32
  extra[:active_job] = job.payload_object.job_data
34
33
  end
35
- ::Raven.capture_exception(exception,
36
- :logger => 'delayed_job',
37
- :tags => {
34
+ ::Raven.capture_exception(e,
35
+ :logger => 'delayed_job',
36
+ :tags => {
38
37
  :delayed_job_queue => job.queue,
39
38
  :delayed_job_id => job.id.to_s
40
39
  },
41
40
  :extra => extra)
42
41
 
43
42
  # Make sure we propagate the failure!
44
- raise exception
43
+ raise e
45
44
  ensure
46
45
  ::Raven::Context.clear!
47
46
  ::Raven::BreadcrumbBuffer.clear!
@@ -14,6 +14,5 @@ module RackTimeoutExtensions
14
14
  end
15
15
  end
16
16
 
17
- # Include is private in Ruby 1.9
18
- Rack::Timeout::Error.__send__(:include, RackTimeoutExtensions)
19
- Rack::Timeout::RequestTimeoutException.__send__(:include, RackTimeoutExtensions)
17
+ Rack::Timeout::Error.include(RackTimeoutExtensions)
18
+ Rack::Timeout::RequestTimeoutException.include(RackTimeoutExtensions)
@@ -92,8 +92,8 @@ module Raven
92
92
  request.body.rewind
93
93
  data
94
94
  end
95
- rescue IOError => ex
96
- ex.message
95
+ rescue IOError => e
96
+ e.message
97
97
  end
98
98
 
99
99
  def format_headers_for_sentry(env_hash)
@@ -112,6 +112,7 @@ module Raven
112
112
  next if key == 'HTTP_COOKIE' # Cookies don't go here, they go somewhere else
113
113
 
114
114
  next unless key.start_with?('HTTP_') || %w(CONTENT_TYPE CONTENT_LENGTH).include?(key)
115
+
115
116
  # Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
116
117
  key = key.sub(/^HTTP_/, "")
117
118
  key = key.split('_').map(&:capitalize).join('-')
@@ -5,6 +5,7 @@ module Raven
5
5
  require 'raven/integrations/rails/overrides/streaming_reporter'
6
6
  require 'raven/integrations/rails/controller_methods'
7
7
  require 'raven/integrations/rails/controller_transaction'
8
+ require 'raven/integrations/rack'
8
9
 
9
10
  initializer "raven.use_rack_middleware" do |app|
10
11
  app.config.middleware.insert 0, Raven::Rack
@@ -20,10 +20,11 @@ module Raven
20
20
 
21
21
  def capture_and_reraise_with_sentry(job, block)
22
22
  block.call
23
- rescue Exception => exception # rubocop:disable Lint/RescueException
24
- return if rescue_with_handler(exception)
25
- Raven.capture_exception(exception, :extra => raven_context(job))
26
- raise exception
23
+ rescue Exception => e # rubocop:disable Lint/RescueException
24
+ return if rescue_with_handler(e)
25
+
26
+ Raven.capture_exception(e, :extra => raven_context(job))
27
+ raise e
27
28
  ensure
28
29
  Context.clear!
29
30
  BreadcrumbBuffer.clear!
@@ -6,7 +6,7 @@ module Raven
6
6
  begin
7
7
  env = env_or_request.respond_to?(:env) ? env_or_request.env : env_or_request
8
8
  Raven::Rack.capture_exception(exception, env)
9
- rescue # rubocop:disable Lint/HandleExceptions
9
+ rescue
10
10
  end
11
11
  super
12
12
  end
@@ -21,7 +21,7 @@ module Raven
21
21
  begin
22
22
  env = env_or_request.respond_to?(:env) ? env_or_request.env : env_or_request
23
23
  Raven::Rack.capture_exception(exception, env)
24
- rescue # rubocop:disable Lint/HandleExceptions
24
+ rescue
25
25
  end
26
26
  render_exception_without_raven(env_or_request, exception)
27
27
  end
@@ -1,9 +1,9 @@
1
1
  module Raven
2
2
  class Interface
3
3
  def initialize(attributes = nil)
4
- attributes.each do |attr, value|
4
+ attributes&.each do |attr, value|
5
5
  public_send "#{attr}=", value
6
- end if attributes
6
+ end
7
7
 
8
8
  yield self if block_given?
9
9
  end
@@ -58,7 +58,7 @@ module Raven
58
58
  end
59
59
 
60
60
  def project_root
61
- @project_root ||= Raven.configuration.project_root && Raven.configuration.project_root.to_s
61
+ @project_root ||= Raven.configuration.project_root&.to_s
62
62
  end
63
63
 
64
64
  def longest_load_path
@@ -10,6 +10,7 @@ module Raven
10
10
  # line should be the line requested by lineno. See specs for more information.
11
11
  def get_file_context(filename, lineno, context)
12
12
  return nil, nil, nil unless valid_path?(filename)
13
+
13
14
  lines = Array.new(2 * context + 1) do |i|
14
15
  getline(filename, lineno - context + i)
15
16
  end
@@ -26,15 +27,17 @@ module Raven
26
27
  def getlines(path)
27
28
  @cache[path] ||= begin
28
29
  IO.readlines(path)
29
- rescue
30
- nil
30
+ rescue
31
+ nil
31
32
  end
32
33
  end
33
34
 
34
35
  def getline(path, n)
35
36
  return nil if n < 1
37
+
36
38
  lines = getlines(path)
37
39
  return nil if lines.nil?
40
+
38
41
  lines[n - 1]
39
42
  end
40
43
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'logger'
3
4
 
4
5
  module Raven
5
6
  class Logger < ::Logger
6
- LOG_PREFIX = "** [Raven] ".freeze
7
- PROGNAME = "sentry".freeze
7
+ LOG_PREFIX = "** [Raven] "
8
+ PROGNAME = "sentry"
8
9
 
9
10
  def initialize(*)
10
11
  super
@@ -10,17 +10,27 @@ module Raven
10
10
  private
11
11
 
12
12
  def process_if_symbol_keys(data)
13
- data[:request][:cookies] = STRING_MASK if data[:request][:cookies]
13
+ if cookies = data.dig(:request, :cookies)
14
+ data[:request][:cookies] = generate_masked_cookies(cookies)
15
+ end
14
16
 
15
- return unless data[:request][:headers] && data[:request][:headers]["Cookie"]
16
- data[:request][:headers]["Cookie"] = STRING_MASK
17
+ if cookies_header = data[:request][:headers]["Cookie"]
18
+ data[:request][:headers]["Cookie"] = generate_masked_cookies(cookies_header)
19
+ end
17
20
  end
18
21
 
19
22
  def process_if_string_keys(data)
20
- data["request"]["cookies"] = STRING_MASK if data["request"]["cookies"]
23
+ if cookies = data.dig("request", "cookies")
24
+ data["request"]["cookies"] = generate_masked_cookies(cookies)
25
+ end
21
26
 
22
- return unless data["request"]["headers"] && data["request"]["headers"]["Cookie"]
23
- data["request"]["headers"]["Cookie"] = STRING_MASK
27
+ if cookies_header = data.dig("request", "headers", "Cookie")
28
+ data["request"]["headers"]["Cookie"] = generate_masked_cookies(cookies_header)
29
+ end
30
+ end
31
+
32
+ def generate_masked_cookies(cookies)
33
+ cookies.merge(cookies) { STRING_MASK }
24
34
  end
25
35
  end
26
36
  end
@@ -11,11 +11,13 @@ module Raven
11
11
 
12
12
  def process_if_symbol_keys(data)
13
13
  return unless data[:request][:method] == "POST"
14
+
14
15
  data[:request][:data] = STRING_MASK
15
16
  end
16
17
 
17
18
  def process_if_string_keys(data)
18
19
  return unless data["request"]["method"] == "POST"
20
+
19
21
  data["request"]["data"] = STRING_MASK
20
22
  end
21
23
  end
@@ -2,6 +2,7 @@ module Raven
2
2
  class Processor::RemoveCircularReferences < Processor
3
3
  def process(value, visited = [])
4
4
  return "(...)" if visited.include?(value.__id__)
5
+
5
6
  visited << value.__id__ if value.is_a?(Array) || value.is_a?(Hash)
6
7
 
7
8
  case value
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'json'
3
4
 
4
5
  module Raven
5
6
  class Processor::SanitizeData < Processor
6
7
  DEFAULT_FIELDS = %w(authorization password passwd secret ssn social(.*)?sec).freeze
7
- CREDIT_CARD_RE = /\b(?:3[47]\d|(?:4\d|5[1-5]|65)\d{2}|6011)\d{12}\b/
8
+ CREDIT_CARD_RE = /\b(?:3[47]\d|(?:4\d|5[1-5]|65)\d{2}|6011)\d{12}\b/.freeze
8
9
  QUERY_STRING = ['query_string', :query_string].freeze
9
10
  JSON_STARTS_WITH = ["[", "{"].freeze
10
11
 
@@ -20,22 +21,13 @@ module Raven
20
21
  def process(value, key = nil)
21
22
  case value
22
23
  when Hash
23
- !value.frozen? ? value.merge!(value) { |k, v| process v, k } : value.merge(value) { |k, v| process v, k }
24
+ sanitize_hash_value(key, value)
24
25
  when Array
25
- !value.frozen? ? value.map! { |v| process v, key } : value.map { |v| process v, key }
26
+ sanitize_array_value(key, value)
26
27
  when Integer
27
28
  matches_regexes?(key, value.to_s) ? INT_MASK : value
28
29
  when String
29
- if value =~ fields_re && (json = parse_json_or_nil(value))
30
- # if this string is actually a json obj, convert and sanitize
31
- process(json).to_json
32
- elsif matches_regexes?(key, value)
33
- STRING_MASK
34
- elsif QUERY_STRING.include?(key)
35
- sanitize_query_string(value)
36
- else
37
- value
38
- end
30
+ sanitize_string_value(key, value)
39
31
  else
40
32
  value
41
33
  end
@@ -49,6 +41,39 @@ module Raven
49
41
  @utf8_processor ||= Processor::UTF8Conversion.new
50
42
  end
51
43
 
44
+ def sanitize_hash_value(key, value)
45
+ if key =~ sensitive_fields
46
+ STRING_MASK
47
+ elsif value.frozen?
48
+ value.merge(value) { |k, v| process v, k }
49
+ else
50
+ value.merge!(value) { |k, v| process v, k }
51
+ end
52
+ end
53
+
54
+ def sanitize_array_value(key, value)
55
+ if value.frozen?
56
+ value.map { |v| process v, key }
57
+ else
58
+ value.map! { |v| process v, key }
59
+ end
60
+ end
61
+
62
+ def sanitize_string_value(key, value)
63
+ if value =~ sensitive_fields && (json = parse_json_or_nil(value))
64
+ # if this string is actually a json obj, convert and sanitize
65
+ process(json).to_json
66
+ elsif matches_regexes?(key, value)
67
+ STRING_MASK
68
+ elsif QUERY_STRING.include?(key)
69
+ sanitize_query_string(value)
70
+ elsif value =~ sensitive_fields
71
+ sanitize_sensitive_string_content(value)
72
+ else
73
+ value
74
+ end
75
+ end
76
+
52
77
  def sanitize_query_string(query_string)
53
78
  query_hash = CGI.parse(query_string)
54
79
  sanitized = utf8_processor.process(query_hash)
@@ -56,16 +81,38 @@ module Raven
56
81
  URI.encode_www_form(processed_query_hash)
57
82
  end
58
83
 
84
+ # this scrubs some sensitive info from the string content. for example:
85
+ #
86
+ # ```
87
+ # unexpected token at '{
88
+ # "role": "admin","password": "Abc@123","foo": "bar"
89
+ # }'
90
+ # ```
91
+ #
92
+ # will become
93
+ #
94
+ # ```
95
+ # unexpected token at '{
96
+ # "role": "admin","password": *******,"foo": "bar"
97
+ # }'
98
+ # ```
99
+ #
100
+ # it's particularly useful in hash or param-parsing related errors
101
+ def sanitize_sensitive_string_content(value)
102
+ value.gsub(/(#{sensitive_fields}['":]\s?(:|=>)?\s?)(".*?"|'.*?')/, '\1' + STRING_MASK)
103
+ end
104
+
59
105
  def matches_regexes?(k, v)
60
106
  (sanitize_credit_cards && v =~ CREDIT_CARD_RE) ||
61
- k =~ fields_re
107
+ k =~ sensitive_fields
62
108
  end
63
109
 
64
- def fields_re
65
- return @fields_re if instance_variable_defined?(:@fields_re)
110
+ def sensitive_fields
111
+ return @sensitive_fields if instance_variable_defined?(:@sensitive_fields)
112
+
66
113
  fields = DEFAULT_FIELDS | sanitize_fields
67
114
  fields -= sanitize_fields_excluded
68
- @fields_re = /#{fields.map do |f|
115
+ @sensitive_fields = /#{fields.map do |f|
69
116
  use_boundary?(f) ? "\\b#{f}\\b" : f
70
117
  end.join("|")}/i
71
118
  end
@@ -80,6 +127,7 @@ module Raven
80
127
 
81
128
  def parse_json_or_nil(string)
82
129
  return unless string.start_with?(*JSON_STARTS_WITH)
130
+
83
131
  JSON.parse(string)
84
132
  rescue JSON::ParserError, NoMethodError
85
133
  nil
@@ -14,6 +14,7 @@ module Raven
14
14
  !value.frozen? ? value.map! { |v| process v } : value.map { |v| process v }
15
15
  when Exception
16
16
  return value if value.message.valid_encoding?
17
+
17
18
  clean_exc = value.class.new(remove_invalid_bytes(value.message))
18
19
  clean_exc.set_backtrace(value.backtrace)
19
20
  clean_exc
@@ -27,6 +28,7 @@ module Raven
27
28
  value.force_encoding(Encoding::UTF_8)
28
29
  end
29
30
  return value if value.valid_encoding?
31
+
30
32
  remove_invalid_bytes(value)
31
33
  else
32
34
  value
@@ -13,3 +13,7 @@ module Raven
13
13
  end
14
14
  end
15
15
  end
16
+
17
+ require "raven/transports/dummy"
18
+ require "raven/transports/http"
19
+ require "raven/transports/stdout"
@@ -26,10 +26,10 @@ module Raven
26
26
  req.headers['X-Sentry-Auth'] = auth_header
27
27
  req.body = data
28
28
  end
29
- rescue Faraday::Error => ex
30
- error_info = ex.message
31
- if ex.response && ex.response[:headers]['x-sentry-error']
32
- error_info += " Error in headers is: #{ex.response[:headers]['x-sentry-error']}"
29
+ rescue Faraday::Error => e
30
+ error_info = e.message
31
+ if e.response && e.response[:headers]['x-sentry-error']
32
+ error_info += " Error in headers is: #{e.response[:headers]['x-sentry-error']}"
33
33
  end
34
34
  raise Raven::Error, error_info
35
35
  end
@@ -42,7 +42,7 @@ module Raven
42
42
  proxy = configuration.public_send(:proxy)
43
43
 
44
44
  Faraday.new(configuration.server, :ssl => ssl_configuration, :proxy => proxy) do |builder|
45
- configuration.faraday_builder.call(builder) if configuration.faraday_builder
45
+ configuration.faraday_builder&.call(builder)
46
46
  builder.response :raise_error
47
47
  builder.options.merge! faraday_opts
48
48
  builder.headers[:user_agent] = "sentry-ruby/#{Raven::VERSION}"
@@ -7,6 +7,7 @@ module Raven
7
7
  while exception.cause
8
8
  exception = exception.cause
9
9
  break if exceptions.any? { |e| e.object_id == exception.object_id }
10
+
10
11
  exceptions << exception
11
12
  end
12
13
  exceptions
@@ -13,7 +13,7 @@ module Raven
13
13
  "fc00::/7", # private IPv6 range fc00::/7
14
14
  "10.0.0.0/8", # private IPv4 range 10.x.x.x
15
15
  "172.16.0.0/12", # private IPv4 range 172.16.0.0 .. 172.31.255.255
16
- "192.168.0.0/16", # private IPv4 range 192.168.x.x
16
+ "192.168.0.0/16" # private IPv4 range 192.168.x.x
17
17
  ].map { |proxy| IPAddr.new(proxy) }
18
18
 
19
19
  attr_accessor :ip, :ip_addresses
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Raven
3
- # Freezing this constant breaks in 1.9.x
4
- VERSION = "3.0.0" # rubocop:disable Style/MutableConstant
4
+ VERSION = "3.0.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-raven
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-02 00:00:00.000000000 Z
11
+ date: 2020-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -33,11 +33,13 @@ extra_rdoc_files:
33
33
  - README.md
34
34
  - LICENSE
35
35
  files:
36
+ - ".craft.yml"
37
+ - ".github/workflows/test.yml"
36
38
  - ".gitignore"
37
39
  - ".gitmodules"
38
40
  - ".rspec"
39
41
  - ".rubocop.yml"
40
- - ".travis.yml"
42
+ - ".scripts/bump-version.sh"
41
43
  - Gemfile
42
44
  - LICENSE
43
45
  - README.md
@@ -1,43 +0,0 @@
1
- language: ruby
2
- dist: trusty
3
- group: beta
4
- cache: bundler
5
-
6
- services:
7
- - redis-server
8
-
9
- branches:
10
- only: [master]
11
-
12
- rvm:
13
- - 2.3.8
14
- - 2.4.9
15
- - 2.5.7
16
- - 2.6.5
17
- - 2.7.0
18
-
19
- env:
20
- - RAILS_VERSION=4
21
- - RAILS_VERSION=5
22
- - RAILS_VERSION=0
23
-
24
- addons:
25
- apt:
26
- packages:
27
- - haveged
28
-
29
- before_install:
30
- - service haveged start
31
- # Pin bundler version due to https://github.com/rubygems/rubygems/issues/2055
32
- - gem install bundler -v 1.16.0
33
-
34
- matrix:
35
- include:
36
- - rvm: jruby-9.2.9.0
37
- env: JRUBY_OPTS="--dev -J-Djruby.launch.inproc=true -J-Xmx1024M" RAILS_VERSION=4
38
- - rvm: jruby-9.2.9.0
39
- env: JRUBY_OPTS="--dev -J-Djruby.launch.inproc=true -J-Xmx1024M" RAILS_VERSION=5
40
- - rvm: ruby-head
41
- env: RAILS_VERSION=0
42
- allow_failures:
43
- - rvm: ruby-head