diff --git a/.github/workflows/maze-runner.yml b/.github/workflows/maze-runner.yml index 2adfe2ae4..e2e27582a 100644 --- a/.github/workflows/maze-runner.yml +++ b/.github/workflows/maze-runner.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['1.9', '3.2'] + ruby-version: ['1.9', '3.3'] uses: ./.github/workflows/run-maze-runner.yml with: @@ -36,11 +36,11 @@ jobs: rack-version: '1' - ruby-version: '2.2' rack-version: '2' - - ruby-version: '3.2' + - ruby-version: '3.3' rack-version: '2' - ruby-version: '2.4' rack-version: '3' - - ruby-version: '3.2' + - ruby-version: '3.3' rack-version: '3' uses: ./.github/workflows/run-maze-runner.yml @@ -56,7 +56,7 @@ jobs: include: - ruby-version: '2.0' que-version: '0.14' - - ruby-version: '3.2' + - ruby-version: '2.5' que-version: '0.14' - ruby-version: '2.5' que-version: '1' @@ -76,7 +76,7 @@ jobs: ruby-version: ['2.5', '2.7'] sidekiq-version: ['2', '3', '4', '5', '6', '7'] include: - - ruby-version: '3.2' + - ruby-version: '3.3' sidekiq-version: '7' exclude: # 2.7 is the minimum ruby version that sidekiq 7 supports @@ -127,7 +127,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.7', '3.2'] + ruby-version: ['2.7', '3.3'] rails-version: ['6', '7', '_integrations'] include: - ruby-version: '2.5' @@ -135,7 +135,7 @@ jobs: exclude: - ruby-version: '2.7' rails-version: '6' - - ruby-version: '3.2' + - ruby-version: '3.3' rails-version: '_integrations' uses: ./.github/workflows/run-maze-runner.yml @@ -148,7 +148,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2'] + ruby-version: ['1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3'] uses: ./.github/workflows/run-maze-runner.yml with: diff --git a/.github/workflows/run-maze-runner.yml b/.github/workflows/run-maze-runner.yml index 9a64c5030..bb8f74269 100644 --- a/.github/workflows/run-maze-runner.yml +++ b/.github/workflows/run-maze-runner.yml @@ -42,6 +42,7 @@ jobs: with: ruby-version: 2.7 bundler-cache: true + cache-version: ${{ inputs.ruby-version }}-${{ inputs.rack-version }}-${{ inputs.que-version }}-${{ inputs.rails-version }}-${{ inputs.sidekiq-version }} - run: bundle exec maze-runner ${{ inputs.features }} --no-source env: diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index aa9efbc58..9783e1475 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2'] + ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3'] optional-groups: ['test sidekiq'] include: - ruby-version: '1.9' diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe723de5..4932a8c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ Changelog ========= +## v6.26.1 (9 January 2024) + +### Fixes + +* Fix deprecation warning from Sidekiq error handler + | [#796](https://github.com/bugsnag/bugsnag-ruby/pull/796) + | [fukayatsu](https://github.com/fukayatsu) +* Fix Resque integration when failure backend is already `Resque::Failure::Multiple` + | [#803](https://github.com/bugsnag/bugsnag-ruby/pull/803) + | [sj26](https://github.com/sj26) +* Redact URLs in automatic Rails breadcrumbs + | [#806](https://github.com/bugsnag/bugsnag-ruby/pull/806) + ## v6.26.0 (19 July 2023) ### Enhancements diff --git a/VERSION b/VERSION index 4c6a35fb6..0e10c8e2c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.26.0 +6.26.1 diff --git a/bugsnag.gemspec b/bugsnag.gemspec index 22ae2e110..12d6b08af 100644 --- a/bugsnag.gemspec +++ b/bugsnag.gemspec @@ -30,7 +30,7 @@ Gem::Specification.new do |s| if s.respond_to?(:metadata=) s.metadata = { - "changelog_uri" => "https://github.com/bugsnag/bugsnag-ruby/blob/HEAD/CHANGELOG.md", + "changelog_uri" => "https://github.com/bugsnag/bugsnag-ruby/blob/v#{File.read("VERSION").strip}/CHANGELOG.md", "documentation_uri" => "https://docs.bugsnag.com/platforms/ruby/", "source_code_uri" => "https://github.com/bugsnag/bugsnag-ruby/", "rubygems_mfa_required" => "true" diff --git a/features/fixtures/expected_breadcrumbs/request.json b/features/fixtures/expected_breadcrumbs/request.json index 0e058748b..89dbe3bdf 100644 --- a/features/fixtures/expected_breadcrumbs/request.json +++ b/features/fixtures/expected_breadcrumbs/request.json @@ -6,8 +6,8 @@ "controller": "BreadcrumbsController", "action": "handled", "method": "GET", - "path": "/breadcrumbs/handled", + "path": "/breadcrumbs/handled?password=[FILTERED]&abc=xyz", "event_name": "start_processing.action_controller", "event_id": ".*" } -} \ No newline at end of file +} diff --git a/features/fixtures/mailman/app/Gemfile b/features/fixtures/mailman/app/Gemfile index 72ffd7f6b..71514855f 100644 --- a/features/fixtures/mailman/app/Gemfile +++ b/features/fixtures/mailman/app/Gemfile @@ -12,3 +12,6 @@ gem 'rack', '~> 1.6.11' # Install a compatible FFI version on Ruby <2.3 gem 'ffi', '< 1.13.0' if RUBY_VERSION < '2.3.0' + +# Install a compatible mini_mime version on Ruby <2.6 +gem 'mini_mime', '< 1.1.4' if RUBY_VERSION < '2.6.0' diff --git a/features/fixtures/plain/app/app.rb b/features/fixtures/plain/app/app.rb index 2af88b891..829c5d61f 100644 --- a/features/fixtures/plain/app/app.rb +++ b/features/fixtures/plain/app/app.rb @@ -5,6 +5,7 @@ def configure_basics Bugsnag.configure do |conf| conf.api_key = ENV['BUGSNAG_API_KEY'] conf.set_endpoints(ENV['BUGSNAG_ENDPOINT'], ENV["BUGSNAG_ENDPOINT"]) + conf.project_root = File.dirname(File.realpath(__FILE__)) end end @@ -17,7 +18,7 @@ def configure_using_environment conf.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS" conf.meta_data_filters << ENV["BUGSNAG_META_DATA_FILTERS"] if ENV.include? "BUGSNAG_META_DATA_FILTERS" conf.enabled_release_stages = [ENV["BUGSNAG_NOTIFY_RELEASE_STAGE"]] if ENV.include? "BUGSNAG_NOTIFY_RELEASE_STAGE" - conf.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT" + conf.project_root = File.dirname(File.realpath(__FILE__)) conf.proxy_host = ENV["BUGSNAG_PROXY_HOST"] if ENV.include? "BUGSNAG_PROXY_HOST" conf.proxy_password = ENV["BUGSNAG_PROXY_PASSWORD"] if ENV.include? "BUGSNAG_PROXY_PASSWORD" conf.proxy_port = ENV["BUGSNAG_PROXY_PORT"] if ENV.include? "BUGSNAG_PROXY_PORT" diff --git a/features/fixtures/plain/app/stack_frame_modification/mark_frames_in_project.rb b/features/fixtures/plain/app/stack_frame_modification/mark_frames_in_project.rb index 2b966081e..9ac1844e6 100644 --- a/features/fixtures/plain/app/stack_frame_modification/mark_frames_in_project.rb +++ b/features/fixtures/plain/app/stack_frame_modification/mark_frames_in_project.rb @@ -4,10 +4,12 @@ callback = Proc.new do |report| report.exceptions[0][:stacktrace].each_with_index do |frame, index| - if index > 0 + if index == 0 + frame[:inProject] = nil + else frame[:inProject] = true end end end -run(callback) \ No newline at end of file +run(callback) diff --git a/features/fixtures/que/app/Gemfile b/features/fixtures/que/app/Gemfile index 9257d5504..930f39587 100644 --- a/features/fixtures/que/app/Gemfile +++ b/features/fixtures/que/app/Gemfile @@ -6,7 +6,6 @@ que_version = ENV.fetch("QUE_VERSION") gem "que", "~> #{que_version}" gem "pg", RUBY_VERSION < "2.2.0" ? "0.21.0" : "> 0.21.0" -gem "activerecord", RUBY_VERSION < "2.2.0" ? "4.2.11" : "> 4.2.11" # Install a compatible Minitest version on Ruby <2.3 gem 'minitest', '5.11.3' if RUBY_VERSION < '2.3.0' diff --git a/features/fixtures/que/app/app.rb b/features/fixtures/que/app/app.rb index 5ff701eeb..3f984f803 100644 --- a/features/fixtures/que/app/app.rb +++ b/features/fixtures/que/app/app.rb @@ -1,79 +1,3 @@ -require 'pg' -require 'que' -require 'socket' -require 'bugsnag' -require 'active_record' +require_relative "setup-que" -QUE_VERSION = ENV.fetch("QUE_VERSION") - -Bugsnag.configure do |config| - puts "Configuring `api_key` to #{ENV['BUGSNAG_API_KEY']}" - config.api_key = ENV['BUGSNAG_API_KEY'] - puts "Configuring `endpoint` to #{ENV['BUGSNAG_ENDPOINT']}" - config.endpoint = ENV['BUGSNAG_ENDPOINT'] -end - -postgres_ready = false -attempts = 0 -MAX_ATTEMPTS = 10 - -until postgres_ready || attempts >= MAX_ATTEMPTS - begin - Timeout::timeout(5) { TCPSocket.new('postgres', 5432).close } - - postgres_ready = true - rescue Exception - attempts += 1 - sleep 1 - end -end - -raise 'postgres was not ready in time!' unless postgres_ready - -ActiveRecord::Base.establish_connection( - adapter: 'postgresql', - database: 'postgres', - username: 'postgres', - password: 'test_password', - host: 'postgres' -) - -Que.connection = ActiveRecord Que.migrate!(version: Que::Migrations::CURRENT_VERSION) - -# Workaround a bug in que/pg -# see https://github.com/que-rb/que/issues/247 -if QUE_VERSION == '0.14' - Que::Adapters::Base::CAST_PROCS[1184] = lambda do |value| - case value - when Time then value - when String then Time.parse(value) - else raise "Unexpected time class: #{value.class} (#{value.inspect})" - end - end -end - -class UnhandledJob < Que::Job - def run - raise RuntimeError.new("Unhandled error") - end - - def handle_error(error) - destroy - end -end - -class HandledJob < Que::Job - def run - raise RuntimeError.new("Handled error") - rescue => exception - Bugsnag.notify(exception) - end -end - -case ARGV[0] -when "unhandled" - UnhandledJob.enqueue -when "handled" - HandledJob.enqueue -end diff --git a/features/fixtures/que/app/enqueue-job.rb b/features/fixtures/que/app/enqueue-job.rb new file mode 100644 index 000000000..45eff66be --- /dev/null +++ b/features/fixtures/que/app/enqueue-job.rb @@ -0,0 +1,22 @@ +require_relative "setup-que" + +query = <<-SQL +SELECT EXISTS ( + SELECT FROM pg_tables WHERE tablename = 'que_jobs' +) AS que_jobs_exists +SQL + +Timeout::timeout(10) do + loop do + break if $connection.exec(query)[0]["que_jobs_exists"] == "t" + + sleep 0.1 + end +end + +case ARGV[0] +when "unhandled" + UnhandledJob.enqueue +when "handled" + HandledJob.enqueue +end diff --git a/features/fixtures/que/app/setup-que.rb b/features/fixtures/que/app/setup-que.rb new file mode 100644 index 000000000..1fc5724bc --- /dev/null +++ b/features/fixtures/que/app/setup-que.rb @@ -0,0 +1,71 @@ +require 'pg' +require 'que' +require 'socket' +require 'bugsnag' + +QUE_VERSION = ENV.fetch("QUE_VERSION") + +Bugsnag.configure do |config| + puts "Configuring `api_key` to #{ENV['BUGSNAG_API_KEY']}" + config.api_key = ENV['BUGSNAG_API_KEY'] + puts "Configuring `endpoint` to #{ENV['BUGSNAG_ENDPOINT']}" + config.endpoint = ENV['BUGSNAG_ENDPOINT'] +end + +postgres_ready = false +attempts = 0 +MAX_ATTEMPTS = 10 + +until postgres_ready || attempts >= MAX_ATTEMPTS + begin + Timeout::timeout(5) { TCPSocket.new('postgres', 5432).close } + + postgres_ready = true + rescue Exception + attempts += 1 + sleep 1 + end +end + +raise 'postgres was not ready in time!' unless postgres_ready + +$connection = PG::Connection.open( + host: 'postgres', + user: 'postgres', + password: 'test_password', + dbname: 'postgres' +) + +if QUE_VERSION == '0.14' + Que.connection = $connection + + # Workaround a bug in que/pg + # see https://github.com/que-rb/que/issues/247 + Que::Adapters::Base::CAST_PROCS[1184] = lambda do |value| + case value + when Time then value + when String then Time.parse(value) + else raise "Unexpected time class: #{value.class} (#{value.inspect})" + end + end +else + Que.connection_proc = ->(&block) { block.call($connection) } +end + +class UnhandledJob < Que::Job + def run + raise RuntimeError.new("Unhandled error") + end + + def handle_error(error) + destroy + end +end + +class HandledJob < Que::Job + def run + raise RuntimeError.new("Handled error") + rescue => exception + Bugsnag.notify(exception) + end +end diff --git a/features/fixtures/rails3/app/Gemfile b/features/fixtures/rails3/app/Gemfile index e99e60c89..00267d7f3 100644 --- a/features/fixtures/rails3/app/Gemfile +++ b/features/fixtures/rails3/app/Gemfile @@ -18,3 +18,6 @@ gem "warden" # Install a compatible Loofah version on Ruby <2.5 gem 'loofah', '2.20.0' if RUBY_VERSION < '2.5' + +# Install a compatible Thor version on Ruby <2.6 +gem 'thor', '<1.3.0' if RUBY_VERSION < '2.6' diff --git a/features/fixtures/rails7/app/Gemfile b/features/fixtures/rails7/app/Gemfile index cee3e6fba..239f6f473 100644 --- a/features/fixtures/rails7/app/Gemfile +++ b/features/fixtures/rails7/app/Gemfile @@ -8,7 +8,8 @@ gem "rails", "~> 7.0.1" gem "sprockets-rails" # Use sqlite3 as the database for Active Record -gem "sqlite3", "~> 1.4" +# Install a compatible sqlite version on Ruby <3.0 +gem "sqlite3", RUBY_VERSION >= '3.0' ? "~> 1.7" : "< 1.7" # Use the Puma web server [https://github.com/puma/puma] gem "puma", "~> 5.0" diff --git a/features/fixtures/rails_integrations/app/config/application.rb b/features/fixtures/rails_integrations/app/config/application.rb index f28492e96..79984d894 100644 --- a/features/fixtures/rails_integrations/app/config/application.rb +++ b/features/fixtures/rails_integrations/app/config/application.rb @@ -1,3 +1,14 @@ +# reproduce #803 by setting Resque's backend to 'Multiple' before our Resque +# integration runs +# see https://github.com/bugsnag/bugsnag-ruby/pull/803 +require "resque" +require "resque/failure/redis" +require "resque/failure/multiple" + +Resque::Failure::Multiple.classes = [Resque::Failure::Redis] +Resque::Failure.backend = Resque::Failure::Multiple +# end #803 reproduction + require_relative 'boot' require "rails" diff --git a/features/plain_features/handled_errors.feature b/features/plain_features/handled_errors.feature index 3fdcc3f92..d7ad73240 100644 --- a/features/plain_features/handled_errors.feature +++ b/features/plain_features/handled_errors.feature @@ -9,7 +9,7 @@ Scenario: A rescued exception sends a report And the event "severityReason.type" equals "handledException" And the event "device.time" is a timestamp And the exception "errorClass" equals "RuntimeError" - And the "file" of stack frame 0 equals "/usr/src/app/handled/notify_exception.rb" + And the "file" of stack frame 0 equals "handled/notify_exception.rb" And the "lineNumber" of stack frame 0 equals 6 Scenario: A notified string sends a report @@ -21,7 +21,7 @@ Scenario: A notified string sends a report And the event "severityReason.type" equals "handledException" And the event "device.time" is a timestamp And the exception "errorClass" equals "RuntimeError" - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/notify_string.rb" + And the "file" of the top non-bugsnag stackframe equals "handled/notify_string.rb" And the "lineNumber" of the top non-bugsnag stackframe equals 8 Scenario: A handled error doesn't send a report when the :skip_bugsnag flag is set @@ -36,7 +36,7 @@ Scenario: A handled error can attach metadata in a block And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of stack frame 0 equals "/usr/src/app/handled/block_metadata.rb" + And the "file" of stack frame 0 equals "handled/block_metadata.rb" And the "lineNumber" of stack frame 0 equals 6 And the event "metaData.account.id" equals "1234abcd" And the event "metaData.account.name" equals "Acme Co" diff --git a/features/plain_features/release_stages.feature b/features/plain_features/release_stages.feature index d48fe340e..cdc8b23c8 100644 --- a/features/plain_features/release_stages.feature +++ b/features/plain_features/release_stages.feature @@ -16,4 +16,4 @@ Scenario: Does notify in the correct release stage And the event "severity" equals "error" And the event "severityReason.type" equals "unhandledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of stack frame 0 equals "/usr/src/app/configuration/send_unhandled.rb" + And the "file" of stack frame 0 equals "configuration/send_unhandled.rb" diff --git a/features/plain_features/report_stack_frames.feature b/features/plain_features/report_stack_frames.feature index 5569f0222..24b07c917 100644 --- a/features/plain_features/report_stack_frames.feature +++ b/features/plain_features/report_stack_frames.feature @@ -5,7 +5,7 @@ Scenario Outline: Stack frames can be removed When I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/remove_stack_frame.rb" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "file" of the top non-bugsnag stackframe equals "stack_frame_modification/initiators/.rb" And the "lineNumber" of stack frame 0 equals Examples: @@ -20,7 +20,7 @@ Scenario: Stack frames can be removed from a notified string When I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/remove_stack_frame.rb" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/handled_block.rb" + And the "file" of the top non-bugsnag stackframe equals "stack_frame_modification/initiators/handled_block.rb" And the "lineNumber" of the top non-bugsnag stackframe equals 19 Scenario Outline: Stack frames can be marked as in project @@ -28,7 +28,7 @@ Scenario Outline: Stack frames can be marked as in project When I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/mark_frames_in_project.rb" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier - And the "file" of stack frame 0 equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "file" of stack frame 0 equals "stack_frame_modification/initiators/.rb" And the event "exceptions.0.stacktrace.0.inProject" is null And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.inProject" is true @@ -46,7 +46,7 @@ Scenario: Stack frames can be marked as in project with a handled string And I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/mark_frames_in_project.rb" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/handled_block.rb" + And the "file" of the top non-bugsnag stackframe equals "stack_frame_modification/initiators/handled_block.rb" And the event "exceptions.0.stacktrace.0.inProject" is null And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.inProject" is true diff --git a/features/plain_features/unhandled_errors.feature b/features/plain_features/unhandled_errors.feature index f2f075da4..44b63000c 100644 --- a/features/plain_features/unhandled_errors.feature +++ b/features/plain_features/unhandled_errors.feature @@ -9,8 +9,8 @@ Scenario Outline: An unhandled error sends a report And the event "severityReason.type" equals "unhandledException" And the event "device.time" is a timestamp And the exception "errorClass" equals "" - And the "file" of stack frame 0 equals "/usr/src/app/unhandled/.rb" - And the "lineNumber" of stack frame 0 equals + And the "file" of the first in-project stack frame equals "unhandled/.rb" + And the "lineNumber" of the first in-project stack frame equals Examples: | file | error | lineNumber | command | diff --git a/features/que.feature b/features/que.feature index c143b8c60..efe0174aa 100644 --- a/features/que.feature +++ b/features/que.feature @@ -2,7 +2,7 @@ Feature: Errors are delivered to Bugsnag from Que Scenario: Que will deliver unhandled errors Given I start the service "que" - When I execute the command "bundle exec ruby app.rb unhandled" in the service "que" + When I execute the command "bundle exec ruby enqueue-job.rb unhandled" in the service "que" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier And the event "unhandled" is true @@ -15,7 +15,7 @@ Scenario: Que will deliver unhandled errors Scenario: Que will deliver handled errors Given I start the service "que" - When I execute the command "bundle exec ruby app.rb handled" in the service "que" + When I execute the command "bundle exec ruby enqueue-job.rb handled" in the service "que" And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier And the event "unhandled" is false diff --git a/features/rails_features/before_notify.feature b/features/rails_features/before_notify.feature index 99249b823..f337e6d9d 100644 --- a/features/rails_features/before_notify.feature +++ b/features/rails_features/before_notify.feature @@ -21,7 +21,7 @@ Scenario: Rails before_notify controller method works on unhandled errors And I wait to receive an error Then the error is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier" notifier And the exception "errorClass" equals "NameError" - And the exception "message" starts with "undefined local variable or method `generate_unhandled_error' for #