Skip to content

Instantly share code, notes, and snippets.

@st0012
Last active August 21, 2022 23:00
Show Gist options
  • Save st0012/e174c130dc5159038b4d94330b3fd6fd to your computer and use it in GitHub Desktop.
Save st0012/e174c130dc5159038b4d94330b3fd6fd to your computer and use it in GitHub Desktop.
Stan's debugging note for rails/rails#45263

Script

This is a bit different from the challenge's script because it's directly copied from the issue.

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "activesupport", "7.0.3"
end

require "active_support"
require "active_support/core_ext/object/blank"
require "minitest/autorun"

class BugTest < Minitest::Test
  def test_stuff
    old_secret = SecureRandom.base64(24)
    old_encryptor = ActiveSupport::MessageEncryptor.new old_secret

    current_secret = SecureRandom.base64(24)
    current_encryptor = ActiveSupport::MessageEncryptor.new current_secret
    current_encryptor.rotate old_secret

    # Old encryptor roundtrips a 'nil' value correctly
    assert_nil old_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))

    # New encryptor roundtrips a 'nil' value correctly
    assert_nil current_encryptor.decrypt_and_verify(current_encryptor.encrypt_and_sign(nil))

    # Old encryptor cannot decrypt data encrypted with the current secret
    assert_raises(ActiveSupport::MessageVerifier::InvalidSignature) do
      old_encryptor.decrypt_and_verify(current_encryptor.encrypt_and_sign("test"))
    end

    # New encryptor correctly decrypts data encrypted with the old secret (being rotated)
    assert_equal "test", current_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign("test"))

    # New encryptor should be able to decrypt a 'nil' value encrypted with the old secret --THIS FAILS--
    assert_nil current_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
  end
end

The Cause

Code

def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
  super
rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
  run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
end
  1. The initial decryption failed (the super call) and raised the MessageVerifier::InvalidSignature exception
  2. The exception was rescued, and it started to rotate the encryptors
  3. It rotated to an encryptor that has the old secret (added via #rotate). And it successfully decrypted the value as nil
  4. However, because this line uses || raise, when run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } returned nil, it'd still re-raise the exception

My debugging notes

I didn't have the 5 iterations constraint for myself when I started debugging the issue (was just finding a good debugging demo). So I was less stressful when doing it and that might have helped.

With that being said, I did force myself to finish it in a single session when I was in the 5th iteration. And it let me started using commands that I wasn't used to, like edit and list -. This experience inspired me to create the debugging challenge to see how constraints affect people's debugging behavior.

(I used ruby/debug in all 5 iterations)

1st

From the test cases, I knew there are expected and unexpected exceptions. So I decided to trace exceptions and try to catch the InvalidSignature ones with catch breakpoints. But I started the tracer too early so it caused a lot of noise.

# I ran it with `rdbg -c -e "trace exception ;; c" ruby test.rb` to trace exceptions
# but because that activated tracers from the program start, it logged bundlers' exceptions as well
# and it caused a lot of noise so let's skip them here

DEBUGGER (trace/exception) #th:1 #depth:11 #<NameError: method `gem' not defined in #<Class:Kernel>

          klass.send(:remove_method, method)
               ^^^^^> at ~/.gem/ruby/3.1.2/gems/bundler-2.3.7/lib/bundler/rubygems_integration.rb:415
DEBUGGER (trace/exception) #th:1 #depth:10 #<LoadError: cannot load such file -- activesupport> at ~/.gem/ruby/3.1.2/gems/bundler-2.3.7/lib/bundler/runtime.rb:60
DEBUGGER (trace/exception) #th:1 #depth:20 #<LoadError: cannot load such file -- concurrent/concurrent_ruby_ext> at ~/.gem/ruby/3.1.2/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb:62
DEBUGGER (trace/exception) #th:1 #depth:20 #<LoadError: cannot load such file -- concurrent/3.1/concurrent_ruby_ext> at ~/.gem/ruby/3.1.2/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb:62
Run options: --seed 29357

# Running:

[12, 21] in test.rb
    12| require "active_support/core_ext/object/blank"
    13| require "minitest/autorun"
    14|
    15| class BugTest < Minitest::Test
    16|   def test_stuff
=>  17|     debugger(do: "catch ActiveSupport::MessageVerifier::InvalidSignature")
    18|     old_secret = SecureRandom.base64(24)
    19|     old_encryptor = ActiveSupport::MessageEncryptor.new old_secret
    20|
    21|     current_secret = SecureRandom.base64(24)
=>#0    BugTest#test_stuff at test.rb:17
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) catch ActiveSupport::MessageVerifier::InvalidSignature
#0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'bZvGSU2UIMNUyG4LdgSSgg==--jObHmViZ8VEUfpR0r7w/aA=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'yHs2FzELtW7j5Hxd99JwA==--GlYfWlGUegUwEJmvd9uppQ=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk3..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 25 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg) bt     # backtrace command
=>#0    ActiveSupport::MessageVerifier#verify(args=["NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk3..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  #2    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22
  #3    block in test_stuff at test.rb:33
  #4    Minitest::Assertions#assert_raises(exp=[ActiveSupport::MessageVerifier::InvalidS...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/assertions.rb:404
  #5    BugTest#test_stuff at test.rb:32
  #6    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #7    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #8    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #9    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  #10   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:94
  #11   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000010ea87708 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #12   Minitest::Test#with_info_handler(block=#<Proc:0x000000010ea87898 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:243
  #13   Minitest::Test#run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:93
  #14   Minitest.run_one_method(klass=BugTest, method_name="test_stuff") at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:1059
  #15   #<Class:Minitest::Runnable>#run_one_method(klass=BugTest, method_name="test_stuff", reporter=#<Minitest::CompositeReporter:0x000000010...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:365
  #16   block {|method_name="test_stuff"|} in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:352
  #17   [C] Array#each at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #18   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #19   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000010ea8e558 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #20   #<Class:Minitest::Runnable>#with_info_handler(reporter=#<Minitest::CompositeReporter:0x000000010..., block=#<Proc:0x000000010ea8e9b8 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:378
  #21   #<Class:Minitest::Runnable>#run(reporter=#<Minitest::CompositeReporter:0x000000010..., options={:io=>#<IO:<STDOUT>>, :seed=>29357, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:350
  #22   block {|suite=BugTest|} in __run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #23   [C] Array#map at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #24   Minitest.__run(reporter=#<Minitest::CompositeReporter:0x000000010..., options={:io=>#<IO:<STDOUT>>, :seed=>29357, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #25   Minitest.run(args=[]) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:159
  #26   block in autorun at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:83
(rdbg) c    # continue command
DEBUGGER (trace/exception) #th:1 #depth:27 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
[19, 28] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  # and 24 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg) info    # command
%self = #<ActiveSupport::MessageEncryptor:0x000000010ff3d1c0 @secret="VZejHjM6orIf/7U+OfVreWg2QKXb77in", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x000000010ff3ccc0 @secret="VZejHjM6orI...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["NzY0RXZibnJaREFIL0o3WWcwYnY3UT09LS1rSkk3N1pydDJXVEhwQW0ralNEN1RBPT0=--735e3667437b456fe5f2c317d896c53d0793042e"]
on_rotation = nil
options = {}
@aead_mode = false
@cipher = "aes-256-cbc"
@digest = "SHA1"
@on_rotation = nil
@options = {}
@rotations = []
@secret = "VZejHjM6orIf/7U+OfVreWg2QKXb77in"
@serializer = Marshal
@sign_secret = nil
@verifier = #<ActiveSupport::MessageVerifier:0x000000010ff3ccc0 @secret="VZejHjM6orIf/7U+OfVreWg2QKXb77in", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::Null...>
(rdbg) q!    # quit! command
E

Finished in 272.491107s, 0.0037 runs/s, 0.0147 assertions/s.

  1) Error:
BugTest#test_stuff:
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178:in `verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160:in `decrypt_and_verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22:in `decrypt_and_verify'
    test.rb:40:in `test_stuff'

1 runs, 4 assertions, 0 failures, 1 errors, 0 skips

2nd

I placed the tracer correctly this time and poked around from both the library and the test case.

$ rdbg -c -n ruby test.rb
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Using bundler 2.3.7
Using concurrent-ruby 1.1.10
Using minitest 5.16.2
Using i18n 1.12.0
Using tzinfo 2.0.5
Using activesupport 7.0.3
Run options: --seed 64542

# Running:

[12, 21] in test.rb
    12| require "active_support/core_ext/object/blank"
    13| require "minitest/autorun"
    14|
    15| class BugTest < Minitest::Test
    16|   def test_stuff
=>  17|     debugger(do: "trace exception ;; catch ActiveSupport::MessageVerifier::InvalidSignature")
    18|     old_secret = SecureRandom.base64(24)
    19|     old_encryptor = ActiveSupport::MessageEncryptor.new old_secret
    20|
    21|     current_secret = SecureRandom.base64(24)
=>#0    BugTest#test_stuff at test.rb:17
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) trace exception
Enable ExceptionTracer (enabled)
(rdbg:binding.break) catch ActiveSupport::MessageVerifier::InvalidSignature
#0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
[20, 29] in test.rb
    20|
    21|     current_secret = SecureRandom.base64(24)
    22|     current_encryptor = ActiveSupport::MessageEncryptor.new current_secret
    23|     current_encryptor.rotate old_secret
    24|
=>  25|     debugger(do: "info")
    26|
    27|     # Old encryptor roundtrips a 'nil' value correctly
    28|     assert_nil old_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
    29|
=>#0    BugTest#test_stuff at test.rb:25
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) info
%self = #<BugTest:0x0000000112266070 @NAME="test_stuff", @assertions=0, @failures=[]>
old_secret = "6DCt7FGdeDdMHlCrODVos69R4tgbvIR2"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000112f7cfe8 @secret="6DCt7FGdeDdMHlCrODVos69R4tgbvIR2", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000112f7c980 @secret="6DC...>
current_secret = "nn9lFwhrbSoVl2QlnLw5DyMDcZpr9phf"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000112f7c408 @secret="nn9lFwhrbSoVl2QlnLw5DyMDcZpr9phf", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000112f7c188 @secret=...>
@NAME = "test_stuff"
@assertions = 0
@failures = []
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'soGcijjcBXB1HrYr/lHlWg==--Gc6CL0oa0V+8mzUH4vy6KA=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'QeLf4JXO2rktfl0iNEt5w==--3D8bhxQltf+SeVYIdRpfmA=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["MGx5RHJyRU9TclpLd0xITUkrVVVHdz09LS02VjZ..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="MGx5RHJyRU9TclpLd0xITUkrVVVHdz09LS02VjZk..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 25 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg) q!    # quit! command
E

Finished in 11.838025s, 0.0845 runs/s, 0.3379 assertions/s.

  1) Error:
BugTest#test_stuff:
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178:in `verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160:in `decrypt_and_verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22:in `decrypt_and_verify'
    test.rb:42:in `test_stuff'

1 runs, 4 assertions, 0 failures, 1 errors, 0 skips

3rd

I tried to use something fancy like catch ActiveSupport::MessageVerifier::InvalidSignature do: "info" and expected it to print frame info (variables) whenever a exception was raised. But I made a syntax mistake so it only printed "info" instead of calling the info command 🤦‍♂️ Basically wasted it.

$ rdbg -c -n ruby test.rb
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Using bundler 2.3.7
Using concurrent-ruby 1.1.10
Using minitest 5.16.2
Using i18n 1.12.0
Using tzinfo 2.0.5
Using activesupport 7.0.3
Run options: --seed 30132

# Running:

[12, 21] in test.rb
    12| require "active_support/core_ext/object/blank"
    13| require "minitest/autorun"
    14|
    15| class BugTest < Minitest::Test
    16|   def test_stuff
=>  17|     debugger(do: "trace exception ;; catch ActiveSupport::MessageVerifier::InvalidSignature do: 'info'")
    18|     old_secret = SecureRandom.base64(24)
    19|     old_encryptor = ActiveSupport::MessageEncryptor.new old_secret
    20|
    21|     current_secret = SecureRandom.base64(24)
=>#0    BugTest#test_stuff at test.rb:17
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) trace exception
Enable ExceptionTracer (enabled)
(rdbg:binding.break) catch ActiveSupport::MessageVerifier::InvalidSignature do: 'info'
#0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
[20, 29] in test.rb
    20|
    21|     current_secret = SecureRandom.base64(24)
    22|     current_encryptor = ActiveSupport::MessageEncryptor.new current_secret
    23|     current_encryptor.rotate old_secret
    24|
=>  25|     debugger(do: "info")
    26|
    27|     # Old encryptor roundtrips a 'nil' value correctly
    28|     assert_nil old_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
    29|
=>#0    BugTest#test_stuff at test.rb:25
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) info
%self = #<BugTest:0x000000011871d6a8 @NAME="test_stuff", @assertions=0, @failures=[]>
old_secret = "e6KxH42DKJyQbcb4Q/X2QcCzQyjjsAeW"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000119386d68 @secret="e6KxH42DKJyQbcb4Q/X2QcCzQyjjsAeW", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x00000001193867a0 @secret="e6K...>
current_secret = "BPD80Kq/RvEDBc/LKlPcLkncZnGHxGLQ"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x00000001193862f0 @secret="BPD80Kq/RvEDBc/LKlPcLkncZnGHxGLQ", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000119386098 @secret=...>
@NAME = "test_stuff"
@assertions = 0
@failures = []
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 't0RxJFWqsMe15FxRz48FYg==--ohmjSZMsdEq6tqGZUMBHqA=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'Xxaz04nV3duyaj5sfb4sVQ==--YJPiUsVzPPI9Aqamfa8OpQ=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["V3lOZG1wUUJOVndvNjR5enVDU0U2Zz09LS0zY2Z..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="V3lOZG1wUUJOVndvNjR5enVDU0U2Zz09LS0zY2ZB..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 25 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
DEBUGGER (trace/exception) #th:1 #depth:27 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
[19, 28] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["V3lOZG1wUUJOVndvNjR5enVDU0U2Zz09LS0zY2Z..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  # and 24 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
DEBUGGER (trace/exception) #th:1 #depth:26 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["b3NEMkxuMnN5d1YvYXJ0NlRNcGxMQT09LS0rZFZ..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="b3NEMkxuMnN5d1YvYXJ0NlRNcGxMQT09LS0rZFZl..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 23 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
DEBUGGER (trace/exception) #th:1 #depth:25 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
DEBUGGER (trace/exception) #th:1 #depth:39 #<JSON::ParserError: 859: unexpected token at 'osD2Ln2sywV/art6TMplLA==--+dVeL3a8mJchsI/2KfzmYg=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:37 #<JSON::ParserError: 859: unexpected token at I"     test:ET'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["cW1CUXJiQmhoRkFJUVpibU5rOU5yZz09LS1zMmF..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="cW1CUXJiQmhoRkFJUVpibU5rOU5yZz09LS1zMmFM..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 23 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
DEBUGGER (trace/exception) #th:1 #depth:25 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
DEBUGGER (trace/exception) #th:1 #depth:39 #<JSON::ParserError: 859: unexpected token at 'qmBQrbBhhFAIQZbmNk9Nrg==--s2aLbEuVmjp8byWFx1irtg=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:37 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[19, 28] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["cW1CUXJiQmhoRkFJUVpibU5rOU5yZz09LS1zMmF..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  # and 22 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
DEBUGGER (trace/exception) #th:1 #depth:24 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
E

Finished in 0.128255s, 7.7970 runs/s, 31.1879 assertions/s.

  1) Error:
BugTest#test_stuff:
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178:in `verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160:in `decrypt_and_verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22:in `decrypt_and_verify'
    test.rb:42:in `test_stuff'

1 runs, 4 assertions, 0 failures, 1 errors, 0 skips
DEBUGGER (trace/exception) #th:1 #depth:2  #<SystemExit: exit> at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:80

4th

Not sure what I was doing here.

$ rdbg -c -n ruby test.rb
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Using minitest 5.16.2
Using concurrent-ruby 1.1.10
Using bundler 2.3.7
Using tzinfo 2.0.5
Using i18n 1.12.0
Using activesupport 7.0.3
Run options: --seed 63351

# Running:

[12, 21] in test.rb
    12| require "active_support/core_ext/object/blank"
    13| require "minitest/autorun"
    14|
    15| class BugTest < Minitest::Test
    16|   def test_stuff
=>  17|     debugger(do: "trace exception ;; catch ActiveSupport::MessageVerifier::InvalidSignature pre: 'info'")
    18|     old_secret = SecureRandom.base64(24)
    19|     old_encryptor = ActiveSupport::MessageEncryptor.new old_secret
    20|
    21|     current_secret = SecureRandom.base64(24)
=>#0    BugTest#test_stuff at test.rb:17
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) trace exception
Enable ExceptionTracer (enabled)
(rdbg:binding.break) catch ActiveSupport::MessageVerifier::InvalidSignature pre: 'info'
#0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
[20, 29] in test.rb
    20|
    21|     current_secret = SecureRandom.base64(24)
    22|     current_encryptor = ActiveSupport::MessageEncryptor.new current_secret
    23|     current_encryptor.rotate old_secret
    24|
=>  25|     debugger(do: "info")
    26|
    27|     # Old encryptor roundtrips a 'nil' value correctly
    28|     assert_nil old_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
    29|
=>#0    BugTest#test_stuff at test.rb:25
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) info
%self = #<BugTest:0x000000010b60eb48 @NAME="test_stuff", @assertions=0, @failures=[]>
old_secret = "XoX8wqb/f/nlfOu5L4SDaHL6LX5Gx/wK"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x000000010c18dca8 @secret="XoX8wqb/f/nlfOu5L4SDaHL6LX5Gx/wK", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x000000010c18d140 @secret="XoX...>
current_secret = "yupETd36cNKzrzVswzpQ4xDlJwgzVnS2"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x000000010c18c358 @secret="yupETd36cNKzrzVswzpQ4xDlJwgzVnS2", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x000000010c18c060 @secret=...>
@NAME = "test_stuff"
@assertions = 0
@failures = []
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'oeoYX1rTLjjS++8AKsKuUw==--vs2dWX5MouabmQbM4Rj4Lw=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'TPgGb+L2BOcsK5lxS0G+NQ==--eCl6WejwM04gvLQ8/suoQA=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["T3YvUU5nYTlvemVxZzBlTFR0Z0lZdz09LS1mUEF..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="T3YvUU5nYTlvemVxZzBlTFR0Z0lZdz09LS1mUEFs..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 25 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) 'info'
"info"
(rdbg) q!    # quit! command
E

Finished in 13.817523s, 0.0724 runs/s, 0.2895 assertions/s.

  1) Error:
BugTest#test_stuff:
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178:in `verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160:in `decrypt_and_verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22:in `decrypt_and_verify'
    test.rb:42:in `test_stuff'

1 runs, 4 assertions, 0 failures, 1 errors, 0 skips

5th

I decided to locate the cause in this iteration no matter what happens. So I treid a lot of stuff here:

  • step and next to slowly advance (cause no going backward)
  • up and down to move between frames
  • info and ls to collect information
  • list to print source code (which advances everytime is called, so I also used list - to move back)
  • edit to open ActiveSupport in editor
$ rdbg -c -n ruby test.rb
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Using concurrent-ruby 1.1.10
Using bundler 2.3.7
Using minitest 5.16.2
Using i18n 1.12.0
Using tzinfo 2.0.5
Using activesupport 7.0.3
Run options: --seed 37767

# Running:

[12, 21] in test.rb
    12| require "active_support/core_ext/object/blank"
    13| require "minitest/autorun"
    14|
    15| class BugTest < Minitest::Test
    16|   def test_stuff
=>  17|     debugger(do: "trace exception ;; catch ActiveSupport::MessageVerifier::InvalidSignature pre: info")
    18|     old_secret = SecureRandom.base64(24)
    19|     old_encryptor = ActiveSupport::MessageEncryptor.new old_secret
    20|
    21|     current_secret = SecureRandom.base64(24)
=>#0    BugTest#test_stuff at test.rb:17
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) trace exception
Enable ExceptionTracer (enabled)
(rdbg:binding.break) catch ActiveSupport::MessageVerifier::InvalidSignature pre: info
#0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
[20, 29] in test.rb
    20|
    21|     current_secret = SecureRandom.base64(24)
    22|     current_encryptor = ActiveSupport::MessageEncryptor.new current_secret
    23|     current_encryptor.rotate old_secret
    24|
=>  25|     debugger(do: "info")
    26|
    27|     # Old encryptor roundtrips a 'nil' value correctly
    28|     assert_nil old_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
    29|
=>#0    BugTest#test_stuff at test.rb:25
  #1    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  # and 20 frames (use `bt' command for all frames)
(rdbg:binding.break) info
%self = #<BugTest:0x000000011105d7e8 @NAME="test_stuff", @assertions=0, @failures=[]>
old_secret = "RNQ2YepodsSZzyk7cmXLjATDycy1K9WA"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d77078 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ...>
current_secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret=...>
@NAME = "test_stuff"
@assertions = 0
@failures = []
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'bVs6qzIakT3D+wJmwtPEbg==--hk2jIJ2jaF6QLuY7sKgolg=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:32 #<JSON::ParserError: 859: unexpected token at 'oF+BZ1q6Y4jezWH6uwzd9Q==--E4IuCqU3UaRlsyM73xEbHw=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:30 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM2..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 25 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) info
%self = #<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSeri...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM2UlNFNW9XYlRqS0pMV0F5ekJBPT0=--c994dbb5b1bc397e7b3c8ba68636633b652864a8"]
options = {}
@digest = "SHA1"
@digest_length_in_hex = 40
@on_rotation = nil
@options = {:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}
@rotations = []
@secret = "RNQ2YepodsSZzyk7cmXLjATDycy1K9WA"
@serializer = ActiveSupport::MessageEncryptor::NullSerializer
(rdbg) bt 10    # backtrace command
=>#0    ActiveSupport::MessageVerifier#verify(args=["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM2..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  #2    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22
  #3    block in test_stuff at test.rb:35
  #4    Minitest::Assertions#assert_raises(exp=[ActiveSupport::MessageVerifier::InvalidS...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/assertions.rb:404
  #5    BugTest#test_stuff at test.rb:34
  #6    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #7    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #8    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #9    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  # and 17 frames (use `bt' command for all frames)
(rdbg) f 3    # frame command
=>  35|       old_encryptor.decrypt_and_verify(current_encryptor.encrypt_and_sign("test"))
=>#3    block in test_stuff at test.rb:35
(rdbg) info    # command
%self = #<BugTest:0x000000011105d7e8 @NAME="test_stuff", @assertions=2, @failures=[]>
old_secret = "RNQ2YepodsSZzyk7cmXLjATDycy1K9WA"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d77078 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ...>
current_secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret=...>
@NAME = "test_stuff"
@assertions = 2
@failures = []
(rdbg) c    # continue command
DEBUGGER (trace/exception) #th:1 #depth:27 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
[19, 28] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  # and 24 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) info
%self = #<ActiveSupport::MessageEncryptor:0x0000000111d77078 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ2YepodsS...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM2UlNFNW9XYlRqS0pMV0F5ekJBPT0=--c994dbb5b1bc397e7b3c8ba68636633b652864a8"]
on_rotation = nil
options = {}
@aead_mode = false
@cipher = "aes-256-cbc"
@digest = "SHA1"
@on_rotation = nil
@options = {}
@rotations = []
@secret = "RNQ2YepodsSZzyk7cmXLjATDycy1K9WA"
@serializer = Marshal
@sign_secret = nil
@verifier = #<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::Null...>
(rdbg) bt    # backtrace command
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["RjArNFZBR1VEOGYyQzkwY0ZyRTBTQT09LS1ncVM..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  #2    block in test_stuff at test.rb:35
  #3    Minitest::Assertions#assert_raises(exp=[ActiveSupport::MessageVerifier::InvalidS...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/assertions.rb:404
  #4    BugTest#test_stuff at test.rb:34
  #5    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #6    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #7    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #8    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  #9    block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:94
  #10   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105cb90 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #11   Minitest::Test#with_info_handler(block=#<Proc:0x000000011105ccd0 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:243
  #12   Minitest::Test#run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:93
  #13   Minitest.run_one_method(klass=BugTest, method_name="test_stuff") at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:1059
  #14   #<Class:Minitest::Runnable>#run_one_method(klass=BugTest, method_name="test_stuff", reporter=#<Minitest::CompositeReporter:0x000000011...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:365
  #15   block {|method_name="test_stuff"|} in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:352
  #16   [C] Array#each at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #17   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #18   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105f048 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #19   #<Class:Minitest::Runnable>#with_info_handler(reporter=#<Minitest::CompositeReporter:0x000000011..., block=#<Proc:0x000000011105f110 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:378
  #20   #<Class:Minitest::Runnable>#run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:350
  #21   block {|suite=BugTest|} in __run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #22   [C] Array#map at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #23   Minitest.__run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #24   Minitest.run(args=[]) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:159
  #25   block in autorun at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:83
(rdbg) c    # continue command
DEBUGGER (trace/exception) #th:1 #depth:26 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMER..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMERk..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 23 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) info
%self = #<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSeri...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMERkMXQ1cjNiNXBXYXV3UWxndnRRPT0=--3c3f86ea0891694b27c9e70bc7401dc40dbeaad2"]
options = {}
@digest = "SHA1"
@digest_length_in_hex = 40
@on_rotation = nil
@options = {:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}
@rotations = []
@secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
@serializer = ActiveSupport::MessageEncryptor::NullSerializer
(rdbg) bt     # backtrace command
=>#0    ActiveSupport::MessageVerifier#verify(args=["UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMER..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMERk..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  #2    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["UzZwMFNoTlVyZldxaGIzMkEvbi90dz09LS1yMER..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22
  #3    BugTest#test_stuff at test.rb:39
  #4    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #5    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #6    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #7    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  #8    block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:94
  #9    #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105cb90 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #10   Minitest::Test#with_info_handler(block=#<Proc:0x000000011105ccd0 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:243
  #11   Minitest::Test#run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:93
  #12   Minitest.run_one_method(klass=BugTest, method_name="test_stuff") at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:1059
  #13   #<Class:Minitest::Runnable>#run_one_method(klass=BugTest, method_name="test_stuff", reporter=#<Minitest::CompositeReporter:0x000000011...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:365
  #14   block {|method_name="test_stuff"|} in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:352
  #15   [C] Array#each at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #16   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #17   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105f048 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #18   #<Class:Minitest::Runnable>#with_info_handler(reporter=#<Minitest::CompositeReporter:0x000000011..., block=#<Proc:0x000000011105f110 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:378
  #19   #<Class:Minitest::Runnable>#run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:350
  #20   block {|suite=BugTest|} in __run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #21   [C] Array#map at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #22   Minitest.__run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #23   Minitest.run(args=[]) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:159
  #24   block in autorun at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:83
(rdbg) c    # continue command
DEBUGGER (trace/exception) #th:1 #depth:25 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
DEBUGGER (trace/exception) #th:1 #depth:39 #<JSON::ParserError: 859: unexpected token at 'S6p0ShNUrfWqhb32A/n/tw==--r0Dd1t5r3b5pWauwQlgvtQ=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:37 #<JSON::ParserError: 859: unexpected token at I"     test:ET'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[173, 182] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb
   173|     # secret or was not Base64-encoded.
   174|     #
   175|     #   other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
   176|     #   other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
   177|     def verify(*args, **options)
=> 178|       verified(*args, **options) || raise(InvalidSignature)
   179|     end
   180|
   181|     # Generates a signed message for the provided value.
   182|     #
=>#0    ActiveSupport::MessageVerifier#verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  # and 23 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) info
%self = #<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSeri...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3TitNamFxZ0ZESC95T0pFVWlnPT0=--71a16fa82902807fec3bdaff90b6b1b5e82dd981"]
options = {}
@digest = "SHA1"
@digest_length_in_hex = 40
@on_rotation = nil
@options = {:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}
@rotations = []
@secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
@serializer = ActiveSupport::MessageEncryptor::NullSerializer
(rdbg) bt    # backtrace command
=>#0    ActiveSupport::MessageVerifier#verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
  #1    ActiveSupport::MessageEncryptor#decrypt_and_verify(data="cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3..., purpose=nil) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160
  #2    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22
  #3    BugTest#test_stuff at test.rb:42
  #4    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #5    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #6    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #7    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  #8    block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:94
  #9    #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105cb90 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #10   Minitest::Test#with_info_handler(block=#<Proc:0x000000011105ccd0 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:243
  #11   Minitest::Test#run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:93
  #12   Minitest.run_one_method(klass=BugTest, method_name="test_stuff") at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:1059
  #13   #<Class:Minitest::Runnable>#run_one_method(klass=BugTest, method_name="test_stuff", reporter=#<Minitest::CompositeReporter:0x000000011...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:365
  #14   block {|method_name="test_stuff"|} in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:352
  #15   [C] Array#each at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #16   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #17   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105f048 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #18   #<Class:Minitest::Runnable>#with_info_handler(reporter=#<Minitest::CompositeReporter:0x000000011..., block=#<Proc:0x000000011105f110 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:378
  #19   #<Class:Minitest::Runnable>#run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:350
  #20   block {|suite=BugTest|} in __run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #21   [C] Array#map at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #22   Minitest.__run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #23   Minitest.run(args=[]) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:159
  #24   block in autorun at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:83
(rdbg) f 3    # frame command
=>  42|     assert_nil current_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
=>#3    BugTest#test_stuff at test.rb:42
(rdbg) info    # command
%self = #<BugTest:0x000000011105d7e8 @NAME="test_stuff", @assertions=4, @failures=[]>
old_secret = "RNQ2YepodsSZzyk7cmXLjATDycy1K9WA"
old_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d77078 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d76ad8 @secret="RNQ...>
current_secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
current_encryptor = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret=...>
@NAME = "test_stuff"
@assertions = 4
@failures = []
(rdbg) up    # command
=>  98|             self.send self.name
=>#4    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
(rdbg) down    # command
=>  42|     assert_nil current_encryptor.decrypt_and_verify(old_encryptor.encrypt_and_sign(nil))
=>#3    BugTest#test_stuff at test.rb:42
(rdbg) down    # command
=>  22|           super
=>#2    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22
(rdbg) info    # command
%self = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPen...>
args = ["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3TitNamFxZ0ZESC95T0pFVWlnPT0=--71a16fa82902807fec3bdaff90b6b1b5e82dd981"]
on_rotation = nil
options = {}
@aead_mode = false
@cipher = "aes-256-cbc"
@digest = "SHA1"
@on_rotation = nil
@options = {}
@rotations = [#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d75c78 @secret="RNQ2Ye...
@secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
@serializer = Marshal
@sign_secret = nil
@verifier = #<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::Null...>
(rdbg) c    # continue command
DEBUGGER (trace/exception) #th:1 #depth:25 #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature> at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178
DEBUGGER (trace/exception) #th:1 #depth:39 #<JSON::ParserError: 859: unexpected token at 'p8Jbb63jLhTmPGGPoV/thQ==--MgA7N+MjaqgFDH/yOJEUig=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:37 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
[19, 28] in ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  # and 22 frames (use `bt' command for all frames)

Stop by #0  BP - Catch  "ActiveSupport::MessageVerifier::InvalidSignature"
(rdbg:catch) info
%self = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPen...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3TitNamFxZ0ZESC95T0pFVWlnPT0=--71a16fa82902807fec3bdaff90b6b1b5e82dd981"]
on_rotation = nil
options = {}
@aead_mode = false
@cipher = "aes-256-cbc"
@digest = "SHA1"
@on_rotation = nil
@options = {}
@rotations = [#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d75c78 @secret="RNQ2Ye...
@secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
@serializer = Marshal
@sign_secret = nil
@verifier = #<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::Null...>
(rdbg) info    # command
%self = #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPen...>
_raised = #<ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature>
args = ["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E3TitNamFxZ0ZESC95T0pFVWlnPT0=--71a16fa82902807fec3bdaff90b6b1b5e82dd981"]
on_rotation = nil
options = {}
@aead_mode = false
@cipher = "aes-256-cbc"
@digest = "SHA1"
@on_rotation = nil
@options = {}
@rotations = [#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d75c78 @secret="RNQ2Ye...
@secret = "MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE"
@serializer = Marshal
@sign_secret = nil
@verifier = #<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::Null...>
(rdbg) ls self    # outline command
ActiveSupport::MessageEncryptor#methods: encrypt_and_sign
ActiveSupport::Messages::Rotator#methods: rotate
ActiveSupport::Messages::Rotator::Encryptor#methods: decrypt_and_verify
instance variables: @aead_mode  @cipher  @digest  @on_rotation  @options  @rotations  @secret  @serializer  @sign_secret  @verifier
class variables: @@use_authenticated_message_encryption
locals: args  on_rotation  options
(ruby) @rotations
[#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8
  @aead_mode=false,
  @cipher="aes-256-cbc",
  @digest="SHA1",
  @on_rotation=nil,
  @options={},
  @rotations=[],
  @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
  @serializer=Marshal,
  @sign_secret=nil,
  @verifier=
   #<ActiveSupport::MessageVerifier:0x0000000111d75c78
    @digest="SHA1",
    @digest_length_in_hex=40,
    @on_rotation=nil,
    @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer},
    @rotations=[],
    @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
    @serializer=ActiveSupport::MessageEncryptor::NullSerializer>>]
(rdbg) list     # command
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
(rdbg) edit .    # command
command: nvim
   path: /Users/hung-wulo/src/github.com/ruby/debug
(rdbg) edit     # command
command: nvim
   path: /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
(ruby) @rotations
[#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8
  @aead_mode=false,
  @cipher="aes-256-cbc",
  @digest="SHA1",
  @on_rotation=nil,
  @options={},
  @rotations=[],
  @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
  @serializer=Marshal,
  @sign_secret=nil,
  @verifier=
   #<ActiveSupport::MessageVerifier:0x0000000111d75c78
    @digest="SHA1",
    @digest_length_in_hex=40,
    @on_rotation=nil,
    @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer},
    @rotations=[],
    @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
    @serializer=ActiveSupport::MessageEncryptor::NullSerializer>>]
(rdbg) edit     # command
command: nvim
   path: /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb
(rdbg) bt    # backtrace command
=>#0    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:24
  #1    ActiveSupport::Messages::Rotator::Encryptor#decrypt_and_verify(args=["cDhKYmI2M2pMaFRtUEdHUG9WL3RoUT09LS1NZ0E..., on_rotation=nil, options={}) at ~/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:21
  #2    BugTest#test_stuff at test.rb:42
  #3    block in run (3 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:98
  #4    Minitest::Test#capture_exceptions at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:195
  #5    block in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:95
  #6    Minitest::Runnable#time_it at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:296
  #7    block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:94
  #8    #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105cb90 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #9    Minitest::Test#with_info_handler(block=#<Proc:0x000000011105ccd0 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:243
  #10   Minitest::Test#run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest/test.rb:93
  #11   Minitest.run_one_method(klass=BugTest, method_name="test_stuff") at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:1059
  #12   #<Class:Minitest::Runnable>#run_one_method(klass=BugTest, method_name="test_stuff", reporter=#<Minitest::CompositeReporter:0x000000011...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:365
  #13   block {|method_name="test_stuff"|} in run (2 levels) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:352
  #14   [C] Array#each at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #15   block in run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:351
  #16   #<Class:Minitest::Runnable>#on_signal(name="INFO", action=#<Proc:0x000000011105f048 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:391
  #17   #<Class:Minitest::Runnable>#with_info_handler(reporter=#<Minitest::CompositeReporter:0x000000011..., block=#<Proc:0x000000011105f110 /Users/hung-wul...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:378
  #18   #<Class:Minitest::Runnable>#run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:350
  #19   block {|suite=BugTest|} in __run at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #20   [C] Array#map at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #21   Minitest.__run(reporter=#<Minitest::CompositeReporter:0x000000011..., options={:io=>#<IO:<STDOUT>>, :seed=>37767, :args...) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:182
  #22   Minitest.run(args=[]) at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:159
  #23   block in autorun at ~/.gem/ruby/3.1.2/gems/minitest-5.16.2/lib/minitest.rb:83
(rdbg) list    # command
    29|             self.class.new(secret, sign_secret, **options)
    30|           end
    31|       end
    32|
    33|       module Verifier
    34|         include Rotator
    35|
    36|         def verified(*args, on_rotation: @on_rotation, **options)
    37|           super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
    38|         end
(rdbg) list -    # command
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
(rdbg) encryptor
DEBUGGER (trace/exception) #th:1 #depth:38 #<NameError: undefined local variable or method `encryptor' for #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}, @rotations=[], @on_rotation=nil, @digest_length_in_hex=40>, @serializer=Marshal, @options={}, @rotations=[#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d75c78 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}, @rotations=[], @on_rotation=nil, @digest_length_in_hex=40>, @serializer=Marshal, @options={}, @rotations=[], @on_rotation=nil>], @on_rotation=nil>

encryptor
^^^^^^^^^
Did you mean?  _encrypt> at (rdbg)//Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:1
eval error: undefined local variable or method `encryptor' for #<ActiveSupport::MessageEncryptor:0x0000000111d76650 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d763f8 @secret="MUDdXNHTPend6oOxaNyXqZQQHOwxb4JE", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}, @rotations=[], @on_rotation=nil, @digest_length_in_hex=40>, @serializer=Marshal, @options={}, @rotations=[#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x0000000111d75c78 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer, @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer}, @rotations=[], @on_rotation=nil, @digest_length_in_hex=40>, @serializer=Marshal, @options={}, @rotations=[], @on_rotation=nil>], @on_rotation=nil>

encryptor
^^^^^^^^^
Did you mean?  _encrypt
  (rdbg)//Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:1:in `rescue in decrypt_and_verify'
nil
(rdbg) list 15    # command
    15|         @rotations << build_rotation(*secrets, @options.merge(options))
    16|       end
    17|
    18|       module Encryptor
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
(rdbg) list 50    # command
    50|               on_rotation&.call
    51|               return message
    52|             end
    53|           end
    54|         end
    55|     end
    56|   end
    57| end
(rdbg) list 45    # command
    45|
    46|       private
    47|         def run_rotations(on_rotation)
    48|           @rotations.find do |rotation|
    49|             if message = yield(rotation) rescue next
    50|               on_rotation&.call
    51|               return message
    52|             end
    53|           end
    54|         end
(ruby) @rotations.first
#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8
 @aead_mode=false,
 @cipher="aes-256-cbc",
 @digest="SHA1",
 @on_rotation=nil,
 @options={},
 @rotations=[],
 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
 @serializer=Marshal,
 @sign_secret=nil,
 @verifier=
  #<ActiveSupport::MessageVerifier:0x0000000111d75c78
   @digest="SHA1",
   @digest_length_in_hex=40,
   @on_rotation=nil,
   @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer},
   @rotations=[],
   @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
   @serializer=ActiveSupport::MessageEncryptor::NullSerializer>>
(ruby) @rotations.first.decrypt_and_verify(*args)
DEBUGGER (trace/exception) #th:1 #depth:48 #<JSON::ParserError: 859: unexpected token at 'p8Jbb63jLhTmPGGPoV/thQ==--MgA7N+MjaqgFDH/yOJEUig=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:46 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
nil
(rdbg) list    # command
    55|     end
    56|   end
    57| end
(rdbg) list -    # command
    38|         end
    39|
    40|         private
    41|           def build_rotation(secret = @secret, options)
    42|             self.class.new(secret, **options)
    43|           end
    44|       end
    45|
    46|       private
    47|         def run_rotations(on_rotation)
(rdbg) list -    # command
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
    29|             self.class.new(secret, sign_secret, **options)
    30|           end
    31|       end
    32|
    33|       module Verifier
    34|         include Rotator
    35|
    36|         def verified(*args, on_rotation: @on_rotation, **options)
    37|           super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
(rdbg) list -    # command
    18|       module Encryptor
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
(rdbg) q!    # quit! command
E

Finished in 1400.692768s, 0.0007 runs/s, 0.0029 assertions/s.

  1) Error:
BugTest#test_stuff:
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_verifier.rb:178:in `verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/message_encryptor.rb:160:in `decrypt_and_verify'
    /Users/hung-wulo/.gem/ruby/3.1.2/gems/activesupport-7.0.3/lib/active_support/messages/rotator.rb:22:in `decrypt_and_verify'
    test.rb:42:in `test_stuff'

1 runs, 4 assertions, 0 failures, 1 errors, 0 skips

The Clicking Moment

# I checked how run_rotations looks like, and found that it goes through @rotations

(rdbg) list 45    # command
    45|
    46|       private
    47|         def run_rotations(on_rotation)
    48|           @rotations.find do |rotation|
    49|             if message = yield(rotation) rescue next
    50|               on_rotation&.call
    51|               return message
    52|             end
    53|           end
    54|         end
    
# I checked what are the @rotations, and they turned out to be MessageEncryptor objects

(ruby) @rotations.first
#<ActiveSupport::MessageEncryptor:0x0000000111d75ea8
 @aead_mode=false,
 @cipher="aes-256-cbc",
 @digest="SHA1",
 @on_rotation=nil,
 @options={},
 @rotations=[],
 @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
 @serializer=Marshal,
 @sign_secret=nil,
 @verifier=
  #<ActiveSupport::MessageVerifier:0x0000000111d75c78
   @digest="SHA1",
   @digest_length_in_hex=40,
   @on_rotation=nil,
   @options={:digest=>"SHA1", :serializer=>ActiveSupport::MessageEncryptor::NullSerializer},
   @rotations=[],
   @secret="RNQ2YepodsSZzyk7cmXLjATDycy1K9WA",
   @serializer=ActiveSupport::MessageEncryptor::NullSerializer>>

# I knew there's only one rotation in this case, so I checked if it'd decrypt the message

(ruby) @rotations.first.decrypt_and_verify(*args)

# tracer logs, not important

DEBUGGER (trace/exception) #th:1 #depth:48 #<JSON::ParserError: 859: unexpected token at 'p8Jbb63jLhTmPGGPoV/thQ==--MgA7N+MjaqgFDH/yOJEUig=='> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216
DEBUGGER (trace/exception) #th:1 #depth:46 #<JSON::ParserError: 859: unexpected token at 0'> at /opt/rubies/3.1.2/lib/ruby/3.1.0/json/common.rb:216

# and then it returned nil, which is the message (if it's not decryptable, it'd raise an error)

nil

# so then I went back to see why the nil value not properly returned
# I "scrolled back" the source code with `list -`
# now I hope https://github.com/ruby/debug/issues/639 could be implemented sooner

(rdbg) list    # command
    55|     end
    56|   end
    57| end
(rdbg) list -    # command
    38|         end
    39|
    40|         private
    41|           def build_rotation(secret = @secret, options)
    42|             self.class.new(secret, **options)
    43|           end
    44|       end
    45|
    46|       private
    47|         def run_rotations(on_rotation)
(rdbg) list -    # command
    28|           def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
    29|             self.class.new(secret, sign_secret, **options)
    30|           end
    31|       end
    32|
    33|       module Verifier
    34|         include Rotator
    35|
    36|         def verified(*args, on_rotation: @on_rotation, **options)
    37|           super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
 
# after I finally scrolled back, I saw the `||` condition and then it clicked

(rdbg) list -    # command
    18|       module Encryptor
    19|         include Rotator
    20|
    21|         def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
    22|           super
    23|         rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
=>  24|           run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
    25|         end
    26|
    27|         private
    
# so I finished the session

(rdbg) q!    # quit! command
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment